diff --git a/Makefile.work b/Makefile.work index 389f3f7c831f..f2e6c7bea5b6 100644 --- a/Makefile.work +++ b/Makefile.work @@ -227,18 +227,24 @@ init : @git submodule update --init --recursive @git submodule foreach --recursive '[ -f .git ] && echo "gitdir: $$(realpath --relative-to=. $$(cut -d" " -f2 .git))" > .git' +.ONESHELL : reset reset : @echo && echo -n "Warning! All local changes will be lost. Proceed? [y/N]: " - @read ans && \ - if [ $$ans == y ]; then \ - echo "Resetting local repository. Please wait..."; \ - $(DOCKER_RUN) $(SLAVE_IMAGE):$(SLAVE_TAG) sudo rm -rf fsroot; \ - git clean -xfdf; \ - git reset --hard; \ - git submodule foreach --recursive git clean -xfdf; \ - git submodule foreach --recursive git reset --hard; \ - git submodule update --init --recursive; \ - echo "Reset complete!"; \ - else \ - echo "Reset aborted"; \ - fi + @read ans && ( + if [ $$ans == y ]; then + echo "Resetting local repository. Please wait..."; + $(DOCKER_RUN) $(SLAVE_IMAGE):$(SLAVE_TAG) sudo rm -rf fsroot; + if [[ "$(CONFIGURED_ARCH)" == "armhf" || "$(CONFIGURED_ARCH)" == "arm64" ]]; then + echo "Stopping march $(CONFIGURED_ARCH) docker" + sudo kill -9 `sudo cat /var/run/march/docker.pid` || true + sudo rm -f /var/run/march/docker.pid || true + fi + git clean -xfdf; + git reset --hard; + git submodule foreach --recursive git clean -xfdf; + git submodule foreach --recursive git reset --hard; + git submodule update --init --recursive; + echo "Reset complete!"; + else + echo "Reset aborted"; + fi ) diff --git a/README.md b/README.md index 9c486e412063..afa26457fe4f 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,11 @@ Install pip and jinja in host build machine, execute below commands if j2/j2cli sudo pip install --force-reinstall --upgrade jinja2>=2.10 sudo pip install j2cli +Configure your system to allow running the 'docker' command without 'sudo': + Add current user to the docker group + `sudo gpasswd -a ${USER} docker` + Log out and log back in so that your group membership is re-evaluated + ## SAI Version Please refer to [SONiC roadmap](https://github.com/Azure/SONiC/wiki/Sonic-Roadmap-Planning) on the SAI version for each SONiC release. diff --git a/build_debian.sh b/build_debian.sh index 126a8ee329eb..4a734aea0995 100755 --- a/build_debian.sh +++ b/build_debian.sh @@ -31,7 +31,12 @@ set -x -e CONFIGURED_ARCH=$([ -f .arch ] && cat .arch || echo amd64) ## docker engine version (with platform) -DOCKER_VERSION=5:18.09.8~3-0~debian-stretch +if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then + # Version name differs between ARCH, copying same version as in sonic-slave docker + DOCKER_VERSION=18.06.3~ce~3-0~debian +else + DOCKER_VERSION=5:18.09.8~3-0~debian-stretch +fi LINUX_KERNEL_VERSION=4.9.0-9-2 ## Working directory to prepare the file system @@ -458,6 +463,14 @@ build_number: ${BUILD_NUMBER:-0} built_by: $USER@$BUILD_HOSTNAME EOF +## Copy ASIC config checksum +python files/build_scripts/generate_asic_config_checksum.py +if [[ ! -f './asic_config_checksum' ]]; then + echo 'asic_config_checksum not found' + exit 1 +fi +sudo cp ./asic_config_checksum $FILESYSTEM_ROOT/etc/sonic/asic_config_checksum + if [ -f sonic_debian_extension.sh ]; then ./sonic_debian_extension.sh $FILESYSTEM_ROOT $PLATFORM_DIR fi @@ -488,10 +501,7 @@ then sudo LANG=C chroot $FILESYSTEM_ROOT /bin/bash -c "echo '/debug is mounted in each docker' >> /etc/motd" sudo mkdir -p $FILESYSTEM_ROOT/src - pushd src - ../scripts/dbg_files.sh | sudo tar -cvzf ../$FILESYSTEM_ROOT/src/sonic_src.tar.gz -T - - popd - + sudo cp $DEBUG_SRC_ARCHIVE_FILE $FILESYSTEM_ROOT/src/ sudo mkdir -p $FILESYSTEM_ROOT/debug fi diff --git a/device/accton/x86_64-accton_as9716_32d-r0/Accton-AS9716-32D/port_config.ini b/device/accton/x86_64-accton_as9716_32d-r0/Accton-AS9716-32D/port_config.ini new file mode 100644 index 000000000000..a13514fcd909 --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/Accton-AS9716-32D/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed +Ethernet0 73,74,75,76,77,78,79,80 fourHundredGigE1 0 400000 +Ethernet4 65,66,67,68,69,70,71,72 fourHundredGigE2 1 400000 +Ethernet8 81,82,83,84,85,86,87,88 fourHundredGigE3 2 400000 +Ethernet12 89,90,91,92,93,94,95,96 fourHundredGigE4 3 400000 +Ethernet16 97,98,99,100,101,102,103,104 fourHundredGigE5 4 400000 +Ethernet20 105,106,107,108,109,110,111,112 fourHundredGigE6 5 400000 +Ethernet24 113,114,115,116,117,118,119,120 fourHundredGigE7 6 400000 +Ethernet28 121,122,123,124,125,126,127,128 fourHundredGigE8 7 400000 +Ethernet32 41,42,43,44,45,46,47,48 fourHundredGigE9 8 400000 +Ethernet36 33,34,35,36,37,38,39,40 fourHundredGigE10 9 400000 +Ethernet40 49,50,51,52,53,54,55,56 fourHundredGigE11 10 400000 +Ethernet44 57,58,59,60,61,62,63,64 fourHundredGigE12 11 400000 +Ethernet48 129,130,131,132,133,134,135,136 fourHundredGigE13 12 400000 +Ethernet52 137,138,139,140,141,142,143,144 fourHundredGigE14 13 400000 +Ethernet56 145,146,147,148,149,150,151,152 fourHundredGigE15 14 400000 +Ethernet60 153,154,155,156,157,158,159,160 fourHundredGigE16 15 400000 +Ethernet64 169,170,171,172,173,174,175,176 fourHundredGigE17 16 400000 +Ethernet68 161,162,163,164,165,166,167,168 fourHundredGigE18 17 400000 +Ethernet72 177,178,179,180,181,182,183,184 fourHundredGigE19 18 400000 +Ethernet76 185,186,187,188,189,190,191,192 fourHundredGigE20 19 400000 +Ethernet80 1,2,3,4,5,6,7,8 fourHundredGigE21 20 400000 +Ethernet84 9,10,11,12,13,14,15,16 fourHundredGigE22 21 400000 +Ethernet88 17,18,19,20,21,22,23,24 fourHundredGigE23 22 400000 +Ethernet92 25,26,27,28,29,30,31,32 fourHundredGigE24 23 400000 +Ethernet96 201,202,203,204,205,206,207,208 fourHundredGigE25 24 400000 +Ethernet100 193,194,195,196,197,198,199,200 fourHundredGigE26 25 400000 +Ethernet104 217,218,219,220,221,222,223,224 fourHundredGigE27 26 400000 +Ethernet108 209,210,211,212,213,214,215,216 fourHundredGigE28 27 400000 +Ethernet112 233,234,235,236,237,238,239,240 fourHundredGigE29 28 400000 +Ethernet116 225,226,227,228,229,230,231,232 fourHundredGigE30 29 400000 +Ethernet120 249,250,251,252,253,254,255,256 fourHundredGigE31 30 400000 +Ethernet124 241,242,243,244,245,246,247,248 fourHundredGigE32 31 400000 diff --git a/device/accton/x86_64-accton_as9716_32d-r0/Accton-AS9716-32D/sai.profile b/device/accton/x86_64-accton_as9716_32d-r0/Accton-AS9716-32D/sai.profile new file mode 100644 index 000000000000..be39b1f961f2 --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/Accton-AS9716-32D/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/th3-as9716-32x400G.config.bcm diff --git a/device/accton/x86_64-accton_as9716_32d-r0/default_sku b/device/accton/x86_64-accton_as9716_32d-r0/default_sku new file mode 100644 index 000000000000..ccebae89a34e --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/default_sku @@ -0,0 +1 @@ +Accton-AS9716-32D t1 diff --git a/device/accton/x86_64-accton_as9716_32d-r0/installer.conf b/device/accton/x86_64-accton_as9716_32d-r0/installer.conf new file mode 100644 index 000000000000..d5f9419d77ff --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off" diff --git a/device/accton/x86_64-accton_as9716_32d-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as9716_32d-r0/plugins/eeprom.py new file mode 100644 index 000000000000..1e7d1046d93d --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/plugins/eeprom.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/0-0056/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as9716_32d-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as9716_32d-r0/plugins/psuutil.py new file mode 100644 index 000000000000..25eceb7428c7 --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/plugins/psuutil.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/bus/i2c/devices/" + self.psu_presence = "/psu_present" + self.psu_oper_status = "/psu_power_good" + self.psu_mapping = { + 2: "10-0051", + 1: "9-0050", + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/accton/x86_64-accton_as9716_32d-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as9716_32d-r0/plugins/sfputil.py new file mode 100644 index 000000000000..17799035963e --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/plugins/sfputil.py @@ -0,0 +1,150 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 0 + PORT_END = 33 + PORTS_IN_BLOCK = 34 + + BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" + BASE_CPLD1_PATH = "/sys/bus/i2c/devices/20-0061/" + BASE_CPLD2_PATH = "/sys/bus/i2c/devices/21-0062/" + + _port_to_is_present = {} + _port_to_lp_mode = {} + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 0: [1, 25], + 1: [2, 26], + 2: [3, 27], + 3: [4, 28], + 4: [5, 29], + 5: [6, 30], + 6: [7, 31], + 7: [8, 32], + 8: [9, 33], + 9: [10, 34], + 10: [11, 35], + 11: [12, 36], + 12: [13, 37], + 13: [14, 38], + 14: [15, 39], + 15: [16, 40], + 16: [17, 41], + 17: [18, 42], + 18: [19, 43], + 19: [20, 44], + 20: [21, 45], + 21: [22, 46], + 22: [23, 47], + 23: [24, 48], + 24: [25, 49], + 25: [26, 50], + 26: [27, 51], + 27: [28, 52], + 28: [29, 53], + 29: [30, 54], + 30: [31, 55], + 31: [32, 56], + 32: [33, 57], + 33: [34, 58], + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = self.BASE_OOM_PATH + "eeprom" + + for x in range(0, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self._port_to_i2c_mapping[x][1] + ) + + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + if port_num < 16 : + present_path = self.BASE_CPLD1_PATH + "module_present_" + str(port_num+1) + else: + present_path = self.BASE_CPLD2_PATH + "module_present_" + str(port_num+1) + self.__port_to_is_present = present_path + + try: + val_file = open(self.__port_to_is_present) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + raise NotImplementedError + + def set_low_power_mode(self, port_num, lpmode): + raise NotImplementedError + + def reset(self, port_num): + if port_num < self.port_start or port_num > self.port_end: + return False + + if port_num < 16 : + mod_rst_path = self.BASE_CPLD1_PATH + "module_reset_" + str(port_num+1) + else: + mod_rst_path = self.BASE_CPLD2_PATH + "module_reset_" + str(port_num+1) + + self.__port_to_mod_rst = mod_rst_path + try: + reg_file = open(self.__port_to_mod_rst, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = '1' + + reg_file.write(reg_value) + reg_file.close() + + return True + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError \ No newline at end of file diff --git a/device/accton/x86_64-accton_as9716_32d-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as9716_32d-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..44bad6494229 --- /dev/null +++ b/device/accton/x86_64-accton_as9716_32d-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true +} + diff --git a/device/arista/x86_64-arista_7060px4_32/Arista-7060PX4-O32/th3-a7060px4-o32-32x400G.config.bcm b/device/arista/x86_64-arista_7060px4_32/Arista-7060PX4-O32/th3-a7060px4-o32-32x400G.config.bcm index 5cb507321b02..d3a66dee635f 100644 --- a/device/arista/x86_64-arista_7060px4_32/Arista-7060PX4-O32/th3-a7060px4-o32-32x400G.config.bcm +++ b/device/arista/x86_64-arista_7060px4_32/Arista-7060PX4-O32/th3-a7060px4-o32-32x400G.config.bcm @@ -815,3 +815,37 @@ serdes_core_tx_polarity_flip_physical{233}=0x36 serdes_core_tx_polarity_flip_physical{241}=0xc6 serdes_core_tx_polarity_flip_physical{249}=0xc3 serdes_core_tx_polarity_flip_physical{257}=0x0 +serdes_tx_taps_cd0=pam4:-28:124:-12:4:0:0 +serdes_tx_taps_cd1=pam4:-28:124:-12:4:0:0 +serdes_tx_taps_cd2=pam4:-28:124:-12:4:0:0 +serdes_tx_taps_cd3=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd4=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd5=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd6=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd7=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd8=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd9=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd10=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd11=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd12=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd13=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd14=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd15=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd16=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd17=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd18=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd19=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd20=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd21=pam4:-28:124:0:4:0:0 +serdes_tx_taps_cd22=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd23=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd24=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd25=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd26=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd27=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd28=pam4:-28:120:-4:4:0:0 +serdes_tx_taps_cd29=pam4:-28:124:-12:4:0:0 +serdes_tx_taps_cd30=pam4:-28:124:-12:4:0:0 +serdes_tx_taps_cd31=pam4:-28:124:-12:4:0:0 +serdes_tx_taps_cd32=pam4:1:34:9:0:0:0 +serdes_tx_taps_cd33=pam4:1:34:9:0:0:0 diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/eeprom.py b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/eeprom.py index c06a1899fc3c..9c14441475d4 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/eeprom.py +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/eeprom.py @@ -9,6 +9,9 @@ import sys import errno import datetime + import logging + import logging.config + import yaml sys.path.append(os.path.dirname(__file__)) import pltfm_mgr_rpc @@ -71,13 +74,17 @@ pltfm_mgr = None EEPROM_SYMLINK = "/var/run/platform/eeprom/syseeprom" - +EEPROM_STATUS = "/var/run/platform/eeprom/status" class board(eeprom_tlvinfo.TlvInfoDecoder): - RETRIES = 30 + RETRIES = 3 def __init__(self, name, path, cpld_root, ro): + with open(os.path.dirname(__file__) + "/logging.conf", 'r') as f: + config_dict = yaml.load(f) + logging.config.dictConfig(config_dict) + if not os.path.exists(os.path.dirname(EEPROM_SYMLINK)): try: os.makedirs(os.path.dirname(EEPROM_SYMLINK)) @@ -86,19 +93,17 @@ def __init__(self, name, path, cpld_root, ro): raise open(EEPROM_SYMLINK, 'a').close() + f = open(EEPROM_STATUS, 'w') + f.write("initializing..") + f.close() self.eeprom_path = EEPROM_SYMLINK - super(board, self).__init__(self.eeprom_path, 0, '', True) + super(board, self).__init__(self.eeprom_path, 0, EEPROM_STATUS, True) - for attempt in range(self.RETRIES + 1): - if not self.eeprom_init(): - time.sleep(1) - else: + for attempt in range(self.RETRIES): + if self.eeprom_init() or (attempt + 1 >= self.RETRIES): break - - if attempt == self.RETRIES: - raise RuntimeError("Could not initialize syseeprom") - + time.sleep(1) def thrift_setup(self): global thrift_server, transport, pltfm_mgr @@ -119,13 +124,18 @@ def thrift_teardown(self): def eeprom_init(self): global pltfm_mgr + try: - self.thrift_setup() - eeprom = pltfm_mgr.pltfm_mgr_sys_eeprom_get() - self.thrift_teardown() + self.thrift_setup() + eeprom = pltfm_mgr.pltfm_mgr_sys_eeprom_get() + self.thrift_teardown() except: return False + f = open(EEPROM_STATUS, 'w') + f.write("ok") + f.close() + eeprom_params = "" for attr, val in eeprom.__dict__.iteritems(): if val is None: diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/logging.conf b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/logging.conf new file mode 100644 index 000000000000..d7fd84773404 --- /dev/null +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/logging.conf @@ -0,0 +1,17 @@ +version: 1 +disable_existing_loggers: False + +formatters: + simple: + format: '%(asctime)s %(name)-30s %(levelname)-7s %(message)s' + +handlers: + file: + class: logging.handlers.RotatingFileHandler + formatter: simple + filename: /var/log/platform.log + +root: + level: ERROR + handlers: + - file diff --git a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py index c92bc4212123..5e75376baa27 100644 --- a/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py +++ b/device/barefoot/x86_64-accton_wedge100bf_32x-r0/plugins/sfputil.py @@ -34,6 +34,7 @@ class SfpUtil(SfpUtilBase): QSFP_PORT_START = 1 QSFP_PORT_END = 0 EEPROM_OFFSET = 0 + QSFP_CHECK_INTERVAL = 4 @property def port_start(self): @@ -56,6 +57,11 @@ def port_to_eeprom_mapping(self): raise Exception() def __init__(self): + self.ready = False + self.phy_port_dict = {'-1': 'system_not_ready'} + self.phy_port_cur_state = {} + self.qsfp_interval = self.QSFP_CHECK_INTERVAL + if not os.path.exists(os.path.dirname(SFP_EEPROM_CACHE)): try: os.makedirs(os.path.dirname(SFP_EEPROM_CACHE)) @@ -142,12 +148,76 @@ def reset(self, port_num): self.thrift_teardown() return status + def check_transceiver_change(self): + if not self.ready: + return + + self.phy_port_dict = {} + + try: + self.thrift_setup() + except: + return + + # Get presence of each SFP + for port in range(self.port_start, self.port_end + 1): + try: + sfp_resent = pltfm_mgr.pltfm_mgr_qsfp_presence_get(port) + except: + sfp_resent = False + sfp_state = '1' if sfp_resent else '0' + + if port in self.phy_port_cur_state: + if self.phy_port_cur_state[port] != sfp_state: + self.phy_port_dict[port] = sfp_state + else: + self.phy_port_dict[port] = sfp_state + + # Update port current state + self.phy_port_cur_state[port] = sfp_state + + self.thrift_teardown() + def get_transceiver_change_event(self, timeout=0): - phy_port_dict = {} - status = True - # TODO: Process transceiver plug-in/out event - time.sleep(1) - return status, phy_port_dict + forever = False + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + print "get_transceiver_change_event:Invalid timeout value", timeout + return False, {} + + while forever or timeout > 0: + if not self.ready: + try: + self.thrift_setup() + self.thrift_teardown() + except: + pass + else: + self.ready = True + self.phy_port_dict = {} + break + elif self.qsfp_interval == 0: + self.qsfp_interval = self.QSFP_CHECK_INTERVAL + + # Process transceiver plug-in/out event + self.check_transceiver_change() + + # Break if tranceiver state has changed + if bool(self.phy_port_dict): + break + + if timeout: + timeout -= 1 + + if self.qsfp_interval: + self.qsfp_interval -= 1 + + time.sleep(1) + + return self.ready, self.phy_port_dict def _get_port_eeprom_path(self, port_num, devid): eeprom_path = None diff --git a/device/celestica/x86_64-cel_e1031-r0/fancontrol-B2F b/device/celestica/x86_64-cel_e1031-r0/fancontrol-B2F index cab392995bb5..883f3c0c899d 100644 --- a/device/celestica/x86_64-cel_e1031-r0/fancontrol-B2F +++ b/device/celestica/x86_64-cel_e1031-r0/fancontrol-B2F @@ -1,7 +1,7 @@ # Configuration file generated by pwmconfig, changes will be lost INTERVAL=2 DEVPATH=hwmon3=devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-23/23-004d hwmon2=devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-11/11-001a -DEVNAME=hwmon3=emc2305 hwmon2=max6697 +DEVNAME=hwmon3=emc2305 hwmon2=max6699 FCTEMPS=hwmon3/device/pwm1=hwmon2/temp1_input hwmon3/device/pwm2=hwmon2/temp1_input hwmon3/device/pwm4=hwmon2/temp1_input FCFANS=hwmon3/device/pwm1=hwmon3/device/fan1_input hwmon3/device/pwm2=hwmon3/device/fan2_input hwmon3/device/pwm4=hwmon3/device/fan4_input MINTEMP=hwmon3/device/pwm1=27 hwmon3/device/pwm2=27 hwmon3/device/pwm4=27 diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/__init__.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/__init__.py index e69de29bb2d1..d82f3749319c 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/__init__.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py index a611be9d47dc..633af66dbaa8 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/chassis.py @@ -26,13 +26,16 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -NUM_FAN = 3 +NUM_FAN_TRAY = 3 +NUM_FAN = 1 NUM_PSU = 2 NUM_THERMAL = 7 NUM_SFP = 52 RESET_REGISTER = "0x112" -REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt" +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/previous-reboot-cause.txt" COMPONENT_NAME_LIST = ["SMC_CPLD", "MMC_CPLD", "BIOS"] +HOST_CHK_CMD = "docker > /dev/null 2>&1" class Chassis(ChassisBase): @@ -40,9 +43,10 @@ class Chassis(ChassisBase): def __init__(self): self.config_data = {} - for index in range(0, NUM_FAN): - fan = Fan(index) - self._fan_list.append(fan) + for fant_index in range(0, NUM_FAN_TRAY): + for fan_index in range(0, NUM_FAN): + fan = Fan(fant_index, fan_index) + self._fan_list.append(fan) for index in range(0, NUM_PSU): psu = Psu(index) self._psu_list.append(psu) @@ -53,17 +57,23 @@ def __init__(self): sfp = Sfp(index) self._sfp_list.append(sfp) ChassisBase.__init__(self) + self._reboot_cause_path = HOST_REBOOT_CAUSE_PATH if self.__is_host( + ) else PMON_REBOOT_CAUSE_PATH self._component_name_list = COMPONENT_NAME_LIST self._watchdog = Watchdog() self._eeprom = Tlv() + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + def __read_txt_file(self, file_path): try: with open(file_path, 'r') as fd: data = fd.read() return data.strip() except IOError: - raise IOError("Unable to open %s file !" % file_path) + pass + return None def get_base_mac(self): """ @@ -137,14 +147,15 @@ def get_reboot_cause(self): description = 'None' reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER hw_reboot_cause = self.component.get_register_value(RESET_REGISTER) - sw_reboot_cause = self.__read_txt_file(REBOOT_CAUSE_PATH) + sw_reboot_cause = self.__read_txt_file( + self._reboot_cause_path) or "Unknown" - if sw_reboot_cause != "Unexpected reboot": + if hw_reboot_cause == "0x55": reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE description = sw_reboot_cause elif hw_reboot_cause == "0x11": reboot_cause = self.REBOOT_CAUSE_POWER_LOSS - elif hw_reboot_cause == "0x33" or hw_reboot_cause == "0x55": + elif hw_reboot_cause == "0x33": reboot_cause = self.REBOOT_CAUSE_WATCHDOG else: reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py index ad993ce24182..2c5bc5c0c45c 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/fan.py @@ -17,34 +17,50 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -EMC2305_FAN_PATH = "/sys/bus/i2c/drivers/emc2305/" +EMC2305_PATH = "/sys/bus/i2c/drivers/emc2305/" FAN_PATH = "/sys/devices/platform/e1031.smc/" -SYS_GPIO_DIR = "/sys/class/gpio" EMC2305_MAX_PWM = 255 EMC2305_FAN_PWM = "pwm{}" EMC2305_FAN_TARGET = "fan{}_target" EMC2305_FAN_INPUT = "pwm{}" FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"] +PSU_FAN_MAX_RPM = 11000 +PSU_HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" +PSU_I2C_MAPPING = { + 0: { + "num": 13, + "addr": "5b" + }, + 1: { + "num": 12, + "addr": "5a" + }, +} class Fan(FanBase): """Platform-specific Fan class""" - def __init__(self, fan_index): - self.index = fan_index - self.config_data = {} - self.fan_speed = 0 + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]["num"] + self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]["addr"] + self.psu_hwmon_path = PSU_HWMON_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) # e1031 fan attributes # Single emc2305 chip located at i2c-23-4d # to control a fan module - self.e1031_emc2305_chip = [ + self.emc2305_chip_mapping = [ { 'device': "23-004d", 'index_map': [1, 2, 4] } ] - self.fan_e1031_presence = "fan{}_prs" self.fan_e1031_direction = "fan{}_dir" self.fan_e1031_led = "fan{}_led" @@ -55,84 +71,103 @@ def __init__(self, fan_index): } FanBase.__init__(self) - def get_direction(self): - - direction = self.FAN_DIRECTION_INTAKE - + def __read_txt_file(self, file_path): try: - fan_direction_file = (FAN_PATH + - self.fan_e1031_direction.format(self.index+1)) - with open(fan_direction_file, 'r') as file: - raw = file.read().strip('\r\n') - if str(raw).upper() == "F2B": - direction = self.FAN_DIRECTION_INTAKE - else: - direction = self.FAN_DIRECTION_EXHAUST + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() except IOError: + pass + return "" + + def __write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except: return False + return True + + def __search_file_by_name(self, directory, file_name): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name in file_name: + return file_path + return None + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = self.FAN_DIRECTION_EXHAUST + if not self.is_psu_fan: + fan_direction_file = (FAN_PATH + + self.fan_e1031_direction.format(self.fan_tray_index+1)) + raw = self.__read_txt_file(fan_direction_file).strip('\r\n') + direction = self.FAN_DIRECTION_INTAKE if str( + raw).upper() == "F2B" else self.FAN_DIRECTION_EXHAUST return direction def get_speed(self): """ - E1031 platform specific data: + Retrieves the speed of fan as a percentage of full speed + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + Note: speed = pwm_in/255*100 """ - # TODO: Seperate PSU's fan and main fan class - if self.fan_speed != 0: - return self.fan_speed - else: - speed = 0 - pwm = [] - emc2305_chips = self.e1031_emc2305_chip - - for chip in emc2305_chips: - device = chip['device'] - fan_index = chip['index_map'] - sysfs_path = "%s%s/%s" % ( - EMC2305_FAN_PATH, device, EMC2305_FAN_INPUT) - sysfs_path = sysfs_path.format(fan_index[self.index]) - try: - with open(sysfs_path, 'r') as file: - raw = file.read().strip('\r\n') - pwm.append(int(raw, 10)) - except IOError: - raise IOError("Unable to open " + sysfs_path) - - speed = math.ceil( - float(pwm[0]) * 100 / EMC2305_MAX_PWM) - - return int(speed) + speed = 0 + if self.is_psu_fan: + fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) + fan_speed_sysfs_path = self.__search_file_by_name( + self.psu_hwmon_path, fan_speed_sysfs_name) + fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 + fan_speed_raw = float(fan_speed_rpm)/PSU_FAN_MAX_RPM * 100 + speed = math.ceil(float(fan_speed_rpm) * 100 / PSU_FAN_MAX_RPM) + elif self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] + device = chip['device'] + fan_index = chip['index_map'] + sysfs_path = "%s%s/%s" % ( + EMC2305_PATH, device, EMC2305_FAN_INPUT) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + raw = self.__read_txt_file(sysfs_path).strip('\r\n') + pwm = int(raw, 10) if raw else 0 + speed = math.ceil(float(pwm * 100 / EMC2305_MAX_PWM)) + + return int(speed) def get_target_speed(self): """ - E1031 platform specific data: + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + Note: speed_pc = pwm_target/255*100 0 : when PWM mode is use pwm : when pwm mode is not use - """ target = 0 - pwm = [] - emc2305_chips = self.e1031_emc2305_chip - - for chip in emc2305_chips: + if not self.is_psu_fan: + chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( - EMC2305_FAN_PATH, device, EMC2305_FAN_TARGET) - sysfs_path = sysfs_path.format(fan_index[self.index]) - try: - with open(sysfs_path, 'r') as file: - raw = file.read().strip('\r\n') - pwm.append(int(raw, 10)) - except IOError: - raise IOError("Unable to open " + sysfs_path) - - target = pwm[0] * 100 / EMC2305_MAX_PWM + EMC2305_PATH, device, EMC2305_FAN_TARGET) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + raw = self.__read_txt_file(sysfs_path).strip('\r\n') + pwm = int(raw, 10) if raw else 0 + target = math.ceil(float(pwm) * 100 / EMC2305_MAX_PWM) return target @@ -147,40 +182,50 @@ def get_speed_tolerance(self): def set_speed(self, speed): """ - Depends on pwm or target mode is selected: + Sets the fan speed + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + A boolean, True if speed is set successfully, False if not + + Note: + Depends on pwm or target mode is selected: 1) pwm = speed_pc * 255 <-- Currently use this mode. 2) target_pwm = speed_pc * 100 / 255 2.1) set pwm{}_enable to 3 """ pwm = speed * 255 / 100 - emc2305_chips = self.e1031_emc2305_chip - - for chip in emc2305_chips: + if not self.is_psu_fan and self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( - EMC2305_FAN_PATH, device, EMC2305_FAN_PWM) - sysfs_path = sysfs_path.format(fan_index[self.index]) - try: - with open(sysfs_path, 'w') as file: - file.write(str(int(pwm))) - except IOError: - return False + EMC2305_PATH, device, EMC2305_FAN_PWM) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + return self.__write_txt_file(sysfs_path, int(pwm)) - return True + return False def set_status_led(self, color): - - try: + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + set_status_led = False + if not self.is_psu_fan: fan_led_file = (FAN_PATH + - self.fan_e1031_led.format(self.index+1)) - with open(fan_led_file, 'r') as file: - file.write(self.fan_e1031_led_col_map[color]) - except IOError: - return False + self.fan_e1031_led.format(self.fan_tray_index+1)) - return True + set_status_led = self.__write_txt_file( + fan_led_file, self.fan_e1031_led_col_map[color]) if self.get_presence() else False + + return set_status_led def get_name(self): """ @@ -188,7 +233,10 @@ def get_name(self): Returns: string: The name of the device """ - return FAN_NAME_LIST[self.index] + fan_name = FAN_NAME_LIST[self.fan_tray_index] if not self.is_psu_fan else "PSU-{} FAN-{}".format( + self.psu_index+1, self.fan_index+1) + + return fan_name def get_presence(self): """ @@ -196,13 +244,8 @@ def get_presence(self): Returns: bool: True if PSU is present, False if not """ + fan_direction_file = (FAN_PATH + + self.fan_e1031_presence.format(self.fan_tray_index+1)) + present_str = self.__read_txt_file(fan_direction_file) or '1' - try: - fan_direction_file = (FAN_PATH + - self.fan_e1031_presence.format(self.index+1)) - with open(fan_direction_file, 'r') as file: - present = int(file.read().strip('\r\n')) - except IOError: - return False - - return present == 0 + return int(present_str) == 0 if not self.is_psu_fan else True diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/psu.py index 73b890a8b773..9777bb6fea64 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/psu.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/psu.py @@ -18,8 +18,20 @@ raise ImportError(str(e) + "- required module not found") FAN_E1031_SPEED_PATH = "/sys/class/hwmon/hwmon{}/fan1_input" +HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" FAN_MAX_RPM = 11000 PSU_NAME_LIST = ["PSU-R", "PSU-L"] +PSU_NUM_FAN = [1, 1] +PSU_I2C_MAPPING = { + 0: { + "num": 13, + "addr": "5b" + }, + 1: { + "num": 12, + "addr": "5a" + }, +} class Psu(PsuBase): @@ -31,26 +43,109 @@ def __init__(self, psu_index): self.psu_path = "/sys/devices/platform/e1031.smc/" self.psu_presence = "psu{}_prs" self.psu_oper_status = "psu{}_status" + self.i2c_num = PSU_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_addr) + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + PsuBase.__init__(self) + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __search_file_by_contain(self, directory, search_str, file_start): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name.startswith(file_start) and search_str in self.__read_txt_file(file_path): + return file_path + return None - def get_fan(self): + def get_voltage(self): """ - Retrieves object representing the fan module contained in this PSU + Retrieves current PSU voltage output Returns: - An object dervied from FanBase representing the fan module - contained in this PSU + A float number, the output voltage in volts, + e.g. 12.1 """ - fan_speed_path = FAN_E1031_SPEED_PATH.format( - str(self.index+3)) - try: - with open(fan_speed_path) as fan_speed_file: - fan_speed_rpm = int(fan_speed_file.read()) - except IOError: - fan_speed = 0 + psu_voltage = 0.0 + voltage_name = "in{}_input" + voltage_label = "vout1" - fan_speed = float(fan_speed_rpm)/FAN_MAX_RPM * 100 - fan = Fan(0) - fan.fan_speed = int(fan_speed) if int(fan_speed) <= 100 else 100 - return fan + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, voltage_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = filter(str.isdigit, basename) + vout_path = os.path.join( + dir_name, voltage_name.format(in_num)) + vout_val = self.__read_txt_file(vout_path) + psu_voltage = float(vout_val) / 1000 + + return psu_voltage + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + psu_current = 0.0 + current_name = "curr{}_input" + current_label = "iout1" + + curr_label_path = self.__search_file_by_contain( + self.hwmon_path, current_label, "cur") + if curr_label_path: + dir_name = os.path.dirname(curr_label_path) + basename = os.path.basename(curr_label_path) + cur_num = filter(str.isdigit, basename) + cur_path = os.path.join( + dir_name, current_name.format(cur_num)) + cur_val = self.__read_txt_file(cur_path) + psu_current = float(cur_val) / 1000 + + return psu_current + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + psu_power = 0.0 + current_name = "power{}_input" + current_label = "pout1" + + pw_label_path = self.__search_file_by_contain( + self.hwmon_path, current_label, "power") + if pw_label_path: + dir_name = os.path.dirname(pw_label_path) + basename = os.path.basename(pw_label_path) + pw_num = filter(str.isdigit, basename) + pw_path = os.path.join( + dir_name, current_name.format(pw_num)) + pw_val = self.__read_txt_file(pw_path) + psu_power = float(pw_val) / 1000000 + + return psu_power + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() def set_status_led(self, color): """ @@ -64,6 +159,15 @@ def set_status_led(self, color): # Hardware not supported return False + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + # Hardware not supported + return self.STATUS_LED_COLOR_OFF + def get_name(self): """ Retrieves the name of the device @@ -79,14 +183,10 @@ def get_presence(self): bool: True if PSU is present, False if not """ psu_location = ["R", "L"] - status = 0 - try: - with open(self.psu_path + self.psu_presence.format(psu_location[self.index]), 'r') as psu_prs: - status = int(psu_prs.read()) - except IOError: - return False + presences_status = self.__read_txt_file( + self.psu_path + self.psu_presence.format(psu_location[self.index])) or 0 - return status == 1 + return int(presences_status) == 1 def get_status(self): """ @@ -95,11 +195,7 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ psu_location = ["R", "L"] - status = 0 - try: - with open(self.psu_path + self.psu_oper_status.format(psu_location[self.index]), 'r') as power_status: - status = int(power_status.read()) - except IOError: - return False + power_status = self.__read_txt_file( + self.psu_path + self.psu_oper_status.format(psu_location[self.index])) or 0 - return status == 1 + return int(power_status) == 1 diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py index 8379299569f5..4cfdcf50b66d 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/sfp.py @@ -15,16 +15,65 @@ from ctypes import create_string_buffer try: - from swsssdk import ConfigDBConnector from sonic_platform_base.sfp_base import SfpBase - from sonic_platform_base.sonic_sfp.sfputilbase import SfpUtilBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sffbase + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") - -class Sfp(SfpBase, SfpUtilBase): +INFO_OFFSET = 0 +DOM_OFFSET = 256 + +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + +# Offset for values in SFP eeprom +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes', 'FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia', 'FibreChannelSpeed') + + +class Sfp(SfpBase): """Platform-specific Sfp class""" + # Port number PORT_START = 1 PORT_END = 52 port_to_i2c_mapping = { @@ -33,50 +82,39 @@ class Sfp(SfpBase, SfpUtilBase): 51: 17, 52: 16 } + _sfp_port = range(49, PORT_END + 1) PRS_PATH = "/sys/devices/platform/e1031.smc/SFP/sfp_modabs" PLATFORM_ROOT_PATH = '/usr/share/sonic/device' - SFP_STATUS_CONTROL_OFFSET = 110 - SFP_STATUS_CONTROL_WIDTH = 1 + PMON_HWSKU_PATH = '/usr/share/sonic/hwsku' + HOST_CHK_CMD = "docker > /dev/null 2>&1" - _port_to_eeprom_mapping = {} - _sfp_port = range(49, PORT_END + 1) + PLATFORM = "x86_64-cel_e1031-r0" + HWSKU = "Celestica-E1031-T48S4" + + def __init__(self, sfp_index): + # Init index + self.index = sfp_index + self.port_num = self.index + 1 + + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + for x in range(self.PORT_START, self.PORT_END + 1): + if x not in self._sfp_port: + self.port_to_i2c_mapping[x] = None + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self.port_to_i2c_mapping[x]) + + self.info_dict_keys = ['type', 'hardwarerev', 'serialnum', 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] - SFP_EEPROM_TYPE_KEY = "TypeOfTransceiver" - SFP_EEPROM_HW_REV_KEY = "VendorRev" - SFP_EEPROM_MF_NAME_KEY = "VendorName" - SFP_EEPROM_MODEL_NAME_KEY = "VendorPN" - SFP_EEPROM_SERIAL_KEY = "VendorSN" - SFP_EEPROM_CONNECTOR_KEY = "Connector" - SFP_EEPROM_ENCODE_KEY = "EncodingCodes" - SFP_EEPROM_EXT_IDENT_KEY = "ExtIdentOfTypeOfTransceiver" - SFP_EEPROM_CABLE_KEY = "LengthCable(UnitsOfm)" - SFP_EEPROM_BIT_RATE_KEY = "NominalSignallingRate(UnitsOf100Mbd)" - SFP_EEPROM_SPEC_COM_KEY = "Specification compliance" - SFP_EEPROM_DATE_KEY = "VendorDataCode(YYYY-MM-DD Lot)" - SFP_EEPROM_OUI_KEY = "VendorOUI" - SFP_EEPROM_MON_DATA_KEY = "MonitorData" - SFP_EEPROM_TEMP_KEY = "Temperature" - SFP_EEPROM_VCC_KEY = "Vcc" - SFP_EEPROM_RX_PWR_KEY = "RXPower" - SFP_EEPROM_TX_PWR_KEY = "TXPower" - SFP_EEPROM_TX_BS_KEY = "TXBias" - SFP_EEPROM_STATUS_CON_KEY = "StatusControl" - - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return [] - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) def _convert_string_to_num(self, value_str): if "-inf" in value_str: @@ -98,64 +136,45 @@ def _convert_string_to_num(self, value_str): else: return 'N/A' - def get_low_power_mode(self, port_num): - raise NotImplementedError - - def set_low_power_mode(self, port_num, lpmode): - raise NotImplementedError - - def get_transceiver_change_event(self, timeout=0): - raise NotImplementedError + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" - def __init__(self, sfp_index): - # Init SfpUtilBase - eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' - for x in range(self.PORT_START, self.PORT_END + 1): - if x not in self._sfp_port: - self.port_to_i2c_mapping[x] = None - self.port_to_eeprom_mapping[x] = eeprom_path.format( - self.port_to_i2c_mapping[x]) - self.read_porttab_mappings(self.__get_path_to_port_config_file()) - SfpUtilBase.__init__(self) + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 - # Init index - self.index = sfp_index - self.port_num = self.index + 1 + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) - def __get_sysfsfile_eeprom(self): + def __read_eeprom_specific_bytes(self, offset, num_bytes): sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] try: sysfsfile_eeprom = open( - sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % - sysfs_sfp_i2c_client_eeprom_path) - return sysfsfile_eeprom - - def __get_path_to_port_config_file(self): - # Get platform and hwsku - machine_info = sonic_device_util.get_machine_info() - platform = sonic_device_util.get_platform_info(machine_info) - config_db = ConfigDBConnector() - config_db.connect() - data = config_db.get_table('DEVICE_METADATA') - try: - hwsku = data['localhost']['hwsku'] - except KeyError: - hwsku = "Unknown" - - # Load platform module from source - platform_path = "/".join([self.PLATFORM_ROOT_PATH, platform]) - hwsku_path = "/".join([platform_path, hwsku]) - - # First check for the presence of the new 'port_config.ini' file - port_config_file_path = "/".join([hwsku_path, "port_config.ini"]) - if not os.path.isfile(port_config_file_path): - # port_config.ini doesn't exist. Try loading the legacy 'portmap.ini' file - port_config_file_path = "/".join([hwsku_path, "portmap.ini"]) - - return port_config_file_path + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw def get_transceiver_info(self): """ @@ -181,44 +200,84 @@ def get_transceiver_info(self): vendor_oui |1*255VCHAR |vendor OUI ======================================================================== """ - transceiver_info_dict = dict() - # get eeprom data - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('interface'): - transceiver_info_data = self.eeprom_dict['interface'].get('data') - - # set specification_compliance - spec_com = transceiver_info_data.get( - self.SFP_EEPROM_SPEC_COM_KEY, {}) - spec_com_str = "/".join(list(spec_com.values())) - - # set normal transceiver info - transceiver_info_dict['type'] = transceiver_info_data.get( - self.SFP_EEPROM_TYPE_KEY, 'N/A') - transceiver_info_dict['hardwarerev'] = transceiver_info_data.get( - self.SFP_EEPROM_HW_REV_KEY, 'N/A') - transceiver_info_dict['manufacturename'] = transceiver_info_data.get( - self.SFP_EEPROM_MF_NAME_KEY, 'N/A') - transceiver_info_dict['modelname'] = transceiver_info_data.get( - self.SFP_EEPROM_MODEL_NAME_KEY, 'N/A') - transceiver_info_dict['serialnum'] = transceiver_info_data.get( - self.SFP_EEPROM_SERIAL_KEY, 'N/A') - transceiver_info_dict['Connector'] = transceiver_info_data.get( - self.SFP_EEPROM_CONNECTOR_KEY, 'N/A') - transceiver_info_dict['encoding'] = transceiver_info_data.get( - self.SFP_EEPROM_ENCODE_KEY, 'N/A') - transceiver_info_dict['ext_identifier'] = transceiver_info_data.get( - self.SFP_EEPROM_EXT_IDENT_KEY, 'N/A') - transceiver_info_dict['cable_length'] = transceiver_info_data.get( - self.SFP_EEPROM_CABLE_KEY, 'N/A') - transceiver_info_dict['nominal_bit_rate'] = transceiver_info_data.get( - self.SFP_EEPROM_BIT_RATE_KEY, 'N/A') - transceiver_info_dict['vendor_date'] = transceiver_info_data.get( - self.SFP_EEPROM_DATE_KEY, 'N/A') - transceiver_info_dict['vendor_oui'] = transceiver_info_data.get( - self.SFP_EEPROM_OUI_KEY, 'N/A') - transceiver_info_dict['ext_rateselect_compliance'] = "N/A" - transceiver_info_dict['specification_compliance'] = spec_com_str or "N/A" + # check present status + sfpi_obj = sff8472InterfaceId() + if not self.get_presence() or not sfpi_obj: + return {} + + offset = INFO_OFFSET + + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP) + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw, 0) + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + + sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + + sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_vendor_oui_raw, 0) + + sfp_vendor_date_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + compliance_code_dict = dict() + + if sfp_interface_bulk_data: + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['Connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data[ + 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' + transceiver_info_dict['cable_type'] = "Unknown" + transceiver_info_dict['cable_length'] = "Unknown" + + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) return transceiver_info_dict @@ -230,60 +289,146 @@ def get_transceiver_bulk_status(self): ======================================================================== keys |Value Format |Information ---------------------------|---------------|---------------------------- - RX LOS |BOOLEAN |RX lost-of-signal status, - | |True if has RX los, False if not. - TX FAULT |BOOLEAN |TX fault status, - | |True if has TX fault, False if not. - Reset status |BOOLEAN |reset status, - | |True if SFP in reset, False if not. - LP mode |BOOLEAN |low power mode status, - | |True in lp mode, False if not. - TX disable |BOOLEAN |TX disable status, - | |True TX disabled, False if not. - TX disabled channel |HEX |disabled TX channles in hex, - | |bits 0 to 3 represent channel 0 + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 | |to channel 3. - Temperature |INT |module temperature in Celsius - Voltage |INT |supply voltage in mV - TX bias |INT |TX Bias Current in mA - RX power |INT |received optical power in mW - TX power |INT |TX output power in mW + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. ======================================================================== """ - transceiver_bulk_status_dict = dict() - # get eeprom data - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('dom'): - transceiver_dom_data = self.eeprom_dict['dom'].get('data', {}) - transceiver_dom_data_mmv = transceiver_dom_data.get( - self.SFP_EEPROM_MON_DATA_KEY) - - # set normal transceiver bulk status - transceiver_bulk_status_dict['temperature'] = transceiver_dom_data_mmv.get( - self.SFP_EEPROM_TEMP_KEY, 'N/A') - transceiver_bulk_status_dict['voltage'] = transceiver_dom_data_mmv.get( - self.SFP_EEPROM_VCC_KEY, 'N/A') - transceiver_bulk_status_dict['rx1power'] = transceiver_dom_data_mmv.get( - self.SFP_EEPROM_RX_PWR_KEY, 'N/A') - transceiver_bulk_status_dict['rx2power'] = "N/A" - transceiver_bulk_status_dict['rx3power'] = "N/A" - transceiver_bulk_status_dict['rx4power'] = "N/A" - transceiver_bulk_status_dict['tx1bias'] = transceiver_dom_data_mmv.get( - self.SFP_EEPROM_TX_BS_KEY, 'N/A') - transceiver_bulk_status_dict['tx2bias'] = "N/A" - transceiver_bulk_status_dict['tx3bias'] = "N/A" - transceiver_bulk_status_dict['tx4bias'] = "N/A" - transceiver_bulk_status_dict['tx1power'] = transceiver_dom_data_mmv.get( - self.SFP_EEPROM_TX_PWR_KEY, 'N/A') - transceiver_bulk_status_dict['tx2power'] = "N/A" - transceiver_bulk_status_dict['tx3power'] = "N/A" - transceiver_bulk_status_dict['tx4power'] = "N/A" - - for key in transceiver_bulk_status_dict: - transceiver_bulk_status_dict[key] = self._convert_string_to_num( - transceiver_bulk_status_dict[key]) - - return transceiver_bulk_status_dict + # check present status + sfpd_obj = sff8472Dom() + if not self.get_presence() or not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (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) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (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) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + # check present status + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys( + self.threshold_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold( + dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ + 'data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict def get_reset_status(self): """ @@ -292,7 +437,7 @@ def get_reset_status(self): A Boolean, True if reset enabled, False if disabled """ # SFP doesn't support this feature - return NotImplementedError + return False def get_rx_los(self): """ @@ -302,14 +447,12 @@ def get_rx_los(self): Note : RX LOS status is latched until a call to get_rx_los or a reset. """ rx_los = False - rx_los_key = "RXLOSState" - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('dom'): - transceiver_dom_data = self.eeprom_dict['dom'].get('data', {}) - transceiver_dom_data_sc = transceiver_dom_data.get( - self.SFP_EEPROM_STATUS_CON_KEY) - state = transceiver_dom_data_sc.get(rx_los_key) - rx_los = True if 'off' not in state.lower() else False + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + rx_los = (sffbase().test_bit(data, 1) != 0) + return rx_los def get_tx_fault(self): @@ -320,14 +463,12 @@ def get_tx_fault(self): Note : TX fault status is lached until a call to get_tx_fault or a reset. """ tx_fault = False - tx_fault_key = "TXFaultState" - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('dom'): - transceiver_dom_data = self.eeprom_dict['dom'].get('data', {}) - transceiver_dom_data_sc = transceiver_dom_data.get( - self.SFP_EEPROM_STATUS_CON_KEY) - state = transceiver_dom_data_sc.get(tx_fault_key) - tx_fault = True if 'off' not in state.lower() else False + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + tx_fault = (sffbase().test_bit(data, 2) != 0) + return tx_fault def get_tx_disable(self): @@ -337,14 +478,17 @@ def get_tx_disable(self): A Boolean, True if tx_disable is enabled, False if disabled """ tx_disable = False - tx_disable_key = "TXDisableState" - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('dom'): - transceiver_dom_data = self.eeprom_dict['dom'].get('data', {}) - transceiver_dom_data_sc = transceiver_dom_data.get( - self.SFP_EEPROM_STATUS_CON_KEY) - state = transceiver_dom_data_sc.get(tx_disable_key) - tx_disable = True if 'off' not in state.lower() else False + tx_fault = False + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + tx_disable_hard = (sffbase().test_bit( + data, SFP_TX_DISABLE_HARD_BIT) != 0) + tx_disable_soft = (sffbase().test_bit( + data, SFP_TX_DISABLE_SOFT_BIT) != 0) + tx_disable = tx_disable_hard | tx_disable_soft + return tx_disable def get_tx_disable_channel(self): @@ -357,7 +501,7 @@ def get_tx_disable_channel(self): and channel 2 have been disabled. """ # SFP doesn't support this feature - return NotImplementedError + return 0 def get_lpmode(self): """ @@ -366,7 +510,7 @@ def get_lpmode(self): A Boolean, True if lpmode is enabled, False if disabled """ # SFP doesn't support this feature - return self.get_low_power_mode(self.port_num) + return False def get_power_override(self): """ @@ -375,7 +519,7 @@ def get_power_override(self): A Boolean, True if power-override is enabled, False if disabled """ # SFP doesn't support this feature - return NotImplementedError + return False def get_temperature(self): """ @@ -405,7 +549,7 @@ def get_tx_bias(self): """ transceiver_dom_info_dict = self.get_transceiver_bulk_status() tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") - return [tx1_bs, "N/A", "N/A", "N/A"] + return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] def get_rx_power(self): """ @@ -417,7 +561,7 @@ def get_rx_power(self): """ transceiver_dom_info_dict = self.get_transceiver_bulk_status() rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") - return [rx1_pw, "N/A", "N/A", "N/A"] + return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] def get_tx_power(self): """ @@ -429,7 +573,7 @@ def get_tx_power(self): """ transceiver_dom_info_dict = self.get_transceiver_bulk_status() tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") - return [tx1_pw, "N/A", "N/A", "N/A"] + return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] def reset(self): """ @@ -438,7 +582,7 @@ def reset(self): A boolean, True if successful, False if not """ # SFP doesn't support this feature - return NotImplementedError + return False def tx_disable(self, tx_disable): """ @@ -449,26 +593,29 @@ def tx_disable(self, tx_disable): Returns: A boolean, True if tx_disable is set successfully, False if not """ - - sysfsfile_eeprom = self.__get_sysfsfile_eeprom() - status_control_raw = self._read_eeprom_specific_bytes( - sysfsfile_eeprom, self.SFP_STATUS_CONTROL_OFFSET, self.SFP_STATUS_CONTROL_WIDTH) + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self.__read_eeprom_specific_bytes( + SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) if status_control_raw is not None: - tx_disable_bit = 0x80 if tx_disable else 0x7f + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 status_control = int(status_control_raw[0], 16) tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( status_control & tx_disable_bit) try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) buffer = create_string_buffer(1) buffer[0] = chr(tx_disable_ctl) # Write to eeprom - sysfsfile_eeprom.seek(self.SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.seek(SFP_STATUS_CONTROL_OFFSET) sysfsfile_eeprom.write(buffer[0]) - except IOError as e: - print "Error: unable to open file: %s" % str(e) + except: + #print("Error: unable to open file: %s" % str(e)) return False finally: - if sysfsfile_eeprom is not None: + if sysfsfile_eeprom: sysfsfile_eeprom.close() time.sleep(0.01) return True @@ -486,7 +633,7 @@ def tx_disable_channel(self, channel, disable): A boolean, True if successful, False if not """ # SFP doesn't support this feature - return NotImplementedError + return False def set_lpmode(self, lpmode): """ @@ -497,7 +644,8 @@ def set_lpmode(self, lpmode): Returns: A boolean, True if lpmode is set successfully, False if not """ - return self.set_low_power_mode(self.port_num, lpmode) + # SFP doesn't support this feature + return False def set_power_override(self, power_override, power_set): """ @@ -516,7 +664,8 @@ def set_power_override(self, power_override, power_set): A boolean, True if power-override and power_set are set successfully, False if not """ - return NotImplementedError + # SFP doesn't support this feature + return False def get_name(self): """ @@ -524,7 +673,11 @@ def get_name(self): Returns: string: The name of the device """ - return self.logical[self.index] + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self.index] or "Unknown" + return name def get_presence(self): """ @@ -551,7 +704,7 @@ def get_model(self): Returns: string: Model/part number of device """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() + transceiver_dom_info_dict = self.get_transceiver_info() return transceiver_dom_info_dict.get("modelname", "N/A") def get_serial(self): @@ -560,5 +713,5 @@ def get_serial(self): Returns: string: Serial number of device """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() + transceiver_dom_info_dict = self.get_transceiver_info() return transceiver_dom_info_dict.get("serialnum", "N/A") diff --git a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/thermal.py b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/thermal.py index a6d45dc41c93..6c37f3b7ce88 100644 --- a/device/celestica/x86_64-cel_e1031-r0/sonic_platform/thermal.py +++ b/device/celestica/x86_64-cel_e1031-r0/sonic_platform/thermal.py @@ -22,8 +22,8 @@ class Thermal(ThermalBase): """Platform-specific Thermal class""" THERMAL_NAME_LIST = [] - MAINBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-11/11-001a/hwmon/" - CPUBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-3/3-001a/hwmon/" + MAINBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-11/11-001a/hwmon/hwmon2" + CPUBOARD_SS_PATH = "/sys/class/i2c-adapter/i2c-3/3-001a/hwmon/hwmon1" SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_e1031-r0/sensors.conf" def __init__(self, thermal_index): @@ -41,10 +41,8 @@ def __init__(self, thermal_index): self.THERMAL_NAME_LIST.append("CPU board temperature sensor : 2") # Set hwmon path - self.ss_index, self.ss_path = self.__get_ss_info(self.index) + self.ss_index, self.hwmon_path = self.__get_ss_info(self.index) self.ss_key = self.THERMAL_NAME_LIST[self.index] - self.hwmon_name = os.listdir(self.ss_path)[0] - self.hwmon_path = os.path.join(self.ss_path, self.hwmon_name) def __get_ss_info(self, index): if self.index <= 4: diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/__init__.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/__init__.py index e69de29bb2d1..d82f3749319c 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/__init__.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py index 5e98cb3d3db8..7e597b7d08e7 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/chassis.py @@ -26,13 +26,18 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -NUM_FAN = 5 +NUM_FAN_TRAY = 5 +NUM_FAN = 2 NUM_PSU = 2 NUM_THERMAL = 5 NUM_SFP = 32 RESET_REGISTER = "0x103" -REBOOT_CAUSE_PATH = "/host/reboot-cause/previous-reboot-cause.txt" +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" COMPONENT_NAME_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"] +HOST_CHK_CMD = "docker > /dev/null 2>&1" class Chassis(ChassisBase): @@ -40,9 +45,10 @@ class Chassis(ChassisBase): def __init__(self): self.config_data = {} - for index in range(0, NUM_FAN): - fan = Fan(index) - self._fan_list.append(fan) + for fant_index in range(0, NUM_FAN_TRAY): + for fan_index in range(0, NUM_FAN): + fan = Fan(fant_index, fan_index) + self._fan_list.append(fan) for index in range(0, NUM_PSU): psu = Psu(index) self._psu_list.append(psu) @@ -53,17 +59,22 @@ def __init__(self): sfp = Sfp(index) self._sfp_list.append(sfp) ChassisBase.__init__(self) + self._component_name_list = COMPONENT_NAME_LIST self._watchdog = Watchdog() self._eeprom = Tlv() + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + def __read_txt_file(self, file_path): try: with open(file_path, 'r') as fd: data = fd.read() return data.strip() except IOError: - raise IOError("Unable to open %s file !" % file_path) + pass + return None def get_base_mac(self): """ @@ -136,14 +147,27 @@ def get_reboot_cause(self): self.component = Component("CPLD1") description = 'None' reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) if self.__is_host( + ) else PMON_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE + prev_reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE) if self.__is_host( + ) else PMON_REBOOT_CAUSE_PATH + PREV_REBOOT_CAUSE_FILE + hw_reboot_cause = self.component.get_register_value(RESET_REGISTER) - sw_reboot_cause = self.__read_txt_file(REBOOT_CAUSE_PATH) - if sw_reboot_cause != "Unexpected reboot": + sw_reboot_cause = self.__read_txt_file( + reboot_cause_path) or "Unknown" + prev_sw_reboot_cause = self.__read_txt_file( + prev_reboot_cause_path) or "Unknown" + + if sw_reboot_cause == "Unknown" and (prev_sw_reboot_cause == "Unknown" or prev_sw_reboot_cause == self.REBOOT_CAUSE_POWER_LOSS) and hw_reboot_cause == "0x11": + reboot_cause = self.REBOOT_CAUSE_POWER_LOSS + elif sw_reboot_cause != "Unknown" and hw_reboot_cause == "0x11": reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE description = sw_reboot_cause - elif hw_reboot_cause == "0x11": - reboot_cause = self.REBOOT_CAUSE_POWER_LOSS + elif prev_reboot_cause_path != "Unknown" and hw_reboot_cause == "0x11": + reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE + description = prev_sw_reboot_cause elif hw_reboot_cause == "0x22": reboot_cause = self.REBOOT_CAUSE_WATCHDOG, else: diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/fan.py index 99e86d0a6c64..c0724e9bb688 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/fan.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/fan.py @@ -17,29 +17,47 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -CONFIG_DB_PATH = "/etc/sonic/config_db.json" EMC2305_PATH = "/sys/bus/i2c/drivers/emc2305/" -SYS_GPIO_DIR = "/sys/class/gpio" +GPIO_DIR = "/sys/class/gpio" +GPIO_LABEL = "pca9505" EMC2305_MAX_PWM = 255 EMC2305_FAN_PWM = "pwm{}" EMC2305_FAN_TARGET = "fan{}_target" EMC2305_FAN_INPUT = "pwm{}" -FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3", "FAN-4", "FAN-5"] +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", "FAN-5F", "FAN-5R"] +PSU_FAN_MAX_RPM = 11000 +PSU_HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" +PSU_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "5a" + }, + 1: { + "num": 11, + "addr": "5b" + }, +} class Fan(FanBase): """Platform-specific Fan class""" - def __init__(self, fan_index): - self.index = fan_index - self.config_data = {} - self.fan_speed = 0 - FanBase.__init__(self) + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]["num"] + self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]["addr"] + self.psu_hwmon_path = PSU_HWMON_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) # dx010 fan attributes # Two EMC2305s located at i2c-13-4d and i2c-13-2e # to control a dual-fan module. - self.dx010_emc2305_chip = [ + self.emc2305_chip_mapping = [ { 'device': "13-002e", 'index_map': [2, 1, 4, 5, 3] @@ -49,121 +67,133 @@ def __init__(self, fan_index): 'index_map': [2, 4, 5, 3, 1] } ] - self.dx010_fan_gpio = [ - {'base': self.get_gpio_base()}, - {'prs': 10, 'dir': 15, 'color': {'red': 31, 'green': 32}}, - {'prs': 11, 'dir': 16, 'color': {'red': 29, 'green': 30}}, - {'prs': 12, 'dir': 17, 'color': {'red': 35, 'green': 36}}, - {'prs': 13, 'dir': 18, 'color': {'red': 37, 'green': 38}}, - {'prs': 14, 'dir': 19, 'color': {'red': 33, 'green': 34}}, + {'base': self.__get_gpio_base()}, + {'prs': 11, 'dir': 16, 'color': {'red': 31, 'green': 32}}, # 1 + {'prs': 10, 'dir': 15, 'color': {'red': 29, 'green': 30}}, # 2 + {'prs': 13, 'dir': 18, 'color': {'red': 35, 'green': 36}}, # 3 + {'prs': 14, 'dir': 19, 'color': {'red': 37, 'green': 38}}, # 4 + {'prs': 12, 'dir': 17, 'color': {'red': 33, 'green': 34}}, # 5 ] + FanBase.__init__(self) - def get_gpio_base(self): - for r in os.listdir(SYS_GPIO_DIR): - if "gpiochip" in r: + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except: + return False + return True + + def __search_file_by_name(self, directory, file_name): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name in file_name: + return file_path + return None + + def __get_gpio_base(self): + for r in os.listdir(GPIO_DIR): + label_path = os.path.join(GPIO_DIR, r, "label") + if "gpiochip" in r and GPIO_LABEL in self.__read_txt_file(label_path): return int(r[8:], 10) return 216 # Reserve - def get_gpio_value(self, pinnum): + def __get_gpio_value(self, pinnum): gpio_base = self.dx010_fan_gpio[0]['base'] - - gpio_dir = SYS_GPIO_DIR + '/gpio' + str(gpio_base+pinnum) + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) gpio_file = gpio_dir + "/value" + retval = self.__read_txt_file(gpio_file) + return retval.rstrip('\r\n') - try: - with open(gpio_file, 'r') as fd: - retval = fd.read() - except IOError: - raise IOError("Unable to open " + gpio_file + "file !") - - retval = retval.rstrip('\r\n') - return retval - - def set_gpio_value(self, pinnum, value=0): + def __set_gpio_value(self, pinnum, value=0): gpio_base = self.dx010_fan_gpio[0]['base'] - - gpio_dir = SYS_GPIO_DIR + '/gpio' + str(gpio_base+pinnum) + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) gpio_file = gpio_dir + "/value" - - try: - with open(gpio_file, 'w') as fd: - retval = fd.write(str(value)) - except IOError: - raise IOError("Unable to open " + gpio_file + "file !") + return self.__write_txt_file(gpio_file, value) def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = self.FAN_DIRECTION_EXHAUST + if not self.is_psu_fan: + raw = self.__get_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['dir']) - direction = self.FAN_DIRECTION_INTAKE - raw = self.get_gpio_value(self.dx010_fan_gpio[self.index+1]['dir']) - - if int(raw, 10) == 0: - direction = self.FAN_DIRECTION_INTAKE - else: - direction = self.FAN_DIRECTION_EXHAUST + direction = self.FAN_DIRECTION_INTAKE if int( + raw, 10) == 0 else self.FAN_DIRECTION_EXHAUST return direction def get_speed(self): """ - DX010 platform specific data: + Retrieves the speed of fan as a percentage of full speed + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + Note: speed = pwm_in/255*100 """ - # TODO: Seperate PSU's fan and main fan class - if self.fan_speed != 0: - return self.fan_speed - else: - speed = 0 - pwm = [] - emc2305_chips = self.dx010_emc2305_chip - - for chip in emc2305_chips: - device = chip['device'] - fan_index = chip['index_map'] - sysfs_path = "%s%s/%s" % ( - EMC2305_PATH, device, EMC2305_FAN_INPUT) - sysfs_path = sysfs_path.format(fan_index[self.index]) - try: - with open(sysfs_path, 'r') as file: - raw = file.read().strip('\r\n') - pwm.append(int(raw, 10)) - except IOError: - raise IOError("Unable to open " + sysfs_path) - - speed = math.ceil( - float(pwm[0]) * 100 / EMC2305_MAX_PWM) - - return int(speed) + speed = 0 + if self.is_psu_fan: + fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) + fan_speed_sysfs_path = self.__search_file_by_name( + self.psu_hwmon_path, fan_speed_sysfs_name) + fan_speed_rpm = self.__read_txt_file(fan_speed_sysfs_path) or 0 + fan_speed_raw = float(fan_speed_rpm)/PSU_FAN_MAX_RPM * 100 + speed = math.ceil(float(fan_speed_rpm) * 100 / PSU_FAN_MAX_RPM) + elif self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] + device = chip['device'] + fan_index = chip['index_map'] + sysfs_path = "%s%s/%s" % ( + EMC2305_PATH, device, EMC2305_FAN_INPUT) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + raw = self.__read_txt_file(sysfs_path).strip('\r\n') + pwm = int(raw, 10) if raw else 0 + speed = math.ceil(float(pwm * 100 / EMC2305_MAX_PWM)) + + return int(speed) def get_target_speed(self): """ - DX010 platform specific data: + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + Note: speed_pc = pwm_target/255*100 0 : when PWM mode is use pwm : when pwm mode is not use - """ target = 0 - pwm = [] - emc2305_chips = self.dx010_emc2305_chip - - for chip in emc2305_chips: + if not self.is_psu_fan: + chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( EMC2305_PATH, device, EMC2305_FAN_TARGET) - sysfs_path = sysfs_path.format(fan_index[self.index]) - try: - with open(sysfs_path, 'r') as file: - raw = file.read().strip('\r\n') - pwm.append(int(raw, 10)) - except IOError: - raise IOError("Unable to open " + sysfs_path) - - target = pwm[0] * 100 / EMC2305_MAX_PWM + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + raw = self.__read_txt_file(sysfs_path).strip('\r\n') + pwm = int(raw, 10) if raw else 0 + target = math.ceil(float(pwm) * 100 / EMC2305_MAX_PWM) return target @@ -178,55 +208,68 @@ def get_speed_tolerance(self): def set_speed(self, speed): """ - Depends on pwm or target mode is selected: + Sets the fan speed + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + A boolean, True if speed is set successfully, False if not + + Note: + Depends on pwm or target mode is selected: 1) pwm = speed_pc * 255 <-- Currently use this mode. 2) target_pwm = speed_pc * 100 / 255 2.1) set pwm{}_enable to 3 """ pwm = speed * 255 / 100 - emc2305_chips = self.dx010_emc2305_chip - - for chip in emc2305_chips: + if not self.is_psu_fan and self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] device = chip['device'] fan_index = chip['index_map'] sysfs_path = "%s%s/%s" % ( EMC2305_PATH, device, EMC2305_FAN_PWM) - sysfs_path = sysfs_path.format(fan_index[self.index]) - try: - with open(sysfs_path, 'w') as file: - file.write(str(int(pwm))) - except IOError: - return False + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + return self.__write_txt_file(sysfs_path, int(pwm)) - return True + return False def set_status_led(self, color): - try: - if color == self.STATUS_LED_COLOR_GREEN: - self.set_gpio_value( - self.dx010_fan_gpio[self.index+1]['color']['red'], 1) - self.set_gpio_value( - self.dx010_fan_gpio[self.index+1]['color']['green'], 0) - - elif color == self.STATUS_LED_COLOR_RED: - self.set_gpio_value( - self.dx010_fan_gpio[self.index+1]['color']['red'], 0) - self.set_gpio_value( - self.dx010_fan_gpio[self.index+1]['color']['green'], 1) - - elif color == self.STATUS_LED_COLOR_OFF: - self.set_gpio_value( - self.dx010_fan_gpio[self.index+1]['color']['red'], 1) - self.set_gpio_value( - self.dx010_fan_gpio[self.index+1]['color']['green'], 1) - else: + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + set_status_led = False + if not self.is_psu_fan: + s1, s2 = False, False + try: + if color == self.STATUS_LED_COLOR_GREEN: + s1 = self.__set_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'], 1) + s2 = self.__set_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'], 0) + + elif color == self.STATUS_LED_COLOR_RED: + s1 = self.__set_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'], 0) + s2 = self.__set_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'], 1) + + elif color == self.STATUS_LED_COLOR_OFF: + s1 = self.__set_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'], 1) + s2 = self.__set_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'], 1) + set_status_led = s1 and s2 + return set_status_led + except IOError: return False - except IOError: - return False - - return True + return set_status_led def get_name(self): """ @@ -234,7 +277,10 @@ def get_name(self): Returns: string: The name of the device """ - return FAN_NAME_LIST[self.index] + fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] if not self.is_psu_fan else "PSU-{} FAN-{}".format( + self.psu_index+1, self.fan_index+1) + + return fan_name def get_presence(self): """ @@ -242,6 +288,7 @@ def get_presence(self): Returns: bool: True if PSU is present, False if not """ - raw = self.get_gpio_value(self.dx010_fan_gpio[self.index+1]['prs']) + present_str = self.__get_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['prs']) - return int(raw, 10) == 0 + return int(present_str, 10) == 0 if not self.is_psu_fan else True diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py index ab22314495d5..7e18827cbfb0 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/psu.py @@ -8,7 +8,7 @@ # ############################################################################# -import os.path +import os import sonic_platform try: @@ -17,66 +17,152 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -FAN_DX010_SPEED_PATH = "/sys/class/hwmon/hwmon{}/fan1_input" GREEN_LED_PATH = "/sys/devices/platform/leds_dx010/leds/dx010:green:p-{}/brightness" -FAN_MAX_RPM = 11000 -SYS_GPIO_DIR = "/sys/class/gpio" +HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" +GPIO_DIR = "/sys/class/gpio" +GPIO_LABEL = "pca9505" PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] +PSU_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "5a" + }, + 1: { + "num": 11, + "addr": "5b" + }, +} class Psu(PsuBase): """Platform-specific Psu class""" def __init__(self, psu_index): - PsuBase.__init__(self) self.index = psu_index self.green_led_path = GREEN_LED_PATH.format(self.index+1) self.dx010_psu_gpio = [ - {'base': self.get_gpio_base()}, + {'base': self.__get_gpio_base()}, {'prs': 27, 'status': 22}, {'prs': 28, 'status': 25} ] + self.i2c_num = PSU_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_addr) + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + PsuBase.__init__(self) - def get_gpio_base(self): - for r in os.listdir(SYS_GPIO_DIR): - if "gpiochip" in r: + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __search_file_by_contain(self, directory, search_str, file_start): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name.startswith(file_start) and search_str in self.__read_txt_file(file_path): + return file_path + return None + + def __get_gpio_base(self): + for r in os.listdir(GPIO_DIR): + label_path = os.path.join(GPIO_DIR, r, "label") + if "gpiochip" in r and GPIO_LABEL in self.__read_txt_file(label_path): return int(r[8:], 10) return 216 # Reserve - def get_gpio_value(self, pinnum): + def __get_gpio_value(self, pinnum): gpio_base = self.dx010_psu_gpio[0]['base'] - gpio_file = "{}/gpio{}/value".format(SYS_GPIO_DIR, - str(gpio_base+pinnum)) - - try: - with open(gpio_file, 'r') as fd: - retval = fd.read() - except IOError: - raise IOError("Unable to open " + gpio_file + "file !") + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) + gpio_file = gpio_dir + "/value" + retval = self.__read_txt_file(gpio_file) + return retval.rstrip('\r\n') - retval = retval.rstrip('\r\n') - return retval - - def get_fan(self): + def get_voltage(self): """ - Retrieves object representing the fan module contained in this PSU + Retrieves current PSU voltage output Returns: - An object dervied from FanBase representing the fan module - contained in this PSU + A float number, the output voltage in volts, + e.g. 12.1 """ - - fan_speed_path = FAN_DX010_SPEED_PATH.format( - str(self.index+8)) - try: - with open(fan_speed_path) as fan_speed_file: - fan_speed_rpm = int(fan_speed_file.read()) - except IOError: - fan_speed = 0 - - fan_speed = float(fan_speed_rpm)/FAN_MAX_RPM * 100 - fan = Fan(0) - fan.fan_speed = int(fan_speed) if int(fan_speed) <= 100 else 100 - return fan + psu_voltage = 0.0 + voltage_name = "in{}_input" + voltage_label = "vout1" + + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, voltage_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = filter(str.isdigit, basename) + vout_path = os.path.join( + dir_name, voltage_name.format(in_num)) + vout_val = self.__read_txt_file(vout_path) + psu_voltage = float(vout_val) / 1000 + + return psu_voltage + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + psu_current = 0.0 + current_name = "curr{}_input" + current_label = "iout1" + + curr_label_path = self.__search_file_by_contain( + self.hwmon_path, current_label, "cur") + if curr_label_path: + dir_name = os.path.dirname(curr_label_path) + basename = os.path.basename(curr_label_path) + cur_num = filter(str.isdigit, basename) + cur_path = os.path.join( + dir_name, current_name.format(cur_num)) + cur_val = self.__read_txt_file(cur_path) + psu_current = float(cur_val) / 1000 + + return psu_current + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + psu_power = 0.0 + current_name = "power{}_input" + current_label = "pout1" + + pw_label_path = self.__search_file_by_contain( + self.hwmon_path, current_label, "power") + if pw_label_path: + dir_name = os.path.dirname(pw_label_path) + basename = os.path.basename(pw_label_path) + pw_num = filter(str.isdigit, basename) + pw_path = os.path.join( + dir_name, current_name.format(pw_num)) + pw_val = self.__read_txt_file(pw_path) + psu_power = float(pw_val) / 1000000 + + return psu_power + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() def set_status_led(self, color): """ @@ -104,6 +190,20 @@ def set_status_led(self, color): return True + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status = self.__read_txt_file(self.green_led_path) + status_str = { + '255': self.STATUS_LED_COLOR_GREEN, + '0': self.STATUS_LED_COLOR_OFF + }.get(status, None) + + return status_str + def get_name(self): """ Retrieves the name of the device @@ -118,7 +218,7 @@ def get_presence(self): Returns: bool: True if PSU is present, False if not """ - raw = self.get_gpio_value(self.dx010_psu_gpio[self.index+1]['prs']) + raw = self.__get_gpio_value(self.dx010_psu_gpio[self.index+1]['prs']) return int(raw, 10) == 0 def get_status(self): @@ -127,5 +227,6 @@ def get_status(self): Returns: A boolean value, True if device is operating properly, False if not """ - raw = self.get_gpio_value(self.dx010_psu_gpio[self.index+1]['status']) + raw = self.__get_gpio_value( + self.dx010_psu_gpio[self.index+1]['status']) return int(raw, 10) == 1 diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/sfp.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/sfp.py index 6d019d7854ec..3a02be39df6e 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/sfp.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/sfp.py @@ -15,71 +15,110 @@ from ctypes import create_string_buffer try: - from swsssdk import ConfigDBConnector from sonic_platform_base.sfp_base import SfpBase - from sonic_platform_base.sonic_sfp.sfputilbase import SfpUtilBase - from sonic_platform_base.sonic_sfp.sfputilbase import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") - -class Sfp(SfpBase, SfpUtilBase): +INFO_OFFSET = 128 +DOM_OFFSET = 0 + +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 176 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed') + + + +class Sfp(SfpBase): """Platform-specific Sfp class""" # Port number PORT_START = 1 PORT_END = 32 - PORTS_IN_BLOCK = 32 - - # Offset for values in QSFP info eeprom - QSFP_CONTROL_OFFSET = 86 - QSFP_CONTROL_WIDTH = 8 - QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 - QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 - QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 - QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 - QSFP_POWEROVERRIDE_OFFSET = 93 - QSFP_POWEROVERRIDE_WIDTH = 1 - - # Key for values in QSFP eeprom dict - QSFP_EEPROM_TYPE_KEY = "Identifier" - QSFP_EEPROM_HW_REV_KEY = "Vendor Rev" - QSFP_EEPROM_MF_NAME_KEY = "Vendor Name" - QSFP_EEPROM_MODEL_NAME_KEY = "Vendor PN" - QSFP_EEPROM_SERIAL_KEY = "Vendor SN" - QSFP_EEPROM_CONNECTOR_KEY = "Connector" - QSFP_EEPROM_ENCODE_KEY = "Encoding" - QSFP_EEPROM_EXT_IDENT_KEY = "Extended Identifier" - QSFP_EEPROM_EXT_RATE_KEY = "Extended RateSelect Compliance" - QSFP_EEPROM_CABLE_KEY = "Length(km)" - QSFP_EEPROM_BIT_RATE_KEY = "Nominal Bit Rate(100Mbs)" - QSFP_EEPROM_SPEC_COM_KEY = "Specification compliance" - QSFP_EEPROM_DATE_KEY = "Vendor Date Code(YYYY-MM-DD Lot)" - QSFP_EEPROM_OUI_KEY = "Vendor OUI" # Path to QSFP sysfs RESET_PATH = "/sys/devices/platform/dx010_cpld/qsfp_reset" LP_PATH = "/sys/devices/platform/dx010_cpld/qsfp_lpmode" PRS_PATH = "/sys/devices/platform/dx010_cpld/qsfp_modprs" - PLATFORM_ROOT_PATH = '/usr/share/sonic/device' + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-cel_seastone-r0" + HWSKU = "Seastone-DX010" + + def __init__(self, sfp_index): + # Init index + self.index = sfp_index + self.port_num = self.index + 1 if self.PORT_START == 1 else index - _port_to_eeprom_mapping = {} + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + for x in range(self.PORT_START, self.PORT_END + 1): + p_num = x - 1 if self.PORT_START == 1 else x + self.port_to_eeprom_mapping[x] = eeprom_path.format(p_num + 26) - @property - def port_start(self): - return self.PORT_START + self.info_dict_keys = ['type', 'hardwarerev', 'serialnum', 'manufacturename', 'modelname', 'Connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui'] - @property - def port_end(self): - return self.PORT_END + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] - @property - def qsfp_ports(self): - return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping + SfpBase.__init__(self) def _convert_string_to_num(self, value_str): if "-inf" in value_str: @@ -101,122 +140,44 @@ def _convert_string_to_num(self, value_str): else: return 'N/A' - 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 - - try: - reg_file = open(self.LP_PATH, "r") - content = reg_file.readline().rstrip() - except IOError as e: - print("Error: unable to open file: %s" % str(e)) - return False - - # content is a string containing the hex representation of the register - reg_value = int(content, 16) - - # Determind if port_num start from 1 or 0 - bit_index = port_num - 1 if self.port_start == 1 else port_num - - # Mask off the bit corresponding to our port - mask = (1 << bit_index) - - # LPMode is active high - if reg_value & mask == 0: - return False - - return True - - def set_low_power_mode(self, port_num, lpmode): + def __read_txt_file(self, file_path): try: - reg_file = open(self.LP_PATH, "r+") - except IOError as e: - print("Error: unable to open file: %s" % str(e)) - return False - - content = reg_file.readline().rstrip() - - # content is a string containing the hex representation of the register - reg_value = int(content, 16) - - # Determind if port_num start from 1 or 0 - bit_index = port_num - 1 if self.port_start == 1 else port_num - - # Mask off the bit corresponding to our port - mask = (1 << bit_index) - # LPMode is active high; set or clear the bit accordingly - reg_value = reg_value | mask if lpmode else reg_value & ~mask - - # Convert our register value back to a hex string and write back - content = hex(reg_value).strip('L') - - reg_file.seek(0) - reg_file.write(content) - reg_file.close() - - return True - - def get_transceiver_change_event(self, timeout=0): - raise NotImplementedError - - def __init__(self, sfp_index): - # Init SfpUtilBase - eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' - - for x in range(self.PORT_START, self.PORT_END + 1): - if self.port_start == 1: - self._port_to_eeprom_mapping[x] = eeprom_path.format( - (x - 1) + 26) - else: - self._port_to_eeprom_mapping[x] = eeprom_path.format(x + 26) - self.read_porttab_mappings(self.__get_path_to_port_config_file()) - SfpUtilBase.__init__(self) + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" - # Init index - self.index = sfp_index - self.port_num = self.index + 1 + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 def __get_path_to_port_config_file(self): - # Get platform and hwsku - machine_info = sonic_device_util.get_machine_info() - platform = sonic_device_util.get_platform_info(machine_info) - config_db = ConfigDBConnector() - config_db.connect() - data = config_db.get_table('DEVICE_METADATA') - - try: - hwsku = data['localhost']['hwsku'] - except KeyError: - hwsku = "Unknown" - - # Load platform module from source - platform_path = "/".join([self.PLATFORM_ROOT_PATH, platform]) - hwsku_path = "/".join([platform_path, hwsku]) - - # First check for the presence of the new 'port_config.ini' file - port_config_file_path = "/".join([hwsku_path, "port_config.ini"]) - if not os.path.isfile(port_config_file_path): - # port_config.ini doesn't exist. Try loading the legacy 'portmap.ini' file - port_config_file_path = "/".join([hwsku_path, "portmap.ini"]) - - return port_config_file_path + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) def __read_eeprom_specific_bytes(self, offset, num_bytes): sysfsfile_eeprom = None - eeprom_raw = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] try: sysfsfile_eeprom = open( sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) - except IOError: - print("Error: reading sysfs file %s" % - sysfs_sfp_i2c_client_eeprom_path) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except: + pass finally: if sysfsfile_eeprom: - eeprom_raw = self._read_eeprom_specific_bytes( - sysfsfile_eeprom, offset, num_bytes) sysfsfile_eeprom.close() + return eeprom_raw def get_transceiver_info(self): @@ -243,45 +204,84 @@ def get_transceiver_info(self): vendor_oui |1*255VCHAR |vendor OUI ======================================================================== """ - transceiver_info_dict = dict() - # get eeprom data - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('interface'): - transceiver_info_data = self.eeprom_dict['interface'].get('data') - - # set specification_compliance - spec_com = transceiver_info_data.get( - self.QSFP_EEPROM_SPEC_COM_KEY, {}) - spec_com_str = "/".join(list(spec_com.values())) - - # set normal transceiver info - transceiver_info_dict['type'] = transceiver_info_data.get( - self.QSFP_EEPROM_TYPE_KEY, 'N/A') - transceiver_info_dict['hardwarerev'] = transceiver_info_data.get( - self.QSFP_EEPROM_HW_REV_KEY, 'N/A') - transceiver_info_dict['manufacturename'] = transceiver_info_data.get( - self.QSFP_EEPROM_MF_NAME_KEY, 'N/A') - transceiver_info_dict['modelname'] = transceiver_info_data.get( - self.QSFP_EEPROM_MODEL_NAME_KEY, 'N/A') - transceiver_info_dict['serialnum'] = transceiver_info_data.get( - self.QSFP_EEPROM_SERIAL_KEY, 'N/A') - transceiver_info_dict['Connector'] = transceiver_info_data.get( - self.QSFP_EEPROM_CONNECTOR_KEY, 'N/A') - transceiver_info_dict['encoding'] = transceiver_info_data.get( - self.QSFP_EEPROM_ENCODE_KEY, 'N/A') - transceiver_info_dict['ext_identifier'] = transceiver_info_data.get( - self.QSFP_EEPROM_EXT_IDENT_KEY, 'N/A') - transceiver_info_dict['ext_rateselect_compliance'] = transceiver_info_data.get( - self.QSFP_EEPROM_EXT_RATE_KEY, 'N/A') - transceiver_info_dict['cable_length'] = transceiver_info_data.get( - self.QSFP_EEPROM_CABLE_KEY, 'N/A') - transceiver_info_dict['vendor_date'] = transceiver_info_data.get( - self.QSFP_EEPROM_DATE_KEY, 'N/A') - transceiver_info_dict['vendor_oui'] = transceiver_info_data.get( - self.QSFP_EEPROM_OUI_KEY, 'N/A') - transceiver_info_dict['nominal_bit_rate'] = transceiver_info_data.get( - self.QSFP_EEPROM_BIT_RATE_KEY, 'N/A') - transceiver_info_dict['specification_compliance'] = spec_com_str or "N/A" + # check present status + sfpi_obj = sff8436InterfaceId() + if not self.get_presence() or not sfpi_obj: + return {} + + offset = INFO_OFFSET + + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP) + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( + sfp_interface_bulk_raw, 0) + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + sfp_vendor_name_data = sfpi_obj.parse_vendor_name( + sfp_vendor_name_raw, 0) + + sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( + sfp_vendor_pn_raw, 0) + + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP) + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( + sfp_vendor_sn_raw, 0) + + sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_vendor_oui_raw, 0) + + sfp_vendor_date_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + compliance_code_dict = dict() + + if sfp_interface_bulk_data: + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['Connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data[ + 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ + 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' + transceiver_info_dict['cable_type'] = "Unknown" + transceiver_info_dict['cable_length'] = "Unknown" + + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['nominal_bit_rate'] = str( + sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) return transceiver_info_dict @@ -293,83 +293,200 @@ def get_transceiver_bulk_status(self): ======================================================================== keys |Value Format |Information ---------------------------|---------------|---------------------------- - RX LOS |BOOLEAN |RX lost-of-signal status, - | |True if has RX los, False if not. - TX FAULT |BOOLEAN |TX fault status, - | |True if has TX fault, False if not. - Reset status |BOOLEAN |reset status, - | |True if SFP in reset, False if not. - LP mode |BOOLEAN |low power mode status, - | |True in lp mode, False if not. - TX disable |BOOLEAN |TX disable status, - | |True TX disabled, False if not. - TX disabled channel |HEX |disabled TX channles in hex, - | |bits 0 to 3 represent channel 0 + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 | |to channel 3. - Temperature |INT |module temperature in Celsius - Voltage |INT |supply voltage in mV - TX bias |INT |TX Bias Current in mA - RX power |INT |received optical power in mW - TX power |INT |TX output power in mW + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. ======================================================================== """ - transceiver_dom_info_dict = dict() - self.eeprom_dict = self.get_eeprom_dict(self.port_num) - if self.eeprom_dict and self.eeprom_dict.get('dom'): - transceiver_dom_data = self.eeprom_dict['dom'].get('data', {}) - transceiver_dom_data_mmv = transceiver_dom_data.get( - "ModuleMonitorValues") - transceiver_dom_data_cmv = transceiver_dom_data.get( - "ChannelMonitorValues") - transceiver_dom_info_dict['temperature'] = transceiver_dom_data_mmv.get( - 'Temperature', 'N/A') - transceiver_dom_info_dict['voltage'] = transceiver_dom_data_mmv.get( - 'Vcc', 'N/A') - transceiver_dom_info_dict['rx1power'] = transceiver_dom_data_cmv.get( - 'RX1Power', 'N/A') - transceiver_dom_info_dict['rx2power'] = transceiver_dom_data_cmv.get( - 'RX2Power', 'N/A') - transceiver_dom_info_dict['rx3power'] = transceiver_dom_data_cmv.get( - 'RX3Power', 'N/A') - transceiver_dom_info_dict['rx4power'] = transceiver_dom_data_cmv.get( - 'RX4Power', 'N/A') - transceiver_dom_info_dict['tx1bias'] = transceiver_dom_data_cmv.get( - 'TX1Bias', 'N/A') - transceiver_dom_info_dict['tx2bias'] = transceiver_dom_data_cmv.get( - 'TX2Bias', 'N/A') - transceiver_dom_info_dict['tx3bias'] = transceiver_dom_data_cmv.get( - 'TX3Bias', 'N/A') - transceiver_dom_info_dict['tx4bias'] = transceiver_dom_data_cmv.get( - 'TX4Bias', 'N/A') - transceiver_dom_info_dict['tx1power'] = transceiver_dom_data_cmv.get( - 'TX1Power', 'N/A') - transceiver_dom_info_dict['tx2power'] = transceiver_dom_data_cmv.get( - 'TX2Power', 'N/A') - transceiver_dom_info_dict['tx3power'] = transceiver_dom_data_cmv.get( - 'TX3Power', 'N/A') - transceiver_dom_info_dict['tx4power'] = transceiver_dom_data_cmv.get( - 'TX4Power', 'N/A') + # check present status + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not self.get_presence() or not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = DOM_OFFSET + offset_xcvr = INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_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: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (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) + 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'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] for key in transceiver_dom_info_dict: transceiver_dom_info_dict[key] = self._convert_string_to_num( transceiver_dom_info_dict[key]) + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + return transceiver_dom_info_dict + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + # check present status + sfpd_obj = sff8436Dom() + + if not self.get_presence() or not sfpd_obj: + return {} + + transceiver_dom_threshold_dict = dict.fromkeys( + self.threshold_dict_keys, 'N/A') + dom_thres_raw = self.__read_eeprom_specific_bytes( + QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None + + if dom_thres_raw: + module_threshold_values = sfpd_obj.parse_module_threshold_values( + dom_thres_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_thres_raw = self.__read_eeprom_specific_bytes( + QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None + channel_threshold_values = sfpd_obj.parse_channel_threshold_values( + dom_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self._convert_string_to_num( + transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + def get_reset_status(self): """ Retrieves the reset status of SFP Returns: A Boolean, True if reset enabled, False if disabled """ - try: - reg_file = open(self.RESET_PATH, "r") - except IOError as e: - print("Error: unable to open file: %s" % str(e)) + reset_status_raw = self.__read_txt_file(self.RESET_PATH).rstrip() + if not reset_status_raw: return False - content = reg_file.readline().rstrip() - reg_value = int(content, 16) + reg_value = int(reset_status_raw, 16) bin_format = bin(reg_value)[2:].zfill(32) return bin_format[::-1][self.index] == '0' @@ -380,16 +497,18 @@ def get_rx_los(self): A Boolean, True if SFP has RX LOS, False if not. Note : RX LOS status is latched until a call to get_rx_los or a reset. """ + rx_los = False rx_los_list = [] dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - self.QSFP_CHANNL_RX_LOS_STATUS_OFFSET, self.QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None if dom_channel_monitor_raw is not None: rx_los_data = int(dom_channel_monitor_raw[0], 16) rx_los_list.append(rx_los_data & 0x01 != 0) rx_los_list.append(rx_los_data & 0x02 != 0) rx_los_list.append(rx_los_data & 0x04 != 0) rx_los_list.append(rx_los_data & 0x08 != 0) - return rx_los_list + rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3] + return rx_los def get_tx_fault(self): """ @@ -398,16 +517,19 @@ def get_tx_fault(self): A Boolean, True if SFP has TX fault, False if not Note : TX fault status is lached until a call to get_tx_fault or a reset. """ + tx_fault = False tx_fault_list = [] dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - self.QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, self.QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None if dom_channel_monitor_raw is not None: tx_fault_data = int(dom_channel_monitor_raw[0], 16) tx_fault_list.append(tx_fault_data & 0x01 != 0) tx_fault_list.append(tx_fault_data & 0x02 != 0) tx_fault_list.append(tx_fault_data & 0x04 != 0) tx_fault_list.append(tx_fault_data & 0x08 != 0) - return tx_fault_list + tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3] + + return tx_fault def get_tx_disable(self): """ @@ -422,7 +544,7 @@ def get_tx_disable(self): return False dom_control_raw = self.__read_eeprom_specific_bytes( - self.QSFP_CONTROL_OFFSET, self.QSFP_CONTROL_WIDTH) + QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None if dom_control_raw is not None: dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) tx_disable_list.append( @@ -460,7 +582,27 @@ def get_lpmode(self): Returns: A Boolean, True if lpmode is enabled, False if disabled """ - return self.get_low_power_mode(self.port_num) + try: + reg_file = open(self.LP_PATH, "r") + content = reg_file.readline().rstrip() + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Determind if port_num start from 1 or 0 + bit_index = self.port_num - 1 if self.PORT_START == 1 else self.port_num + + # Mask off the bit corresponding to our port + mask = (1 << bit_index) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True def get_power_override(self): """ @@ -476,7 +618,7 @@ def get_power_override(self): return False dom_control_raw = self.__read_eeprom_specific_bytes( - self.QSFP_CONTROL_OFFSET, self.QSFP_CONTROL_WIDTH) + QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None if dom_control_raw is not None: dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) power_override = ( @@ -515,7 +657,7 @@ def get_tx_bias(self): tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A") tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A") tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A") - return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] + return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] if transceiver_dom_info_dict else [] def get_rx_power(self): """ @@ -530,7 +672,7 @@ def get_rx_power(self): rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A") rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A") rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A") - return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] + return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] if transceiver_dom_info_dict else [] def get_tx_power(self): """ @@ -568,7 +710,7 @@ def reset(self): reg_value = int(content, 16) # Determind if port_num start from 1 or 0 - bit_index = self.port_num - 1 if self.port_start == 1 else self.port_num + bit_index = self.port_num - 1 if self.PORT_START == 1 else self.port_num # Mask off the bit corresponding to our port mask = (1 << bit_index) @@ -615,7 +757,7 @@ def tx_disable(self, tx_disable): # Write to eeprom sysfsfile_eeprom = open( self.port_to_eeprom_mapping[self.port_num], "r+b") - sysfsfile_eeprom.seek(self.QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) sysfsfile_eeprom.write(buffer[0]) except IOError as e: print "Error: unable to open file: %s" % str(e) @@ -649,7 +791,7 @@ def tx_disable_channel(self, channel, disable): # Write to eeprom sysfsfile_eeprom = open( self.port_to_eeprom_mapping[self.port_num], "r+b") - sysfsfile_eeprom.seek(self.QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) sysfsfile_eeprom.write(buffer[0]) except IOError as e: print "Error: unable to open file: %s" % str(e) @@ -669,7 +811,33 @@ def set_lpmode(self, lpmode): Returns: A boolean, True if lpmode is set successfully, False if not """ - return self.set_low_power_mode(self.port_num, lpmode) + try: + reg_file = open(self.LP_PATH, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Determind if port_num start from 1 or 0 + bit_index = self.port_num - 1 if self.PORT_START == 1 else self.port_num + + # Mask off the bit corresponding to our port + mask = (1 << bit_index) + # LPMode is active high; set or clear the bit accordingly + reg_value = reg_value | mask if lpmode else reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value).strip('L') + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True def set_power_override(self, power_override, power_set): """ @@ -702,7 +870,7 @@ def set_power_override(self, power_override, power_set): # Write to eeprom sysfsfile_eeprom = open( self.port_to_eeprom_mapping[self.port_num], "r+b") - sysfsfile_eeprom.seek(self.QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) sysfsfile_eeprom.write(buffer[0]) except IOError as e: print "Error: unable to open file: %s" % str(e) @@ -719,7 +887,11 @@ def get_name(self): Returns: string: The name of the device """ - return self.logical[self.index] + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + name = sfputil_helper.logical[self.index] or "Unknown" + return name def get_presence(self): """ @@ -727,17 +899,15 @@ def get_presence(self): Returns: bool: True if PSU is present, False if not """ - try: - reg_file = open(self.PRS_PATH, "r") - except IOError as e: - print("Error: unable to open file: %s" % str(e)) + presence_status_raw = self.__read_txt_file(self.PRS_PATH).rstrip() + if not presence_status_raw: return False - content = reg_file.readline().rstrip() + content = presence_status_raw.rstrip() reg_value = int(content, 16) # Determind if port_num start from 1 or 0 - bit_index = self.port_num - 1 if self.port_start == 1 else self.port_num + bit_index = self.port_num - 1 if self.PORT_START == 1 else self.port_num # Mask off the bit corresponding to our port mask = (1 << bit_index) @@ -754,7 +924,7 @@ def get_model(self): Returns: string: Model/part number of device """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() + transceiver_dom_info_dict = self.get_transceiver_info() return transceiver_dom_info_dict.get("modelname", "N/A") def get_serial(self): @@ -763,5 +933,13 @@ def get_serial(self): Returns: string: Serial number of device """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() + transceiver_dom_info_dict = self.get_transceiver_info() return transceiver_dom_info_dict.get("serialnum", "N/A") + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() and self.get_transceiver_bulk_status() diff --git a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/thermal.py b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/thermal.py index 43390dce8302..1e0a2c4b5645 100644 --- a/device/celestica/x86_64-cel_seastone-r0/sonic_platform/thermal.py +++ b/device/celestica/x86_64-cel_seastone-r0/sonic_platform/thermal.py @@ -37,18 +37,16 @@ def __init__(self, thermal_index): # Set hwmon path i2c_path = { - 0: "i2c-5/5-0048", # u4 system-inlet - 1: "i2c-6/6-0049", # u2 system-inlet - 2: "i2c-7/7-004a", # u44 bmc56960-on-board - 3: "i2c-14/14-0048", # u9200 cpu-on-board - 4: "i2c-15/15-004e" # u9201 system-outlet + 0: "i2c-5/5-0048/hwmon/hwmon1", # u4 system-inlet + 1: "i2c-6/6-0049/hwmon/hwmon2", # u2 system-inlet + 2: "i2c-7/7-004a/hwmon/hwmon3", # u44 bmc56960-on-board + 3: "i2c-14/14-0048/hwmon/hwmon4", # u9200 cpu-on-board + 4: "i2c-15/15-004e/hwmon/hwmon5" # u9201 system-outlet }.get(self.index, None) - self.ss_path = "{}/{}/hwmon".format(self.I2C_ADAPTER_PATH, i2c_path) + self.hwmon_path = "{}/{}".format(self.I2C_ADAPTER_PATH, i2c_path) self.ss_key = self.THERMAL_NAME_LIST[self.index] self.ss_index = 1 - self.hwmon_name = os.listdir(self.ss_path)[0] - self.hwmon_path = os.path.join(self.ss_path, self.hwmon_name) def __read_txt_file(self, file_path): try: @@ -56,7 +54,7 @@ def __read_txt_file(self, file_path): data = fd.read() return data.strip() except IOError: - raise IOError("Unable to open %s file !" % file_path) + pass def __get_temp(self, temp_file): temp_file_path = os.path.join(self.hwmon_path, temp_file) diff --git a/device/dell/x86_64-dell_s6100_c2538-r0/bin/S6100-BIOS-3.25.0.2-7.bin b/device/dell/x86_64-dell_s6100_c2538-r0/bin/S6100-BIOS-3.25.0.2-7.bin new file mode 100644 index 000000000000..e6371a2602d6 Binary files /dev/null and b/device/dell/x86_64-dell_s6100_c2538-r0/bin/S6100-BIOS-3.25.0.2-7.bin differ diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/port_config.ini b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/port_config.ini new file mode 100644 index 000000000000..20d1b84edce5 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/port_config.ini @@ -0,0 +1,65 @@ +# name lanes alias +Ethernet0 73,74,75,76 hundredGigE1 +Ethernet4 65,66,67,68 hundredGigE2 +Ethernet8 81,82,83,84 hundredGigE3 +Ethernet12 89,90,91,92 hundredGigE4 +Ethernet16 105,106,107,108 hundredGigE5 +Ethernet20 97,98,99,100 hundredGigE6 +Ethernet24 113,114,115,116 hundredGigE7 +Ethernet28 121,122,123,124 hundredGigE8 +Ethernet32 41,42,43,44 hundredGigE9 +Ethernet36 33,34,35,36 hundredGigE10 +Ethernet40 49,50,51,52 hundredGigE11 +Ethernet44 57,58,59,60 hundredGigE12 +Ethernet48 137,138,139,140 hundredGigE13 +Ethernet52 129,130,131,132 hundredGigE14 +Ethernet56 145,146,147,148 hundredGigE15 +Ethernet60 153,154,155,156 hundredGigE16 +Ethernet64 173,174,175,176 hundredGigE17 +Ethernet68 165,166,167,168 hundredGigE18 +Ethernet72 181,182,183,184 hundredGigE19 +Ethernet76 189,190,191,192 hundredGigE20 +Ethernet80 13,14,15,16 hundredGigE21 +Ethernet84 5,6,7,8 hundredGigE22 +Ethernet88 29,30,31,32 hundredGigE23 +Ethernet92 21,22,23,24 hundredGigE24 +Ethernet96 205,206,207,208 hundredGigE25 +Ethernet100 197,198,199,200 hundredGigE26 +Ethernet104 213,214,215,216 hundredGigE27 +Ethernet108 221,222,223,224 hundredGigE28 +Ethernet112 229,230,231,232 hundredGigE29 +Ethernet116 237,238,239,240 hundredGigE30 +Ethernet120 245,246,247,248 hundredGigE31 +Ethernet124 253,254,255,256 hundredGigE32 +Ethernet128 69,70,71,72 hundredGigE33 +Ethernet132 77,78,79,80 hundredGigE34 +Ethernet136 93,94,95,96 hundredGigE35 +Ethernet140 85,86,87,88 hundredGigE36 +Ethernet144 101,102,103,104 hundredGigE37 +Ethernet148 109,110,111,112 hundredGigE38 +Ethernet152 125,126,127,128 hundredGigE39 +Ethernet156 117,118,119,120 hundredGigE40 +Ethernet160 37,38,39,40 hundredGigE41 +Ethernet164 45,46,47,48 hundredGigE42 +Ethernet168 61,62,63,64 hundredGigE43 +Ethernet172 53,54,55,56 hundredGigE44 +Ethernet176 133,134,135,136 hundredGigE45 +Ethernet180 141,142,143,144 hundredGigE46 +Ethernet184 157,158,159,160 hundredGigE47 +Ethernet188 149,150,151,152 hundredGigE48 +Ethernet192 161,162,163,164 hundredGigE49 +Ethernet196 169,170,171,172 hundredGigE50 +Ethernet200 185,186,187,188 hundredGigE51 +Ethernet204 177,178,179,180 hundredGigE52 +Ethernet208 1,2,3,4 hundredGigE53 +Ethernet212 9,10,11,12 hundredGigE54 +Ethernet216 25,26,27,28 hundredGigE55 +Ethernet220 17,18,19,20 hundredGigE56 +Ethernet224 193,194,195,196 hundredGigE57 +Ethernet228 201,202,203,204 hundredGigE58 +Ethernet232 217,218,219,220 hundredGigE59 +Ethernet236 209,210,211,212 hundredGigE60 +Ethernet240 225,226,227,228 hundredGigE61 +Ethernet244 233,234,235,236 hundredGigE62 +Ethernet248 249,250,251,252 hundredGigE63 +Ethernet252 241,242,243,244 hundredGigE64 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/sai.profile b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/sai.profile new file mode 100644 index 000000000000..dca8c2f68c04 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/th2-qfx5210-64x100G.config.bcm diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm new file mode 100644 index 000000000000..5c03be736650 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/Juniper-QFX5210-64C/th2-qfx5210-64x100G.config.bcm @@ -0,0 +1,875 @@ +# Broadcom Tomahawk SDK configuration +os=unix +schan_intr_enable=0 +l2_mem_entries=40960 +l2xmsg_mode=1 +l3_mem_entries=40960 +parity_correction=0 +parity_enable=0 +mmu_lossless=1 + +pbmp_xport_xe=0x1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff +pbmp_oversubscribe=0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + +# platform specific setting +arl_clean_timeout_usec=15000000 +asf_mem_profile=2 +bcm_num_cos=8 +bcm_stat_flags=1 +bcm_stat_jumbo=9236 +cdma_timeout_usec=15000000 +dma_desc_timeout_usec=15000000 +ipv6_lpm_128b_enable=1 +l3_alpm_enable=2 +lpm_scaling_enable=0 +max_vp_lags=0 +miim_intr_enable=0 +module_64ports=1 +oversubscribe_mode=1 + +#add loopback port +# port 33 is the first loopback port +portmap_33=260:10 +# port 66 is the first management port +portmap_66=257:10 +# port 67 is the second loopback port +portmap_67=261:10 +# port 100 is the second management port +portmap_100=259:10 +# port 101 is the third loopback port +portmap_101=262:10 +# port 135 is the fourth loopback port +portmap_135=263:10 + +#Port0 +#FC18 +portmap_36=73:100 +phy_chain_rx_lane_map_physical{73.0}=0x3210 +phy_chain_tx_lane_map_physical{73.0}=0x3021 +phy_chain_rx_polarity_flip_physical{73.0}=0x0 +phy_chain_rx_polarity_flip_physical{74.0}=0x0 +phy_chain_rx_polarity_flip_physical{75.0}=0x0 +phy_chain_rx_polarity_flip_physical{76.0}=0x1 +phy_chain_tx_polarity_flip_physical{73.0}=0x0 +phy_chain_tx_polarity_flip_physical{74.0}=0x0 +phy_chain_tx_polarity_flip_physical{75.0}=0x1 +phy_chain_tx_polarity_flip_physical{76.0}=0x0 +#Port1 +#FC16 +portmap_34=65:100 +phy_chain_rx_lane_map_physical{65.0}=0x3210 +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_rx_polarity_flip_physical{65.0}=0x0 +phy_chain_rx_polarity_flip_physical{66.0}=0x0 +phy_chain_rx_polarity_flip_physical{67.0}=0x0 +phy_chain_rx_polarity_flip_physical{68.0}=0x0 +phy_chain_tx_polarity_flip_physical{65.0}=0x1 +phy_chain_tx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x0 +phy_chain_tx_polarity_flip_physical{68.0}=0x0 +#Port2 +#FC20 +portmap_38=81:100 +phy_chain_rx_lane_map_physical{81.0}=0x1230 +phy_chain_tx_lane_map_physical{81.0}=0x1032 +phy_chain_rx_polarity_flip_physical{81.0}=0x1 +phy_chain_rx_polarity_flip_physical{82.0}=0x0 +phy_chain_rx_polarity_flip_physical{83.0}=0x1 +phy_chain_rx_polarity_flip_physical{84.0}=0x0 +phy_chain_tx_polarity_flip_physical{81.0}=0x1 +phy_chain_tx_polarity_flip_physical{82.0}=0x1 +phy_chain_tx_polarity_flip_physical{83.0}=0x1 +phy_chain_tx_polarity_flip_physical{84.0}=0x0 +#Port3 +#FC22 +portmap_40=89:100 +phy_chain_rx_lane_map_physical{89.0}=0x0132 +phy_chain_tx_lane_map_physical{89.0}=0x1203 +phy_chain_rx_polarity_flip_physical{89.0}=0x1 +phy_chain_rx_polarity_flip_physical{90.0}=0x0 +phy_chain_rx_polarity_flip_physical{91.0}=0x0 +phy_chain_rx_polarity_flip_physical{92.0}=0x1 +phy_chain_tx_polarity_flip_physical{89.0}=0x1 +phy_chain_tx_polarity_flip_physical{90.0}=0x0 +phy_chain_tx_polarity_flip_physical{91.0}=0x1 +phy_chain_tx_polarity_flip_physical{92.0}=0x1 +#Port4 +#FC26 +portmap_44=105:100 +phy_chain_rx_lane_map_physical{105.0}=0x3210 +phy_chain_tx_lane_map_physical{105.0}=0x0231 +phy_chain_rx_polarity_flip_physical{105.0}=0x0 +phy_chain_rx_polarity_flip_physical{106.0}=0x0 +phy_chain_rx_polarity_flip_physical{107.0}=0x0 +phy_chain_rx_polarity_flip_physical{108.0}=0x1 +phy_chain_tx_polarity_flip_physical{105.0}=0x0 +phy_chain_tx_polarity_flip_physical{106.0}=0x1 +phy_chain_tx_polarity_flip_physical{107.0}=0x0 +phy_chain_tx_polarity_flip_physical{108.0}=0x1 +#Port5 +#FC24 +portmap_42=97:100 +phy_chain_rx_lane_map_physical{97.0}=0x0213 +phy_chain_tx_lane_map_physical{97.0}=0x3210 +phy_chain_rx_polarity_flip_physical{97.0}=0x1 +phy_chain_rx_polarity_flip_physical{98.0}=0x0 +phy_chain_rx_polarity_flip_physical{99.0}=0x0 +phy_chain_rx_polarity_flip_physical{100.0}=0x1 +phy_chain_tx_polarity_flip_physical{97.0}=0x1 +phy_chain_tx_polarity_flip_physical{98.0}=0x1 +phy_chain_tx_polarity_flip_physical{99.0}=0x0 +phy_chain_tx_polarity_flip_physical{100.0}=0x0 +#Port6 +#FC 28 +portmap_46=113:100 +phy_chain_rx_lane_map_physical{113.0}=0x3021 +phy_chain_tx_lane_map_physical{113.0}=0x0312 +phy_chain_rx_polarity_flip_physical{113.0}=0x0 +phy_chain_rx_polarity_flip_physical{114.0}=0x1 +phy_chain_rx_polarity_flip_physical{115.0}=0x1 +phy_chain_rx_polarity_flip_physical{116.0}=0x0 +phy_chain_tx_polarity_flip_physical{113.0}=0x1 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_tx_polarity_flip_physical{115.0}=0x0 +phy_chain_tx_polarity_flip_physical{116.0}=0x1 +#Port7 +#FC30 +portmap_48=121:100 +phy_chain_rx_lane_map_physical{121.0}=0x3021 +phy_chain_tx_lane_map_physical{121.0}=0x2130 +phy_chain_rx_polarity_flip_physical{121.0}=0x0 +phy_chain_rx_polarity_flip_physical{122.0}=0x1 +phy_chain_rx_polarity_flip_physical{123.0}=0x1 +phy_chain_rx_polarity_flip_physical{124.0}=0x0 +phy_chain_tx_polarity_flip_physical{121.0}=0x1 +phy_chain_tx_polarity_flip_physical{122.0}=0x1 +phy_chain_tx_polarity_flip_physical{123.0}=0x1 +phy_chain_tx_polarity_flip_physical{124.0}=0x0 +#Port8 +#FC10 +portmap_11=41:100 +phy_chain_rx_lane_map_physical{41.0}=0x0132 +phy_chain_tx_lane_map_physical{41.0}=0x1302 +phy_chain_rx_polarity_flip_physical{41.0}=0x0 +phy_chain_rx_polarity_flip_physical{42.0}=0x0 +phy_chain_rx_polarity_flip_physical{43.0}=0x0 +phy_chain_rx_polarity_flip_physical{44.0}=0x0 +phy_chain_tx_polarity_flip_physical{41.0}=0x1 +phy_chain_tx_polarity_flip_physical{42.0}=0x0 +phy_chain_tx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 +#Port9 +#FC8 +portmap_9=33:100 +phy_chain_rx_lane_map_physical{33.0}=0x2310 +phy_chain_tx_lane_map_physical{33.0}=0x0213 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_rx_polarity_flip_physical{36.0}=0x0 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_tx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 +#Port10 +#FC12 +portmap_13=49:100 +phy_chain_rx_lane_map_physical{49.0}=0x3210 +phy_chain_tx_lane_map_physical{49.0}=0x3102 +phy_chain_rx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x0 +phy_chain_rx_polarity_flip_physical{51.0}=0x1 +phy_chain_rx_polarity_flip_physical{52.0}=0x0 +phy_chain_tx_polarity_flip_physical{49.0}=0x1 +phy_chain_tx_polarity_flip_physical{50.0}=0x1 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x1 +#Port11 +#FC14 +portmap_15=57:100 +phy_chain_rx_lane_map_physical{57.0}=0x3210 +phy_chain_tx_lane_map_physical{57.0}=0x1302 +phy_chain_rx_polarity_flip_physical{57.0}=0x1 +phy_chain_rx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x1 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 +phy_chain_tx_polarity_flip_physical{57.0}=0x0 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_tx_polarity_flip_physical{59.0}=0x0 +phy_chain_tx_polarity_flip_physical{60.0}=0x1 +#Port12 +#FC34 +portmap_70=137:100 +phy_chain_rx_lane_map_physical{137.0}=0x3210 +phy_chain_tx_lane_map_physical{137.0}=0x0213 +phy_chain_rx_polarity_flip_physical{137.0}=0x0 +phy_chain_rx_polarity_flip_physical{138.0}=0x0 +phy_chain_rx_polarity_flip_physical{139.0}=0x1 +phy_chain_rx_polarity_flip_physical{140.0}=0x0 +phy_chain_tx_polarity_flip_physical{137.0}=0x1 +phy_chain_tx_polarity_flip_physical{138.0}=0x0 +phy_chain_tx_polarity_flip_physical{139.0}=0x0 +phy_chain_tx_polarity_flip_physical{140.0}=0x0 +#Port13 +#FC32 +portmap_68=129:100 +phy_chain_rx_lane_map_physical{129.0}=0x3021 +phy_chain_tx_lane_map_physical{129.0}=0x1203 +phy_chain_rx_polarity_flip_physical{129.0}=0x1 +phy_chain_rx_polarity_flip_physical{130.0}=0x0 +phy_chain_rx_polarity_flip_physical{131.0}=0x0 +phy_chain_rx_polarity_flip_physical{132.0}=0x0 +phy_chain_tx_polarity_flip_physical{129.0}=0x1 +phy_chain_tx_polarity_flip_physical{130.0}=0x1 +phy_chain_tx_polarity_flip_physical{131.0}=0x1 +phy_chain_tx_polarity_flip_physical{132.0}=0x1 +#Port14 +#FC36 +portmap_72=145:100 +phy_chain_rx_lane_map_physical{145.0}=0x0213 +phy_chain_tx_lane_map_physical{145.0}=0x2301 +phy_chain_rx_polarity_flip_physical{145.0}=0x1 +phy_chain_rx_polarity_flip_physical{146.0}=0x1 +phy_chain_rx_polarity_flip_physical{147.0}=0x0 +phy_chain_rx_polarity_flip_physical{148.0}=0x0 +phy_chain_tx_polarity_flip_physical{145.0}=0x0 +phy_chain_tx_polarity_flip_physical{146.0}=0x0 +phy_chain_tx_polarity_flip_physical{147.0}=0x0 +phy_chain_tx_polarity_flip_physical{148.0}=0x1 +#Port15 +#FC38 +portmap_74=153:100 +phy_chain_rx_lane_map_physical{153.0}=0x0213 +phy_chain_tx_lane_map_physical{153.0}=0x1302 +phy_chain_rx_polarity_flip_physical{153.0}=0x1 +phy_chain_rx_polarity_flip_physical{154.0}=0x0 +phy_chain_rx_polarity_flip_physical{155.0}=0x1 +phy_chain_rx_polarity_flip_physical{156.0}=0x1 +phy_chain_tx_polarity_flip_physical{153.0}=0x0 +phy_chain_tx_polarity_flip_physical{154.0}=0x1 +phy_chain_tx_polarity_flip_physical{155.0}=0x0 +phy_chain_tx_polarity_flip_physical{156.0}=0x0 +#Port16 +#FC43 +portmap_79=173:100 +phy_chain_rx_lane_map_physical{173.0}=0x1032 +phy_chain_tx_lane_map_physical{173.0}=0x1203 +phy_chain_rx_polarity_flip_physical{173.0}=0x0 +phy_chain_rx_polarity_flip_physical{174.0}=0x0 +phy_chain_rx_polarity_flip_physical{175.0}=0x0 +phy_chain_rx_polarity_flip_physical{176.0}=0x0 +phy_chain_tx_polarity_flip_physical{173.0}=0x1 +phy_chain_tx_polarity_flip_physical{174.0}=0x1 +phy_chain_tx_polarity_flip_physical{175.0}=0x0 +phy_chain_tx_polarity_flip_physical{176.0}=0x1 +#Port17 +#FC41 +portmap_77=165:100 +phy_chain_rx_lane_map_physical{165.0}=0x1230 +phy_chain_tx_lane_map_physical{165.0}=0x2130 +phy_chain_rx_polarity_flip_physical{165.0}=0x1 +phy_chain_rx_polarity_flip_physical{166.0}=0x0 +phy_chain_rx_polarity_flip_physical{167.0}=0x1 +phy_chain_rx_polarity_flip_physical{168.0}=0x1 +phy_chain_tx_polarity_flip_physical{165.0}=0x1 +phy_chain_tx_polarity_flip_physical{166.0}=0x0 +phy_chain_tx_polarity_flip_physical{167.0}=0x1 +phy_chain_tx_polarity_flip_physical{168.0}=0x0 +#Port18 +#FC45 +portmap_81=181:100 +phy_chain_rx_lane_map_physical{181.0}=0x0312 +phy_chain_tx_lane_map_physical{181.0}=0x3120 +phy_chain_rx_polarity_flip_physical{181.0}=0x0 +phy_chain_rx_polarity_flip_physical{182.0}=0x1 +phy_chain_rx_polarity_flip_physical{183.0}=0x1 +phy_chain_rx_polarity_flip_physical{184.0}=0x0 +phy_chain_tx_polarity_flip_physical{181.0}=0x0 +phy_chain_tx_polarity_flip_physical{182.0}=0x0 +phy_chain_tx_polarity_flip_physical{183.0}=0x1 +phy_chain_tx_polarity_flip_physical{184.0}=0x0 +#Port19 +#FC47 +portmap_83=189:100 +phy_chain_rx_lane_map_physical{189.0}=0x0132 +phy_chain_tx_lane_map_physical{189.0}=0x3210 +phy_chain_rx_polarity_flip_physical{189.0}=0x0 +phy_chain_rx_polarity_flip_physical{190.0}=0x1 +phy_chain_rx_polarity_flip_physical{191.0}=0x1 +phy_chain_rx_polarity_flip_physical{192.0}=0x1 +phy_chain_tx_polarity_flip_physical{189.0}=0x1 +phy_chain_tx_polarity_flip_physical{190.0}=0x0 +phy_chain_tx_polarity_flip_physical{191.0}=0x0 +phy_chain_tx_polarity_flip_physical{192.0}=0x0 +#Port20 +#FC3 +portmap_4=13:100 +phy_chain_rx_lane_map_physical{13.0}=0x3120 +phy_chain_tx_lane_map_physical{13.0}=0x3210 +phy_chain_rx_polarity_flip_physical{13.0}=0x1 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x1 +phy_chain_rx_polarity_flip_physical{16.0}=0x1 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_tx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_tx_polarity_flip_physical{16.0}=0x1 +#Port21 +#FC1 +portmap_2=5:100 +phy_chain_rx_lane_map_physical{5.0}=0x0213 +phy_chain_tx_lane_map_physical{5.0}=0x0321 +phy_chain_rx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_rx_polarity_flip_physical{7.0}=0x1 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{5.0}=0x1 +phy_chain_tx_polarity_flip_physical{6.0}=0x1 +phy_chain_tx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x1 +#Port22 +#FC7 +portmap_8=29:100 +phy_chain_rx_lane_map_physical{29.0}=0x3021 +phy_chain_tx_lane_map_physical{29.0}=0x2130 +phy_chain_rx_polarity_flip_physical{29.0}=0x1 +phy_chain_rx_polarity_flip_physical{30.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x1 +phy_chain_tx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x0 +#Port23 +#FC5 +portmap_6=21:100 +phy_chain_rx_lane_map_physical{21.0}=0x0321 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_rx_polarity_flip_physical{21.0}=0x1 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x1 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x1 +phy_chain_tx_polarity_flip_physical{23.0}=0x1 +phy_chain_tx_polarity_flip_physical{24.0}=0x1 +#Port24 +#FC51 +portmap_105=205:100 +phy_chain_rx_lane_map_physical{205.0}=0x0132 +phy_chain_tx_lane_map_physical{205.0}=0x1230 +phy_chain_rx_polarity_flip_physical{205.0}=0x1 +phy_chain_rx_polarity_flip_physical{206.0}=0x1 +phy_chain_rx_polarity_flip_physical{207.0}=0x1 +phy_chain_rx_polarity_flip_physical{208.0}=0x0 +phy_chain_tx_polarity_flip_physical{205.0}=0x0 +phy_chain_tx_polarity_flip_physical{206.0}=0x1 +phy_chain_tx_polarity_flip_physical{207.0}=0x0 +phy_chain_tx_polarity_flip_physical{208.0}=0x1 +#Port25 +#FC49 +portmap_103=197:100 +phy_chain_rx_lane_map_physical{197.0}=0x1230 +phy_chain_tx_lane_map_physical{197.0}=0x3021 +phy_chain_rx_polarity_flip_physical{197.0}=0x0 +phy_chain_rx_polarity_flip_physical{198.0}=0x0 +phy_chain_rx_polarity_flip_physical{199.0}=0x0 +phy_chain_rx_polarity_flip_physical{200.0}=0x0 +phy_chain_tx_polarity_flip_physical{197.0}=0x1 +phy_chain_tx_polarity_flip_physical{198.0}=0x0 +phy_chain_tx_polarity_flip_physical{199.0}=0x1 +phy_chain_tx_polarity_flip_physical{200.0}=0x0 +#Port26 +#FC53 +portmap_107=213:100 +phy_chain_rx_lane_map_physical{213.0}=0x3210 +phy_chain_tx_lane_map_physical{213.0}=0x1230 +phy_chain_rx_polarity_flip_physical{213.0}=0x0 +phy_chain_rx_polarity_flip_physical{214.0}=0x1 +phy_chain_rx_polarity_flip_physical{215.0}=0x0 +phy_chain_rx_polarity_flip_physical{216.0}=0x1 +phy_chain_tx_polarity_flip_physical{213.0}=0x0 +phy_chain_tx_polarity_flip_physical{214.0}=0x0 +phy_chain_tx_polarity_flip_physical{215.0}=0x0 +phy_chain_tx_polarity_flip_physical{216.0}=0x1 +#Port27 +#FC55 +portmap_109=221:100 +phy_chain_rx_lane_map_physical{221.0}=0x3210 +phy_chain_tx_lane_map_physical{221.0}=0x3210 +phy_chain_rx_polarity_flip_physical{221.0}=0x1 +phy_chain_rx_polarity_flip_physical{222.0}=0x1 +phy_chain_rx_polarity_flip_physical{223.0}=0x0 +phy_chain_rx_polarity_flip_physical{224.0}=0x0 +phy_chain_tx_polarity_flip_physical{221.0}=0x0 +phy_chain_tx_polarity_flip_physical{222.0}=0x0 +phy_chain_tx_polarity_flip_physical{223.0}=0x0 +phy_chain_tx_polarity_flip_physical{224.0}=0x0 +#Port28 +#FC57 +portmap_111=229:100 +phy_chain_rx_lane_map_physical{229.0}=0x2301 +phy_chain_tx_lane_map_physical{229.0}=0x3210 +phy_chain_rx_polarity_flip_physical{229.0}=0x1 +phy_chain_rx_polarity_flip_physical{230.0}=0x1 +phy_chain_rx_polarity_flip_physical{231.0}=0x0 +phy_chain_rx_polarity_flip_physical{232.0}=0x1 +phy_chain_tx_polarity_flip_physical{229.0}=0x0 +phy_chain_tx_polarity_flip_physical{230.0}=0x1 +phy_chain_tx_polarity_flip_physical{231.0}=0x0 +phy_chain_tx_polarity_flip_physical{232.0}=0x0 +#Port29 +#FC59 +portmap_113=237:100 +phy_chain_rx_lane_map_physical{237.0}=0x0123 +phy_chain_tx_lane_map_physical{237.0}=0x3210 +phy_chain_rx_polarity_flip_physical{237.0}=0x1 +phy_chain_rx_polarity_flip_physical{238.0}=0x0 +phy_chain_rx_polarity_flip_physical{239.0}=0x1 +phy_chain_rx_polarity_flip_physical{240.0}=0x1 +phy_chain_tx_polarity_flip_physical{237.0}=0x1 +phy_chain_tx_polarity_flip_physical{238.0}=0x1 +phy_chain_tx_polarity_flip_physical{239.0}=0x0 +phy_chain_tx_polarity_flip_physical{240.0}=0x0 +#Port30 +#FC61 +portmap_115=245:100 +phy_chain_rx_lane_map_physical{245.0}=0x0213 +phy_chain_tx_lane_map_physical{245.0}=0x3210 +phy_chain_rx_polarity_flip_physical{245.0}=0x0 +phy_chain_rx_polarity_flip_physical{246.0}=0x0 +phy_chain_rx_polarity_flip_physical{247.0}=0x1 +phy_chain_rx_polarity_flip_physical{248.0}=0x1 +phy_chain_tx_polarity_flip_physical{245.0}=0x1 +phy_chain_tx_polarity_flip_physical{246.0}=0x0 +phy_chain_tx_polarity_flip_physical{247.0}=0x1 +phy_chain_tx_polarity_flip_physical{248.0}=0x0 +#Port31 +#FC63 +portmap_117=253:100 +phy_chain_rx_lane_map_physical{253.0}=0x0213 +phy_chain_tx_lane_map_physical{253.0}=0x0312 +phy_chain_rx_polarity_flip_physical{253.0}=0x0 +phy_chain_rx_polarity_flip_physical{254.0}=0x0 +phy_chain_rx_polarity_flip_physical{255.0}=0x0 +phy_chain_rx_polarity_flip_physical{256.0}=0x1 +phy_chain_tx_polarity_flip_physical{253.0}=0x0 +phy_chain_tx_polarity_flip_physical{254.0}=0x1 +phy_chain_tx_polarity_flip_physical{255.0}=0x0 +phy_chain_tx_polarity_flip_physical{256.0}=0x0 +#Port32 +#FC17 +portmap_35=69:100 +phy_chain_rx_lane_map_physical{69.0}=0x1032 +phy_chain_tx_lane_map_physical{69.0}=0x3102 +phy_chain_rx_polarity_flip_physical{69.0}=0x1 +phy_chain_rx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{71.0}=0x0 +phy_chain_rx_polarity_flip_physical{72.0}=0x1 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_tx_polarity_flip_physical{71.0}=0x1 +phy_chain_tx_polarity_flip_physical{72.0}=0x1 +#Port33 +#FC19 +portmap_37=77:100 +phy_chain_rx_lane_map_physical{77.0}=0x1230 +phy_chain_tx_lane_map_physical{77.0}=0x3021 +phy_chain_rx_polarity_flip_physical{77.0}=0x1 +phy_chain_rx_polarity_flip_physical{78.0}=0x0 +phy_chain_rx_polarity_flip_physical{79.0}=0x1 +phy_chain_rx_polarity_flip_physical{80.0}=0x0 +phy_chain_tx_polarity_flip_physical{77.0}=0x0 +phy_chain_tx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x1 +phy_chain_tx_polarity_flip_physical{80.0}=0x0 +#Port34 +#FC23 +portmap_41=93:100 +phy_chain_rx_lane_map_physical{93.0}=0x1032 +phy_chain_tx_lane_map_physical{93.0}=0x0231 +phy_chain_rx_polarity_flip_physical{93.0}=0x1 +phy_chain_rx_polarity_flip_physical{94.0}=0x1 +phy_chain_rx_polarity_flip_physical{95.0}=0x1 +phy_chain_rx_polarity_flip_physical{96.0}=0x1 +phy_chain_tx_polarity_flip_physical{93.0}=0x0 +phy_chain_tx_polarity_flip_physical{94.0}=0x1 +phy_chain_tx_polarity_flip_physical{95.0}=0x1 +phy_chain_tx_polarity_flip_physical{96.0}=0x1 +#Port35 +#FC21 +portmap_39=85:100 +phy_chain_rx_lane_map_physical{85.0}=0x0312 +phy_chain_tx_lane_map_physical{85.0}=0x1230 +phy_chain_rx_polarity_flip_physical{85.0}=0x0 +phy_chain_rx_polarity_flip_physical{86.0}=0x0 +phy_chain_rx_polarity_flip_physical{87.0}=0x0 +phy_chain_rx_polarity_flip_physical{88.0}=0x1 +phy_chain_tx_polarity_flip_physical{85.0}=0x1 +phy_chain_tx_polarity_flip_physical{86.0}=0x0 +phy_chain_tx_polarity_flip_physical{87.0}=0x1 +phy_chain_tx_polarity_flip_physical{88.0}=0x0 +#Port36 +#FC25 +portmap_43=101:100 +phy_chain_rx_lane_map_physical{101.0}=0x1302 +phy_chain_tx_lane_map_physical{101.0}=0x0213 +phy_chain_rx_polarity_flip_physical{101.0}=0x1 +phy_chain_rx_polarity_flip_physical{102.0}=0x0 +phy_chain_rx_polarity_flip_physical{103.0}=0x0 +phy_chain_rx_polarity_flip_physical{104.0}=0x0 +phy_chain_tx_polarity_flip_physical{101.0}=0x0 +phy_chain_tx_polarity_flip_physical{102.0}=0x1 +phy_chain_tx_polarity_flip_physical{103.0}=0x0 +phy_chain_tx_polarity_flip_physical{104.0}=0x1 +#Port37 +#FC27 +portmap_45=109:100 +phy_chain_rx_lane_map_physical{109.0}=0x0213 +phy_chain_tx_lane_map_physical{109.0}=0x1032 +phy_chain_rx_polarity_flip_physical{109.0}=0x1 +phy_chain_rx_polarity_flip_physical{110.0}=0x1 +phy_chain_rx_polarity_flip_physical{111.0}=0x0 +phy_chain_rx_polarity_flip_physical{112.0}=0x0 +phy_chain_tx_polarity_flip_physical{109.0}=0x0 +phy_chain_tx_polarity_flip_physical{110.0}=0x1 +phy_chain_tx_polarity_flip_physical{111.0}=0x1 +phy_chain_tx_polarity_flip_physical{112.0}=0x1 +#Port38 +#FC31 +portmap_49=125:100 +phy_chain_rx_lane_map_physical{125.0}=0x2130 +phy_chain_tx_lane_map_physical{125.0}=0x1203 +phy_chain_rx_polarity_flip_physical{125.0}=0x0 +phy_chain_rx_polarity_flip_physical{126.0}=0x0 +phy_chain_rx_polarity_flip_physical{127.0}=0x1 +phy_chain_rx_polarity_flip_physical{128.0}=0x1 +phy_chain_tx_polarity_flip_physical{125.0}=0x0 +phy_chain_tx_polarity_flip_physical{126.0}=0x1 +phy_chain_tx_polarity_flip_physical{127.0}=0x1 +phy_chain_tx_polarity_flip_physical{128.0}=0x1 +#Port39 +#FC29 +portmap_47=117:100 +phy_chain_rx_lane_map_physical{117.0}=0x3102 +phy_chain_tx_lane_map_physical{117.0}=0x2310 +phy_chain_rx_polarity_flip_physical{117.0}=0x1 +phy_chain_rx_polarity_flip_physical{118.0}=0x0 +phy_chain_rx_polarity_flip_physical{119.0}=0x1 +phy_chain_rx_polarity_flip_physical{120.0}=0x0 +phy_chain_tx_polarity_flip_physical{117.0}=0x1 +phy_chain_tx_polarity_flip_physical{118.0}=0x0 +phy_chain_tx_polarity_flip_physical{119.0}=0x1 +phy_chain_tx_polarity_flip_physical{120.0}=0x0 +#Port40 +#FC9 +portmap_10=37:100 +phy_chain_rx_lane_map_physical{37.0}=0x3210 +phy_chain_tx_lane_map_physical{37.0}=0x1302 +phy_chain_rx_polarity_flip_physical{37.0}=0x1 +phy_chain_rx_polarity_flip_physical{38.0}=0x0 +phy_chain_rx_polarity_flip_physical{39.0}=0x0 +phy_chain_rx_polarity_flip_physical{40.0}=0x0 +phy_chain_tx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x0 +phy_chain_tx_polarity_flip_physical{39.0}=0x1 +phy_chain_tx_polarity_flip_physical{40.0}=0x1 +#Port41 +#FC11 +portmap_12=45:100 +phy_chain_rx_lane_map_physical{45.0}=0x3210 +phy_chain_tx_lane_map_physical{45.0}=0x0123 +phy_chain_rx_polarity_flip_physical{45.0}=0x0 +phy_chain_rx_polarity_flip_physical{46.0}=0x0 +phy_chain_rx_polarity_flip_physical{47.0}=0x0 +phy_chain_rx_polarity_flip_physical{48.0}=0x0 +phy_chain_tx_polarity_flip_physical{45.0}=0x0 +phy_chain_tx_polarity_flip_physical{46.0}=0x1 +phy_chain_tx_polarity_flip_physical{47.0}=0x0 +phy_chain_tx_polarity_flip_physical{48.0}=0x1 +#Port42 +#FC15 +portmap_16=61:100 +phy_chain_rx_lane_map_physical{61.0}=0x3210 +phy_chain_tx_lane_map_physical{61.0}=0x1230 +phy_chain_rx_polarity_flip_physical{61.0}=0x0 +phy_chain_rx_polarity_flip_physical{62.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x0 +phy_chain_rx_polarity_flip_physical{64.0}=0x0 +phy_chain_tx_polarity_flip_physical{61.0}=0x0 +phy_chain_tx_polarity_flip_physical{62.0}=0x1 +phy_chain_tx_polarity_flip_physical{63.0}=0x1 +phy_chain_tx_polarity_flip_physical{64.0}=0x0 +#Port43 +#FC13 +portmap_14=53:100 +phy_chain_rx_lane_map_physical{53.0}=0x3210 +phy_chain_tx_lane_map_physical{53.0}=0x3210 +phy_chain_rx_polarity_flip_physical{53.0}=0x0 +phy_chain_rx_polarity_flip_physical{54.0}=0x0 +phy_chain_rx_polarity_flip_physical{55.0}=0x1 +phy_chain_rx_polarity_flip_physical{56.0}=0x0 +phy_chain_tx_polarity_flip_physical{53.0}=0x1 +phy_chain_tx_polarity_flip_physical{54.0}=0x1 +phy_chain_tx_polarity_flip_physical{55.0}=0x1 +phy_chain_tx_polarity_flip_physical{56.0}=0x0 +#Port44 +#FC33 +portmap_69=133:100 +phy_chain_rx_lane_map_physical{133.0}=0x0312 +phy_chain_tx_lane_map_physical{133.0}=0x2310 +phy_chain_rx_polarity_flip_physical{133.0}=0x0 +phy_chain_rx_polarity_flip_physical{134.0}=0x0 +phy_chain_rx_polarity_flip_physical{135.0}=0x1 +phy_chain_rx_polarity_flip_physical{136.0}=0x0 +phy_chain_tx_polarity_flip_physical{133.0}=0x0 +phy_chain_tx_polarity_flip_physical{134.0}=0x1 +phy_chain_tx_polarity_flip_physical{135.0}=0x0 +phy_chain_tx_polarity_flip_physical{136.0}=0x1 +#Port45 +#FC35 +portmap_71=141:100 +phy_chain_rx_lane_map_physical{141.0}=0x3012 +phy_chain_tx_lane_map_physical{141.0}=0x0123 +phy_chain_rx_polarity_flip_physical{141.0}=0x1 +phy_chain_rx_polarity_flip_physical{142.0}=0x0 +phy_chain_rx_polarity_flip_physical{143.0}=0x1 +phy_chain_rx_polarity_flip_physical{144.0}=0x0 +phy_chain_tx_polarity_flip_physical{141.0}=0x1 +phy_chain_tx_polarity_flip_physical{142.0}=0x1 +phy_chain_tx_polarity_flip_physical{143.0}=0x0 +phy_chain_tx_polarity_flip_physical{144.0}=0x0 +#Port46 +#FC39 +portmap_75=157:100 +phy_chain_rx_lane_map_physical{157.0}=0x2103 +phy_chain_tx_lane_map_physical{157.0}=0x0231 +phy_chain_rx_polarity_flip_physical{157.0}=0x0 +phy_chain_rx_polarity_flip_physical{158.0}=0x0 +phy_chain_rx_polarity_flip_physical{159.0}=0x1 +phy_chain_rx_polarity_flip_physical{160.0}=0x0 +phy_chain_tx_polarity_flip_physical{157.0}=0x0 +phy_chain_tx_polarity_flip_physical{158.0}=0x1 +phy_chain_tx_polarity_flip_physical{159.0}=0x0 +phy_chain_tx_polarity_flip_physical{160.0}=0x0 +#Port47 +#FC37 +portmap_73=149:100 +phy_chain_rx_lane_map_physical{149.0}=0x3120 +phy_chain_tx_lane_map_physical{149.0}=0x1023 +phy_chain_rx_polarity_flip_physical{149.0}=0x0 +phy_chain_rx_polarity_flip_physical{150.0}=0x1 +phy_chain_rx_polarity_flip_physical{151.0}=0x0 +phy_chain_rx_polarity_flip_physical{152.0}=0x0 +phy_chain_tx_polarity_flip_physical{149.0}=0x1 +phy_chain_tx_polarity_flip_physical{150.0}=0x0 +phy_chain_tx_polarity_flip_physical{151.0}=0x0 +phy_chain_tx_polarity_flip_physical{152.0}=0x1 +#Port48 +#FC40 +portmap_76=161:100 +phy_chain_rx_lane_map_physical{161.0}=0x3012 +phy_chain_tx_lane_map_physical{161.0}=0x1023 +phy_chain_rx_polarity_flip_physical{161.0}=0x1 +phy_chain_rx_polarity_flip_physical{162.0}=0x1 +phy_chain_rx_polarity_flip_physical{163.0}=0x0 +phy_chain_rx_polarity_flip_physical{164.0}=0x0 +phy_chain_tx_polarity_flip_physical{161.0}=0x0 +phy_chain_tx_polarity_flip_physical{162.0}=0x1 +phy_chain_tx_polarity_flip_physical{163.0}=0x0 +phy_chain_tx_polarity_flip_physical{164.0}=0x0 +#Port49 +#FC42 +portmap_78=169:100 +phy_chain_rx_lane_map_physical{169.0}=0x3210 +phy_chain_tx_lane_map_physical{169.0}=0x2031 +phy_chain_rx_polarity_flip_physical{169.0}=0x0 +phy_chain_rx_polarity_flip_physical{170.0}=0x1 +phy_chain_rx_polarity_flip_physical{171.0}=0x0 +phy_chain_rx_polarity_flip_physical{172.0}=0x0 +phy_chain_tx_polarity_flip_physical{169.0}=0x1 +phy_chain_tx_polarity_flip_physical{170.0}=0x0 +phy_chain_tx_polarity_flip_physical{171.0}=0x0 +phy_chain_tx_polarity_flip_physical{172.0}=0x0 +#Port50 +#FC46 +portmap_82=185:100 +phy_chain_rx_lane_map_physical{185.0}=0x2310 +phy_chain_tx_lane_map_physical{185.0}=0x3021 +phy_chain_rx_polarity_flip_physical{185.0}=0x1 +phy_chain_rx_polarity_flip_physical{186.0}=0x0 +phy_chain_rx_polarity_flip_physical{187.0}=0x1 +phy_chain_rx_polarity_flip_physical{188.0}=0x0 +phy_chain_tx_polarity_flip_physical{185.0}=0x0 +phy_chain_tx_polarity_flip_physical{186.0}=0x1 +phy_chain_tx_polarity_flip_physical{187.0}=0x0 +phy_chain_tx_polarity_flip_physical{188.0}=0x0 +#Port51 +#FC44 +portmap_80=177:100 +phy_chain_rx_lane_map_physical{177.0}=0x1032 +phy_chain_tx_lane_map_physical{177.0}=0x2301 +phy_chain_rx_polarity_flip_physical{177.0}=0x1 +phy_chain_rx_polarity_flip_physical{178.0}=0x1 +phy_chain_rx_polarity_flip_physical{179.0}=0x0 +phy_chain_rx_polarity_flip_physical{180.0}=0x1 +phy_chain_tx_polarity_flip_physical{177.0}=0x1 +phy_chain_tx_polarity_flip_physical{178.0}=0x1 +phy_chain_tx_polarity_flip_physical{179.0}=0x1 +phy_chain_tx_polarity_flip_physical{180.0}=0x0 +#Port52 +#FC6 +portmap_7=25:100 +phy_chain_rx_lane_map_physical{25.0}=0x3102 +phy_chain_tx_lane_map_physical{25.0}=0x0132 +phy_chain_rx_polarity_flip_physical{25.0}=0x0 +phy_chain_rx_polarity_flip_physical{26.0}=0x0 +phy_chain_rx_polarity_flip_physical{27.0}=0x1 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 +phy_chain_tx_polarity_flip_physical{25.0}=0x0 +phy_chain_tx_polarity_flip_physical{26.0}=0x1 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_tx_polarity_flip_physical{28.0}=0x1 +#Port53 +#FC4 +portmap_5=17:100 +phy_chain_rx_lane_map_physical{17.0}=0x3120 +phy_chain_tx_lane_map_physical{17.0}=0x3021 +phy_chain_rx_polarity_flip_physical{17.0}=0x0 +phy_chain_rx_polarity_flip_physical{18.0}=0x1 +phy_chain_rx_polarity_flip_physical{19.0}=0x0 +phy_chain_rx_polarity_flip_physical{20.0}=0x0 +phy_chain_tx_polarity_flip_physical{17.0}=0x0 +phy_chain_tx_polarity_flip_physical{18.0}=0x0 +phy_chain_tx_polarity_flip_physical{19.0}=0x1 +phy_chain_tx_polarity_flip_physical{20.0}=0x0 +#Port54 +#FC0 +portmap_1=1:100 +phy_chain_rx_lane_map_physical{1.0}=0x2130 +phy_chain_tx_lane_map_physical{1.0}=0x1203 +phy_chain_rx_polarity_flip_physical{1.0}=0x1 +phy_chain_rx_polarity_flip_physical{2.0}=0x0 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_tx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x1 +#Port55 +#FC2 +portmap_3=9:100 +phy_chain_rx_lane_map_physical{9.0}=0x1203 +phy_chain_tx_lane_map_physical{9.0}=0x1230 +phy_chain_rx_polarity_flip_physical{9.0}=0x0 +phy_chain_rx_polarity_flip_physical{10.0}=0x1 +phy_chain_rx_polarity_flip_physical{11.0}=0x0 +phy_chain_rx_polarity_flip_physical{12.0}=0x0 +phy_chain_tx_polarity_flip_physical{9.0}=0x1 +phy_chain_tx_polarity_flip_physical{10.0}=0x0 +phy_chain_tx_polarity_flip_physical{11.0}=0x1 +phy_chain_tx_polarity_flip_physical{12.0}=0x0 +#Port56 +#FC48 +portmap_102=193:100 +phy_chain_rx_lane_map_physical{193.0}=0x2103 +phy_chain_tx_lane_map_physical{193.0}=0x1230 +phy_chain_rx_polarity_flip_physical{193.0}=0x0 +phy_chain_rx_polarity_flip_physical{194.0}=0x1 +phy_chain_rx_polarity_flip_physical{195.0}=0x0 +phy_chain_rx_polarity_flip_physical{196.0}=0x1 +phy_chain_tx_polarity_flip_physical{193.0}=0x0 +phy_chain_tx_polarity_flip_physical{194.0}=0x0 +phy_chain_tx_polarity_flip_physical{195.0}=0x1 +phy_chain_tx_polarity_flip_physical{196.0}=0x0 +#Port57 +#FC50 +portmap_104=201:100 +phy_chain_rx_lane_map_physical{201.0}=0x0321 +phy_chain_tx_lane_map_physical{201.0}=0x3021 +phy_chain_rx_polarity_flip_physical{201.0}=0x0 +phy_chain_rx_polarity_flip_physical{202.0}=0x0 +phy_chain_rx_polarity_flip_physical{203.0}=0x1 +phy_chain_rx_polarity_flip_physical{204.0}=0x0 +phy_chain_tx_polarity_flip_physical{201.0}=0x1 +phy_chain_tx_polarity_flip_physical{202.0}=0x1 +phy_chain_tx_polarity_flip_physical{203.0}=0x0 +phy_chain_tx_polarity_flip_physical{204.0}=0x1 +#Port58 +#FC54 +portmap_108=217:100 +phy_chain_rx_lane_map_physical{217.0}=0x1203 +phy_chain_tx_lane_map_physical{217.0}=0x2031 +phy_chain_rx_polarity_flip_physical{217.0}=0x1 +phy_chain_rx_polarity_flip_physical{218.0}=0x0 +phy_chain_rx_polarity_flip_physical{219.0}=0x1 +phy_chain_rx_polarity_flip_physical{220.0}=0x1 +phy_chain_tx_polarity_flip_physical{217.0}=0x1 +phy_chain_tx_polarity_flip_physical{218.0}=0x0 +phy_chain_tx_polarity_flip_physical{219.0}=0x1 +phy_chain_tx_polarity_flip_physical{220.0}=0x0 +#Port59 +#FC52 +portmap_106=209:100 +phy_chain_rx_lane_map_physical{209.0}=0x0321 +phy_chain_tx_lane_map_physical{209.0}=0x3102 +phy_chain_rx_polarity_flip_physical{209.0}=0x0 +phy_chain_rx_polarity_flip_physical{210.0}=0x0 +phy_chain_rx_polarity_flip_physical{211.0}=0x1 +phy_chain_rx_polarity_flip_physical{212.0}=0x0 +phy_chain_tx_polarity_flip_physical{209.0}=0x0 +phy_chain_tx_polarity_flip_physical{210.0}=0x0 +phy_chain_tx_polarity_flip_physical{211.0}=0x1 +phy_chain_tx_polarity_flip_physical{212.0}=0x0 +#Port60 +#FC56 +portmap_110=225:100 +phy_chain_rx_lane_map_physical{225.0}=0x2103 +phy_chain_tx_lane_map_physical{225.0}=0x2031 +phy_chain_rx_polarity_flip_physical{225.0}=0x0 +phy_chain_rx_polarity_flip_physical{226.0}=0x0 +phy_chain_rx_polarity_flip_physical{227.0}=0x1 +phy_chain_rx_polarity_flip_physical{228.0}=0x1 +phy_chain_tx_polarity_flip_physical{225.0}=0x1 +phy_chain_tx_polarity_flip_physical{226.0}=0x0 +phy_chain_tx_polarity_flip_physical{227.0}=0x1 +phy_chain_tx_polarity_flip_physical{228.0}=0x1 +#Port61 +#FC58 +portmap_112=233:100 +phy_chain_rx_lane_map_physical{233.0}=0x2130 +phy_chain_tx_lane_map_physical{233.0}=0x0312 +phy_chain_rx_polarity_flip_physical{233.0}=0x0 +phy_chain_rx_polarity_flip_physical{234.0}=0x1 +phy_chain_rx_polarity_flip_physical{235.0}=0x1 +phy_chain_rx_polarity_flip_physical{236.0}=0x0 +phy_chain_tx_polarity_flip_physical{233.0}=0x0 +phy_chain_tx_polarity_flip_physical{234.0}=0x0 +phy_chain_tx_polarity_flip_physical{235.0}=0x1 +phy_chain_tx_polarity_flip_physical{236.0}=0x0 +#Port62 +#FC62 +portmap_116=249:100 +phy_chain_rx_lane_map_physical{249.0}=0x1302 +phy_chain_tx_lane_map_physical{249.0}=0x1302 +phy_chain_rx_polarity_flip_physical{249.0}=0x0 +phy_chain_rx_polarity_flip_physical{250.0}=0x1 +phy_chain_rx_polarity_flip_physical{251.0}=0x0 +phy_chain_rx_polarity_flip_physical{252.0}=0x1 +phy_chain_tx_polarity_flip_physical{249.0}=0x1 +phy_chain_tx_polarity_flip_physical{250.0}=0x1 +phy_chain_tx_polarity_flip_physical{251.0}=0x1 +phy_chain_tx_polarity_flip_physical{252.0}=0x1 +#Port63 +#FC60 +portmap_114=241:100 +phy_chain_rx_lane_map_physical{241.0}=0x3012 +phy_chain_tx_lane_map_physical{241.0}=0x2301 +phy_chain_rx_polarity_flip_physical{241.0}=0x1 +phy_chain_rx_polarity_flip_physical{242.0}=0x1 +phy_chain_rx_polarity_flip_physical{243.0}=0x0 +phy_chain_rx_polarity_flip_physical{244.0}=0x1 +phy_chain_tx_polarity_flip_physical{241.0}=0x1 +phy_chain_tx_polarity_flip_physical{242.0}=0x0 +phy_chain_tx_polarity_flip_physical{243.0}=0x1 +phy_chain_tx_polarity_flip_physical{244.0}=0x0 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/default_sku b/device/juniper/x86_64-juniper_qfx5210-r0/default_sku new file mode 100644 index 000000000000..869e1625da46 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/default_sku @@ -0,0 +1 @@ +Juniper-QFX5210-64C t1 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/installer.conf b/device/juniper/x86_64-juniper_qfx5210-r0/installer.conf new file mode 100644 index 000000000000..5c03f5844baa --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/installer.conf @@ -0,0 +1,2 @@ +CONSOLE_SPEED=9600 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="tg3.short_preamble=1 tg3.bcm5718s_reset=1" diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/led_proc_init.soc b/device/juniper/x86_64-juniper_qfx5210-r0/led_proc_init.soc new file mode 100755 index 000000000000..75a36c6f9c68 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/led_proc_init.soc @@ -0,0 +1,155 @@ +m CMIC_LEDUP0_CLK_PARAMS REFRESH_CYCLE_PERIOD=0xc00000 +m CMIC_LEDUP1_CLK_PARAMS REFRESH_CYCLE_PERIOD=0xc00000 +m CMIC_LEDUP2_CLK_PARAMS REFRESH_CYCLE_PERIOD=0xc00000 +m CMIC_LEDUP3_CLK_PARAMS REFRESH_CYCLE_PERIOD=0xc00000 + +m CMIC_LEDUP0_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=63 REMAP_PORT_1=62 REMAP_PORT_2=61 REMAP_PORT_3=60 +m CMIC_LEDUP0_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=59 REMAP_PORT_5=58 REMAP_PORT_6=57 REMAP_PORT_7=56 +m CMIC_LEDUP0_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=55 REMAP_PORT_9=54 REMAP_PORT_10=53 REMAP_PORT_11=52 +m CMIC_LEDUP0_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=51 REMAP_PORT_13=50 REMAP_PORT_14=49 REMAP_PORT_15=48 +m CMIC_LEDUP0_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 REMAP_PORT_17=46 REMAP_PORT_18=45 REMAP_PORT_19=44 +m CMIC_LEDUP0_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 REMAP_PORT_21=42 REMAP_PORT_22=41 REMAP_PORT_23=40 +m CMIC_LEDUP0_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 REMAP_PORT_25=38 REMAP_PORT_26=37 REMAP_PORT_27=36 +m CMIC_LEDUP0_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 REMAP_PORT_29=34 REMAP_PORT_30=33 REMAP_PORT_31=32 +m CMIC_LEDUP0_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=31 REMAP_PORT_33=30 REMAP_PORT_34=29 REMAP_PORT_35=28 +m CMIC_LEDUP0_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=27 REMAP_PORT_37=26 REMAP_PORT_38=25 REMAP_PORT_39=24 +m CMIC_LEDUP0_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=23 REMAP_PORT_41=22 REMAP_PORT_42=21 REMAP_PORT_43=20 +m CMIC_LEDUP0_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=19 REMAP_PORT_45=18 REMAP_PORT_46=17 REMAP_PORT_47=16 +m CMIC_LEDUP0_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 REMAP_PORT_49=14 REMAP_PORT_50=13 REMAP_PORT_51=12 +m CMIC_LEDUP0_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 REMAP_PORT_53=10 REMAP_PORT_54=9 REMAP_PORT_55=8 +m CMIC_LEDUP0_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 REMAP_PORT_57=6 REMAP_PORT_58=5 REMAP_PORT_59=4 +m CMIC_LEDUP0_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 REMAP_PORT_61=2 REMAP_PORT_62=1 REMAP_PORT_63=0 + +m CMIC_LEDUP1_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=3 REMAP_PORT_1=2 REMAP_PORT_2=1 REMAP_PORT_3=0 +m CMIC_LEDUP1_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=7 REMAP_PORT_5=6 REMAP_PORT_6=5 REMAP_PORT_7=4 +m CMIC_LEDUP1_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=11 REMAP_PORT_9=10 REMAP_PORT_10=9 REMAP_PORT_11=8 +m CMIC_LEDUP1_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=15 REMAP_PORT_13=14 REMAP_PORT_14=13 REMAP_PORT_15=12 +m CMIC_LEDUP1_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=19 REMAP_PORT_17=18 REMAP_PORT_18=17 REMAP_PORT_19=16 +m CMIC_LEDUP1_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=23 REMAP_PORT_21=22 REMAP_PORT_22=21 REMAP_PORT_23=20 +m CMIC_LEDUP1_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=27 REMAP_PORT_25=26 REMAP_PORT_26=25 REMAP_PORT_27=24 +m CMIC_LEDUP1_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=31 REMAP_PORT_29=30 REMAP_PORT_30=29 REMAP_PORT_31=28 +m CMIC_LEDUP1_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=35 REMAP_PORT_33=34 REMAP_PORT_34=33 REMAP_PORT_35=32 +m CMIC_LEDUP1_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=39 REMAP_PORT_37=38 REMAP_PORT_38=37 REMAP_PORT_39=36 +m CMIC_LEDUP1_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=43 REMAP_PORT_41=42 REMAP_PORT_42=41 REMAP_PORT_43=40 +m CMIC_LEDUP1_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=47 REMAP_PORT_45=46 REMAP_PORT_46=45 REMAP_PORT_47=44 +m CMIC_LEDUP1_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=51 REMAP_PORT_49=50 REMAP_PORT_50=49 REMAP_PORT_51=48 +m CMIC_LEDUP1_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=55 REMAP_PORT_53=54 REMAP_PORT_54=53 REMAP_PORT_55=52 +m CMIC_LEDUP1_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=59 REMAP_PORT_57=58 REMAP_PORT_58=57 REMAP_PORT_59=56 +m CMIC_LEDUP1_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=63 REMAP_PORT_61=62 REMAP_PORT_62=61 REMAP_PORT_63=60 + +m CMIC_LEDUP2_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=63 REMAP_PORT_1=62 REMAP_PORT_2=61 REMAP_PORT_3=60 +m CMIC_LEDUP2_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=59 REMAP_PORT_5=58 REMAP_PORT_6=57 REMAP_PORT_7=56 +m CMIC_LEDUP2_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=55 REMAP_PORT_9=54 REMAP_PORT_10=53 REMAP_PORT_11=52 +m CMIC_LEDUP2_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=51 REMAP_PORT_13=50 REMAP_PORT_14=49 REMAP_PORT_15=48 +m CMIC_LEDUP2_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=47 REMAP_PORT_17=46 REMAP_PORT_18=45 REMAP_PORT_19=44 +m CMIC_LEDUP2_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=43 REMAP_PORT_21=42 REMAP_PORT_22=41 REMAP_PORT_23=40 +m CMIC_LEDUP2_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=39 REMAP_PORT_25=38 REMAP_PORT_26=37 REMAP_PORT_27=36 +m CMIC_LEDUP2_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=35 REMAP_PORT_29=34 REMAP_PORT_30=33 REMAP_PORT_31=32 +m CMIC_LEDUP2_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=31 REMAP_PORT_33=30 REMAP_PORT_34=29 REMAP_PORT_35=28 +m CMIC_LEDUP2_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=27 REMAP_PORT_37=26 REMAP_PORT_38=25 REMAP_PORT_39=24 +m CMIC_LEDUP2_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=23 REMAP_PORT_41=22 REMAP_PORT_42=21 REMAP_PORT_43=20 +m CMIC_LEDUP2_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=19 REMAP_PORT_45=18 REMAP_PORT_46=17 REMAP_PORT_47=16 +m CMIC_LEDUP2_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=15 REMAP_PORT_49=14 REMAP_PORT_50=13 REMAP_PORT_51=12 +m CMIC_LEDUP2_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=11 REMAP_PORT_53=10 REMAP_PORT_54=9 REMAP_PORT_55=8 +m CMIC_LEDUP2_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=7 REMAP_PORT_57=6 REMAP_PORT_58=5 REMAP_PORT_59=4 +m CMIC_LEDUP2_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=3 REMAP_PORT_61=2 REMAP_PORT_62=1 REMAP_PORT_63=0 + +m CMIC_LEDUP3_PORT_ORDER_REMAP_0_3 REMAP_PORT_0=3 REMAP_PORT_1=2 REMAP_PORT_2=1 REMAP_PORT_3=0 +m CMIC_LEDUP3_PORT_ORDER_REMAP_4_7 REMAP_PORT_4=7 REMAP_PORT_5=6 REMAP_PORT_6=5 REMAP_PORT_7=4 +m CMIC_LEDUP3_PORT_ORDER_REMAP_8_11 REMAP_PORT_8=11 REMAP_PORT_9=10 REMAP_PORT_10=9 REMAP_PORT_11=8 +m CMIC_LEDUP3_PORT_ORDER_REMAP_12_15 REMAP_PORT_12=15 REMAP_PORT_13=14 REMAP_PORT_14=13 REMAP_PORT_15=12 +m CMIC_LEDUP3_PORT_ORDER_REMAP_16_19 REMAP_PORT_16=19 REMAP_PORT_17=18 REMAP_PORT_18=17 REMAP_PORT_19=16 +m CMIC_LEDUP3_PORT_ORDER_REMAP_20_23 REMAP_PORT_20=23 REMAP_PORT_21=22 REMAP_PORT_22=21 REMAP_PORT_23=20 +m CMIC_LEDUP3_PORT_ORDER_REMAP_24_27 REMAP_PORT_24=27 REMAP_PORT_25=26 REMAP_PORT_26=25 REMAP_PORT_27=24 +m CMIC_LEDUP3_PORT_ORDER_REMAP_28_31 REMAP_PORT_28=31 REMAP_PORT_29=30 REMAP_PORT_30=29 REMAP_PORT_31=28 +m CMIC_LEDUP3_PORT_ORDER_REMAP_32_35 REMAP_PORT_32=35 REMAP_PORT_33=34 REMAP_PORT_34=33 REMAP_PORT_35=32 +m CMIC_LEDUP3_PORT_ORDER_REMAP_36_39 REMAP_PORT_36=39 REMAP_PORT_37=38 REMAP_PORT_38=37 REMAP_PORT_39=36 +m CMIC_LEDUP3_PORT_ORDER_REMAP_40_43 REMAP_PORT_40=43 REMAP_PORT_41=42 REMAP_PORT_42=41 REMAP_PORT_43=40 +m CMIC_LEDUP3_PORT_ORDER_REMAP_44_47 REMAP_PORT_44=47 REMAP_PORT_45=46 REMAP_PORT_46=45 REMAP_PORT_47=44 +m CMIC_LEDUP3_PORT_ORDER_REMAP_48_51 REMAP_PORT_48=51 REMAP_PORT_49=50 REMAP_PORT_50=49 REMAP_PORT_51=48 +m CMIC_LEDUP3_PORT_ORDER_REMAP_52_55 REMAP_PORT_52=55 REMAP_PORT_53=54 REMAP_PORT_54=53 REMAP_PORT_55=52 +m CMIC_LEDUP3_PORT_ORDER_REMAP_56_59 REMAP_PORT_56=59 REMAP_PORT_57=58 REMAP_PORT_58=57 REMAP_PORT_59=56 +m CMIC_LEDUP3_PORT_ORDER_REMAP_60_63 REMAP_PORT_60=63 REMAP_PORT_61=62 REMAP_PORT_62=61 REMAP_PORT_63=60 + +led 0 stop +led 0 prog \ + 02 FD 42 80 02 FF 42 00 02 FE 42 00 02 FA 42 E0 \ + 02 FB 42 40 06 F9 D2 00 74 1E 02 F9 42 03 67 AC \ + 67 C3 67 52 86 FE 67 C3 67 52 86 FE 67 C3 67 52 \ + 86 FE 67 C3 67 52 86 FE 06 FB D6 FE 74 1E 86 FC \ + 3E FA 06 FE 88 4A 03 71 4C 67 84 57 67 84 57 67 \ + 98 57 06 FE 88 80 4A 00 27 97 75 4F 90 4A 00 27 \ + 4A 01 27 B7 97 71 69 77 42 06 F9 D6 FC 74 7C 02 \ + F9 4A 07 37 4E 07 02 FC 42 00 4E 07 06 F9 0A 07 \ + 71 4F 77 42 16 FF 06 FD 17 4D DA 07 74 95 12 FF \ + 52 00 86 FD 57 86 FF 57 16 FF 06 FD 07 4D DA 07 \ + 74 A9 12 FF 52 00 86 FD 57 86 FF 57 06 FE C2 FC \ + 98 98 12 F4 50 C2 FC 98 98 F2 F0 14 06 F4 C2 03 \ + 88 77 D1 06 FE C2 FC 98 98 F2 E0 14 06 FE C2 03 \ + 88 18 71 E2 80 18 71 DD 67 98 67 98 57 67 98 67 \ + 84 57 80 18 71 EB 67 84 67 98 57 67 84 67 84 57 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + + +led 1 stop +led 1 prog \ + 02 FD 42 80 02 FF 42 00 02 FE 42 00 02 FA 42 E0 \ + 02 FB 42 40 06 F9 D2 00 74 1E 02 F9 42 03 67 AC \ + 67 C3 67 52 86 FE 67 C3 67 52 86 FE 67 C3 67 52 \ + 86 FE 67 C3 67 52 86 FE 06 FB D6 FE 74 1E 86 FC \ + 3E FA 06 FE 88 4A 03 71 4C 67 84 57 67 84 57 67 \ + 98 57 06 FE 88 80 4A 00 27 97 75 4F 90 4A 00 27 \ + 4A 01 27 B7 97 71 69 77 42 06 F9 D6 FC 74 7C 02 \ + F9 4A 07 37 4E 07 02 FC 42 00 4E 07 06 F9 0A 07 \ + 71 4F 77 42 16 FF 06 FD 17 4D DA 07 74 95 12 FF \ + 52 00 86 FD 57 86 FF 57 16 FF 06 FD 07 4D DA 07 \ + 74 A9 12 FF 52 00 86 FD 57 86 FF 57 06 FE C2 FC \ + 98 98 12 F4 50 C2 FC 98 98 F2 F0 14 06 F4 C2 03 \ + 88 77 D1 06 FE C2 FC 98 98 F2 E0 14 06 FE C2 03 \ + 88 18 71 E2 80 18 71 DD 67 98 67 98 57 67 98 67 \ + 84 57 80 18 71 EB 67 84 67 98 57 67 84 67 84 57 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +led 2 stop +led 2 prog \ + 02 FD 42 80 02 FF 42 00 02 FE 42 00 02 FA 42 E0 \ + 02 FB 42 40 06 F9 D2 00 74 1E 02 F9 42 03 67 AC \ + 67 C3 67 52 86 FE 67 C3 67 52 86 FE 67 C3 67 52 \ + 86 FE 67 C3 67 52 86 FE 06 FB D6 FE 74 1E 86 FC \ + 3E FA 06 FE 88 4A 03 71 4C 67 84 57 67 84 57 67 \ + 98 57 06 FE 88 80 4A 00 27 97 75 4F 90 4A 00 27 \ + 4A 01 27 B7 97 71 69 77 42 06 F9 D6 FC 74 7C 02 \ + F9 4A 07 37 4E 07 02 FC 42 00 4E 07 06 F9 0A 07 \ + 71 4F 77 42 16 FF 06 FD 17 4D DA 07 74 95 12 FF \ + 52 00 86 FD 57 86 FF 57 16 FF 06 FD 07 4D DA 07 \ + 74 A9 12 FF 52 00 86 FD 57 86 FF 57 06 FE C2 FC \ + 98 98 12 F4 50 C2 FC 98 98 F2 F0 14 06 F4 C2 03 \ + 88 77 D1 06 FE C2 FC 98 98 F2 E0 14 06 FE C2 03 \ + 88 18 71 E2 80 18 71 DD 67 98 67 98 57 67 98 67 \ + 84 57 80 18 71 EB 67 84 67 98 57 67 84 67 84 57 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +led 3 stop +led 3 prog \ + 02 FD 42 80 02 FF 42 00 02 FE 42 00 02 FA 42 E0 \ + 02 FB 42 40 06 F9 D2 00 74 1E 02 F9 42 03 67 AC \ + 67 C3 67 52 86 FE 67 C3 67 52 86 FE 67 C3 67 52 \ + 86 FE 67 C3 67 52 86 FE 06 FB D6 FE 74 1E 86 FC \ + 3E FA 06 FE 88 4A 03 71 4C 67 84 57 67 84 57 67 \ + 98 57 06 FE 88 80 4A 00 27 97 75 4F 90 4A 00 27 \ + 4A 01 27 B7 97 71 69 77 42 06 F9 D6 FC 74 7C 02 \ + F9 4A 07 37 4E 07 02 FC 42 00 4E 07 06 F9 0A 07 \ + 71 4F 77 42 16 FF 06 FD 17 4D DA 07 74 95 12 FF \ + 52 00 86 FD 57 86 FF 57 16 FF 06 FD 07 4D DA 07 \ + 74 A9 12 FF 52 00 86 FD 57 86 FF 57 06 FE C2 FC \ + 98 98 12 F4 50 C2 FC 98 98 F2 F0 14 06 F4 C2 03 \ + 88 77 D1 06 FE C2 FC 98 98 F2 E0 14 06 FE C2 03 \ + 88 18 71 E2 80 18 71 DD 67 98 67 98 57 67 98 67 \ + 84 57 80 18 71 EB 67 84 67 98 57 67 84 67 84 57 \ + 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 + +led auto on +led 0 start +led 1 start +led 2 start +led 3 start diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json b/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json new file mode 100644 index 000000000000..d2b28c0aea8b --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/media_settings.json @@ -0,0 +1,2823 @@ +{ + "GLOBAL_MEDIA_SETTINGS": { + }, + "PORT_MEDIA_SETTINGS": { + "0": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0x103f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "1": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0x113f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "2": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "3": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "4": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "5": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "6": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174a03", + "lane1":"0x174a03", + "lane2":"0x174a03", + "lane3":"0x174a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "7": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x1b4603", + "lane2":"0x174a03", + "lane3":"0x174a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "8": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "9": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1d4403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3f02", + "lane2":"0xd3a02", + "lane3":"0xf3a04" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "10": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "11": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "12": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xa3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "13": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3402", + "lane1":"0xb3402", + "lane2":"0xa3402", + "lane3":"0xa3202" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "14": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x93002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "15": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154c03", + "lane1":"0x154c03", + "lane2":"0x154c03", + "lane3":"0x154c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "16": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154901", + "lane1":"0x124901", + "lane2":"0x124903", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0x82d02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "17": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124904", + "lane2":"0x124901", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "18": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x124900", + "lane2":"0x124903", + "lane3":"0x144902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "19": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x124904", + "lane2":"0x124904", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "20": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xc3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "21": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "22": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3402", + "lane1":"0xd3402", + "lane2":"0xd3402", + "lane3":"0xd3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "23": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1e4303", + "lane1":"0x1e4303", + "lane2":"0x1d4403", + "lane3":"0x1e4303" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xe3602", + "lane1":"0xf3a03", + "lane2":"0xf3d03", + "lane3":"0xf3d03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "24": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154906", + "lane1":"0x154904", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "25": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174902", + "lane1":"0x174902", + "lane2":"0x174902", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "26": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3002", + "lane1":"0xa3002", + "lane2":"0xa3002", + "lane3":"0xa3002" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "27": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3203", + "lane1":"0xc3403", + "lane2":"0xc3403", + "lane3":"0xd3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "28": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4505", + "lane1":"0x1a4505", + "lane2":"0x1a4505", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "29": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xc3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "30": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4604", + "lane1":"0x1a4604", + "lane2":"0x1a4604", + "lane3":"0x1a4604" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3402", + "lane1":"0xd3402", + "lane2":"0xc3402", + "lane3":"0xc3402" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "31": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3602", + "lane1":"0xd3602", + "lane2":"0xd3602", + "lane3":"0xd3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "32": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4404", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xf3a02", + "lane1":"0x113c03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "33": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xf3a03", + "lane1":"0xf3a03", + "lane2":"0xf3a03", + "lane3":"0xf3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "34": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4604", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xe3803", + "lane2":"0xd3803", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "35": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xe3804", + "lane1":"0xe3803", + "lane2":"0xe3804", + "lane3":"0xe3804" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "36": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3803", + "lane1":"0xd3803", + "lane2":"0xb3203", + "lane3":"0xc3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "37": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3202", + "lane1":"0xb3202", + "lane2":"0xa3003", + "lane3":"0xb3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "38": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x164903", + "lane1":"0x164903", + "lane2":"0x164903", + "lane3":"0x164903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3203", + "lane1":"0xa3203", + "lane2":"0xa3203", + "lane3":"0xa3203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "39": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x164901", + "lane1":"0x184901", + "lane2":"0x184901", + "lane3":"0x184901" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3202", + "lane1":"0xa3202", + "lane2":"0xa3003", + "lane3":"0xa3003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "40": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1c4503", + "lane2":"0x1c4503", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "41": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1a4703", + "lane2":"0x1b4603", + "lane3":"0x1c4503" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a03", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "42": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xb3a03", + "lane3":"0xa3803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "43": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1a4703", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "44": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x184902", + "lane2":"0x154902", + "lane3":"0x184902" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "45": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154900", + "lane1":"0x154900", + "lane2":"0x154900", + "lane3":"0x154900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x72d03", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "46": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174900", + "lane1":"0x174900", + "lane2":"0x154900", + "lane3":"0x174904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "47": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x154903", + "lane3":"0x154903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x82e03", + "lane3":"0x83003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "48": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184902", + "lane1":"0x164902", + "lane2":"0x164902", + "lane3":"0x144900" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "49": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x174901", + "lane1":"0x144902", + "lane2":"0x144902", + "lane3":"0x144903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x93003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "50": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184901", + "lane1":"0x174901", + "lane2":"0x164903", + "lane3":"0x154904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93003", + "lane2":"0x83003", + "lane3":"0x93003" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "51": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x154903", + "lane1":"0x154903", + "lane2":"0x134903", + "lane3":"0x144904" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93003", + "lane1":"0x93002", + "lane2":"0x82f03", + "lane3":"0x82f03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "52": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0x103f02", + "lane2":"0xd3a02", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "53": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x184803", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "54": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4503", + "lane1":"0x1e4204", + "lane2":"0x1c4503", + "lane3":"0x1d4304" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xf3d02", + "lane2":"0xd3a03", + "lane3":"0xf3c03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "55": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3a03", + "lane1":"0xc3a03", + "lane2":"0xa3403", + "lane3":"0xb3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "56": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x184903", + "lane1":"0x184903", + "lane2":"0x184903", + "lane3":"0x184903" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xa3403", + "lane1":"0xa3403", + "lane2":"0xa3403", + "lane3":"0xa3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "57": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x194803", + "lane1":"0x194803", + "lane2":"0x194903", + "lane3":"0x194803" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0x93203", + "lane1":"0xa3603", + "lane2":"0x93203", + "lane3":"0x93203" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "58": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "59": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4703" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xb3403", + "lane3":"0xb3403" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "60": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1a4703", + "lane1":"0x1a4703", + "lane2":"0x1a4703", + "lane3":"0x1a4505" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xb3403", + "lane1":"0xc3603", + "lane2":"0xc3603", + "lane3":"0xc3603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "61": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4603", + "lane1":"0x1b4603", + "lane2":"0x1b4603", + "lane3":"0x1b4603" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xc3603", + "lane1":"0xd3a03", + "lane2":"0xc3603", + "lane3":"0xc3602" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "62": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1c4404", + "lane1":"0x1c4404", + "lane2":"0x1b4504", + "lane3":"0x1c4404" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a03", + "lane1":"0xd3a03", + "lane2":"0xd3a03", + "lane3":"0xd3a03" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + }, + "63": { + "Default": { + "preemphasis": { + "lane0":"0x14410a", + "lane1":"0x14410a", + "lane2":"0x14410a", + "lane3":"0x14410a" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-AVAGO-AFBR-89CDDZ-JU1": { + "preemphasis": { + "lane0":"0x1b4504", + "lane1":"0x1b4504", + "lane2":"0x1a4703", + "lane3":"0x1b4504" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + }, + "JUNIPER-INNO-TR-IQ13L-NJ3": { + "preemphasis": { + "lane0":"0xd3a02", + "lane1":"0xd3a02", + "lane2":"0xd3a03", + "lane3":"0xd3a02" + }, + "idriver": { + "lane0":"0x8", + "lane1":"0x8", + "lane2":"0x8", + "lane3":"0x8" + } + } + } + } +} + diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/plugins/eeprom.py b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/eeprom.py new file mode 100644 index 000000000000..a5453dc4f0a3 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/eeprom.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess + import syslog + from struct import * + from array import * + +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + +SYSLOG_IDENTIFIER = "eeprom.py" +EEPROM_PATH = "/sys/bus/i2c/devices/0-0056/eeprom" + +def log_error(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + + def __init__(self, name, path, cpld_root, ro): + + if not os.path.exists(EEPROM_PATH): + log_error("Cannot find system eeprom") + raise RuntimeError("No syseeprom found") + + self.eeprom_path = EEPROM_PATH + super(board, self).__init__(self.eeprom_path, 0, '', True) + diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/plugins/psuutil.py b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/psuutil.py new file mode 100755 index 000000000000..707c7c897c82 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/psuutil.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +############################################################################# +# Accton +# +# Module contains an implementation of SONiC PSU Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + PsuBase.__init__(self) + + self.psu_path = "/sys/bus/i2c/devices/" + self.psu_presence = "/psu_present" + self.psu_oper_status = "/psu_power_good" + self.psu_mapping = { + 1: "10-0053", + 2: "9-0050", + } + + def get_num_psus(self): + return len(self.psu_mapping) + + def get_psu_status(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index]+self.psu_oper_status + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return False + + return status == 1 + + def get_psu_presence(self, index): + if index is None: + return False + + status = 0 + node = self.psu_path + self.psu_mapping[index] + self.psu_presence + try: + with open(node, 'r') as presence_status: + status = int(presence_status.read()) + except IOError: + return False + + return status == 1 diff --git a/device/juniper/x86_64-juniper_qfx5210-r0/plugins/sfputil.py b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/sfputil.py new file mode 100644 index 000000000000..fb5d57a609f8 --- /dev/null +++ b/device/juniper/x86_64-juniper_qfx5210-r0/plugins/sfputil.py @@ -0,0 +1,761 @@ +#!/usr/bin/env python + +try: + import time + from sonic_sfp.sfputilbase import * + import sys + import os + import string + from ctypes import create_string_buffer + # sys.path.append('/usr/local/bin') + # import sfp_detect +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +qfx5210_qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +qfx5210_sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +qfx5210_sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +qfx5210_qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed') + + + +class SfpUtil(SfpUtilBase): + """Platform specific SfpUtill class""" + + _port_start = 0 + _port_end = 63 + ports_in_block = 64 + cmd = '/var/run/sfppresence' + _port_to_eeprom_mapping = {} + port_to_i2c_mapping = { + 61 : 25, + 62 : 26, + 63 : 27, + 64 : 28, + 55 : 29, + 56 : 30, + 53 : 31, + 54 : 32, + 9 : 33, + 10 : 34, + 11 : 35, + 12 : 36, + 1 : 37, + 2 : 38, + 3 : 39, + 4 : 40, + 6 : 41, + 5 : 42, + 8 : 43, + 7 : 44, + 13 : 45, + 14 : 46, + 15 : 47, + 16 : 48, + 17 : 49, + 18 : 50, + 19 : 51, + 20 : 52, + 25 : 53, + 26 : 54, + 27 : 55, + 28 : 56, + 29 : 57, + 30 : 58, + 31 : 59, + 32 : 60, + 21 : 61, + 22 : 62, + 23 : 63, + 24 : 64, + 41 : 65, + 42 : 66, + 43 : 67, + 44 : 68, + 33 : 69, + 34 : 70, + 35 : 71, + 36 : 72, + 45 : 73, + 46 : 74, + 47 : 75, + 48 : 76, + 37 : 77, + 38 : 78, + 39 : 79, + 40 : 80, + 57 : 81, + 58 : 82, + 59 : 83, + 60 : 84, + 49 : 85, + 50 : 86, + 51 : 87, + 52 : 88,} + + port_to_sysfs_map = [ + '/sys/bus/i2c/devices/37-0050/sfp_is_present', + '/sys/bus/i2c/devices/38-0050/sfp_is_present', + '/sys/bus/i2c/devices/39-0050/sfp_is_present', + '/sys/bus/i2c/devices/40-0050/sfp_is_present', + '/sys/bus/i2c/devices/42-0050/sfp_is_present', + '/sys/bus/i2c/devices/41-0050/sfp_is_present', + '/sys/bus/i2c/devices/44-0050/sfp_is_present', + '/sys/bus/i2c/devices/43-0050/sfp_is_present', + '/sys/bus/i2c/devices/33-0050/sfp_is_present', + '/sys/bus/i2c/devices/34-0050/sfp_is_present', + '/sys/bus/i2c/devices/35-0050/sfp_is_present', + '/sys/bus/i2c/devices/36-0050/sfp_is_present', + '/sys/bus/i2c/devices/45-0050/sfp_is_present', + '/sys/bus/i2c/devices/46-0050/sfp_is_present', + '/sys/bus/i2c/devices/47-0050/sfp_is_present', + '/sys/bus/i2c/devices/48-0050/sfp_is_present', + '/sys/bus/i2c/devices/49-0050/sfp_is_present', + '/sys/bus/i2c/devices/50-0050/sfp_is_present', + '/sys/bus/i2c/devices/51-0050/sfp_is_present', + '/sys/bus/i2c/devices/52-0050/sfp_is_present', + '/sys/bus/i2c/devices/61-0050/sfp_is_present', + '/sys/bus/i2c/devices/62-0050/sfp_is_present', + '/sys/bus/i2c/devices/63-0050/sfp_is_present', + '/sys/bus/i2c/devices/64-0050/sfp_is_present', + '/sys/bus/i2c/devices/53-0050/sfp_is_present', + '/sys/bus/i2c/devices/54-0050/sfp_is_present', + '/sys/bus/i2c/devices/55-0050/sfp_is_present', + '/sys/bus/i2c/devices/56-0050/sfp_is_present', + '/sys/bus/i2c/devices/57-0050/sfp_is_present', + '/sys/bus/i2c/devices/58-0050/sfp_is_present', + '/sys/bus/i2c/devices/59-0050/sfp_is_present', + '/sys/bus/i2c/devices/60-0050/sfp_is_present', + '/sys/bus/i2c/devices/69-0050/sfp_is_present', + '/sys/bus/i2c/devices/70-0050/sfp_is_present', + '/sys/bus/i2c/devices/71-0050/sfp_is_present', + '/sys/bus/i2c/devices/72-0050/sfp_is_present', + '/sys/bus/i2c/devices/77-0050/sfp_is_present', + '/sys/bus/i2c/devices/78-0050/sfp_is_present', + '/sys/bus/i2c/devices/79-0050/sfp_is_present', + '/sys/bus/i2c/devices/80-0050/sfp_is_present', + '/sys/bus/i2c/devices/65-0050/sfp_is_present', + '/sys/bus/i2c/devices/66-0050/sfp_is_present', + '/sys/bus/i2c/devices/67-0050/sfp_is_present', + '/sys/bus/i2c/devices/68-0050/sfp_is_present', + '/sys/bus/i2c/devices/73-0050/sfp_is_present', + '/sys/bus/i2c/devices/74-0050/sfp_is_present', + '/sys/bus/i2c/devices/75-0050/sfp_is_present', + '/sys/bus/i2c/devices/76-0050/sfp_is_present', + '/sys/bus/i2c/devices/85-0050/sfp_is_present', + '/sys/bus/i2c/devices/86-0050/sfp_is_present', + '/sys/bus/i2c/devices/87-0050/sfp_is_present', + '/sys/bus/i2c/devices/88-0050/sfp_is_present', + '/sys/bus/i2c/devices/31-0050/sfp_is_present', + '/sys/bus/i2c/devices/32-0050/sfp_is_present', + '/sys/bus/i2c/devices/29-0050/sfp_is_present', + '/sys/bus/i2c/devices/30-0050/sfp_is_present', + '/sys/bus/i2c/devices/81-0050/sfp_is_present', + '/sys/bus/i2c/devices/82-0050/sfp_is_present', + '/sys/bus/i2c/devices/83-0050/sfp_is_present', + '/sys/bus/i2c/devices/84-0050/sfp_is_present', + '/sys/bus/i2c/devices/25-0050/sfp_is_present', + '/sys/bus/i2c/devices/26-0050/sfp_is_present', + '/sys/bus/i2c/devices/27-0050/sfp_is_present', + '/sys/bus/i2c/devices/28-0050/sfp_is_present' + + ] + # sys.path.append('/usr/local/bin') + _qsfp_ports = range(0, ports_in_block + 1) + + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/sfp_eeprom' + for x in range(0, self._port_end + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x+1]) + self._port_to_eeprom_mapping[x] = port_eeprom_path + SfpUtilBase.__init__(self) + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + path = "/sys/bus/i2c/devices/19-0060/module_reset_{0}" + port_ps = path.format(port_num+1) + + try: + reg_file = open(port_ps, 'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + #HW will clear reset after set. + reg_file.seek(0) + reg_file.write('1') + reg_file.close() + return True + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num < self._port_start or port_num > self._port_end: + return False + + path = "/sys/bus/i2c/devices/{0}-0050/sfp_is_present" + port_ps = path.format(self.port_to_i2c_mapping[port_num+1]) + + + try: + reg_file = open(port_ps) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_value = reg_file.readline().rstrip() + if reg_value == '1': + return True + + return False + + @property + def port_start(self): + return self._port_start + + @property + def port_end(self): + return self._port_end + + @property + def qsfp_ports(self): + return range(0, self.ports_in_block + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + # Writing to a file from a list + def write_to_file(self, file_name, from_list): + try: + fp1 = open(file_name, 'w') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + for i in from_list: + fp1.write(i) + fp1.write('\n') + + fp1.close() + return True + + + # Reading from a file to a list + def read_from_file(self, file_name): + try: + fp = open(file_name, 'r') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + to_list = fp.readlines() + to_list = [x.rstrip() for x in to_list] + fp.close() + return to_list + + def sfp_detect(self): + x = 0 + ret_dict = {} + defl_dict = {} + current_sfp_values = [0] * 64 + previous_sfp_values = [0] * 64 + + if not os.path.isfile(self.cmd): + pass + else: + if (self.read_from_file(self.cmd) == False): + return False, defl_dict + else: + previous_sfp_values = self.read_from_file(self.cmd) + + # Read the current values from sysfs + for x in range(len(self.port_to_sysfs_map)): + try: + reg_file = open(self.port_to_sysfs_map[x], 'r') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False, defl_dict + + sfp_present = reg_file.readline().rstrip() + reg_file.close() + current_sfp_values[x] = sfp_present + if (current_sfp_values[x] != previous_sfp_values[x]): + ret_dict.update({x:current_sfp_values[x]}) + + if(self.write_to_file(self.cmd, current_sfp_values) == True): + return True, ret_dict + else: + return False, defl_dict + + def get_transceiver_change_event(self): + time.sleep(3) + return self.sfp_detect() + + 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 + + try: + eeprom = None + + if not self.get_presence(port_num): + return False + + eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if ((lpmode & 0x3) == 0x3): + return True # Low Power Mode if "Power override" bit is 1 and "Power set" bit is 1 + else: + return False # High Power Mode if one of the following conditions is matched: + # 1. "Power override" bit is 0 + # 2. "Power override" bit is 1 and "Power set" bit is 0 + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + 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 + + try: + eeprom = None + + if not self.get_presence(port_num): + return False # Port is not present, unable to set the eeprom + + # Fill in write buffer + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") + eeprom.seek(93) + eeprom.write(buffer[0]) + return True + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + finally: + if eeprom is not None: + eeprom.close() + time.sleep(0.01) + + # Read out SFP type, vendor name, PN, REV, SN from eeprom. + def get_transceiver_info_dict(self, port_num): + transceiver_info_dict = {} + compliance_code_dict = {} + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if port_num in self.osfp_ports: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + print("Error, file not exist %s" % file_path) + return None + + try: + sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfp_type_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return None + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_type_data['data']['type_abbrv_name']['value'] + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + # Below part is added to avoid fail the xcvrd, shall be implemented later + transceiver_info_dict['vendor_oui'] = 'N/A' + transceiver_info_dict['vendor_date'] = 'N/A' + transceiver_info_dict['Connector'] = 'N/A' + transceiver_info_dict['encoding'] = 'N/A' + transceiver_info_dict['ext_identifier'] = 'N/A' + transceiver_info_dict['ext_rateselect_compliance'] = 'N/A' + transceiver_info_dict['cable_type'] = 'N/A' + transceiver_info_dict['cable_length'] = 'N/A' + transceiver_info_dict['specification_compliance'] = 'N/A' + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + + else: + if port_num in self.qsfp_ports: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + cable_length_width = XCVR_CABLE_LENGTH_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + sfp_type = 'QSFP' + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + cable_length_width = XCVR_CABLE_LENGTH_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + sfp_type = 'SFP' + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + print("Error, file not exist %s" % file_path) + return None + + try: + sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_INTFACE_BULK_OFFSET), interface_info_bulk_width) + if sfp_interface_bulk_raw is not None: + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) + else: + return None + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + else: + return None + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + else: + return None + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['modelname'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardwarerev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serialnum'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['Connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + if sfp_type == 'QSFP': + for key in qfx5210_qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + break + else: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = 'N/A' + + for key in qfx5210_qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + if sfp_interface_bulk_data['data'].has_key('Nominal Bit Rate(100Mbs)'): + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + else: + for key in qfx5210_sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + else: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = 'N/A' + + for key in qfx5210_sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + if sfp_interface_bulk_data['data'].has_key('NominalSignallingRate(UnitsOf100Mbd)'): + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + else: + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + #transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_dom_info_dict(self, port_num): + transceiver_dom_info_dict = {} + + if port_num in self.osfp_ports: + # Below part is added to avoid fail xcvrd, shall be implemented later + transceiver_dom_info_dict['temperature'] = 'N/A' + transceiver_dom_info_dict['voltage'] = 'N/A' + transceiver_dom_info_dict['rx1power'] = 'N/A' + 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'] = 'N/A' + 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'] = 'N/A' + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + + elif port_num in self.qsfp_ports: + offset = 0 + offset_xcvr = 128 + file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + return None + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability(qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return None + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return None + + qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + else: + return None + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_CHANNL_MON_OFFSET), QSFP_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 None + + 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: + 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']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + 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 + + try: + sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + + sfpd_obj = sff8472Dom() + 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 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 None + + 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 None + + 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 diff --git a/device/mellanox/x86_64-mlnx_msn2700_simx-r0/platform_wait b/device/mellanox/x86_64-mlnx_msn2700_simx-r0/platform_wait deleted file mode 120000 index 4b30bd429854..000000000000 --- a/device/mellanox/x86_64-mlnx_msn2700_simx-r0/platform_wait +++ /dev/null @@ -1 +0,0 @@ -../x86_64-mlnx_msn2700-r0/platform_wait \ No newline at end of file diff --git a/device/mellanox/x86_64-mlnx_msn3700_simx-r0/platform_wait b/device/mellanox/x86_64-mlnx_msn3700_simx-r0/platform_wait deleted file mode 120000 index 685dfb8437fc..000000000000 --- a/device/mellanox/x86_64-mlnx_msn3700_simx-r0/platform_wait +++ /dev/null @@ -1 +0,0 @@ -../x86_64-mlnx_msn3700-r0/platform_wait \ No newline at end of file diff --git a/dockers/docker-database/Dockerfile.j2 b/dockers/docker-database/Dockerfile.j2 index 9ec3926de6fb..acb5e013fb84 100644 --- a/dockers/docker-database/Dockerfile.j2 +++ b/dockers/docker-database/Dockerfile.j2 @@ -32,6 +32,9 @@ RUN apt-get clean -y && \ s/^client-output-buffer-limit pubsub [0-9]+mb [0-9]+mb [0-9]+/client-output-buffer-limit pubsub 0 0 0/ \ ' /etc/redis/redis.conf -COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["supervisord.conf.j2", "/usr/share/sonic/templates/"] +COPY ["docker-database-init.sh", "/usr/local/bin/"] +COPY ["ping_pong_db_insts", "/usr/local/bin/"] +COPY ["database_config.json", "/etc/default/sonic-db/"] -ENTRYPOINT ["/usr/bin/supervisord"] +ENTRYPOINT ["/usr/local/bin/docker-database-init.sh"] diff --git a/dockers/docker-database/database_config.json b/dockers/docker-database/database_config.json new file mode 100644 index 000000000000..6725af38c5ea --- /dev/null +++ b/dockers/docker-database/database_config.json @@ -0,0 +1,43 @@ +{ + "INSTANCES": { + "redis":{ + "port": 6379, + "socket": "/var/run/redis/redis.sock" + } + }, + "DATABASES" : { + "APPL_DB" : { + "id" : 0, + "instance" : "redis" + }, + "ASIC_DB" : { + "id" : 1, + "instance" : "redis" + }, + "COUNTERS_DB" : { + "id" : 2, + "instance" : "redis" + }, + "LOGLEVEL_DB" : { + "id" : 3, + "instance" : "redis" + }, + "CONFIG_DB" : { + "id" : 4, + "instance" : "redis" + }, + "PFC_WD_DB" : { + "id" : 5, + "instance" : "redis" + }, + "FLEX_COUNTER_DB" : { + "id" : 5, + "instance" : "redis" + }, + "STATE_DB" : { + "id" : 6, + "instance" : "redis" + } + }, + "VERSION" : "1.0" +} diff --git a/dockers/docker-database/docker-database-init.sh b/dockers/docker-database/docker-database-init.sh new file mode 100755 index 000000000000..ebdcc6abb694 --- /dev/null +++ b/dockers/docker-database/docker-database-init.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +mkdir -p /var/run/redis/sonic-db +if [ -f /etc/sonic/database_config.json ]; then + cp /etc/sonic/database_config.json /var/run/redis/sonic-db +else + cp /etc/default/sonic-db/database_config.json /var/run/redis/sonic-db +fi + +mkdir -p /etc/supervisor/conf.d/ +# generate all redis server supervisord configuration file +sonic-cfggen -j /var/run/redis/sonic-db/database_config.json -t /usr/share/sonic/templates/supervisord.conf.j2 > /etc/supervisor/conf.d/supervisord.conf + +exec /usr/bin/supervisord diff --git a/dockers/docker-database/ping_pong_db_insts b/dockers/docker-database/ping_pong_db_insts new file mode 100755 index 000000000000..484d4da0cfb0 --- /dev/null +++ b/dockers/docker-database/ping_pong_db_insts @@ -0,0 +1,40 @@ +#!/usr/bin/python +import json +import os +import subprocess +import time +import syslog + +def ping_redis(cmd): + output = '' + while True: + try: + output = subprocess.check_output(cmd, shell=True) + except subprocess.CalledProcessError as e: + syslog.syslog(syslog.LOG_ERR, 'ping redis failed, cmd : {}'.format(cmd)) + + if 'PONG' in output: + break + syslog.syslog(syslog.LOG_ERR, 'ping response : {}'.format(output)) + time.sleep(1) + +database_config_file = "/var/run/redis/sonic-db/database_config.json" + +data = {} +while True: + if os.path.isfile(database_config_file): + with open(database_config_file, "r") as read_file: + data = json.load(read_file) + break + time.sleep(1) + syslog.syslog(syslog.LOG_ERR, 'config file {} does not exist right now'.format(database_config_file)) + +while True: + if 'INSTANCES' in data: + for inst in data["INSTANCES"]: + port = data["INSTANCES"][inst]["port"] + cmd = "redis-cli -p " + str(port) + " ping" + ping_redis(cmd) + break + time.sleep(1) + syslog.syslog(syslog.LOG_ERR, 'config file {} does not have INSTANCES'.format(database_config_file)) diff --git a/dockers/docker-database/supervisord.conf b/dockers/docker-database/supervisord.conf deleted file mode 100644 index 798fedd0c895..000000000000 --- a/dockers/docker-database/supervisord.conf +++ /dev/null @@ -1,21 +0,0 @@ -[supervisord] -logfile_maxbytes=1MB -logfile_backups=2 -nodaemon=true - -[program:rsyslogd] -command=/bin/bash -c "rm -f /var/run/rsyslogd.pid && /usr/sbin/rsyslogd -n" -priority=1 -autostart=true -autorestart=false -stdout_logfile=syslog -stderr_logfile=syslog - -[program:redis-server] -command=/bin/bash -c "{ [[ -s /var/lib/redis/dump.rdb ]] || rm -f /var/lib/redis/dump.rdb; } && exec /usr/bin/redis-server /etc/redis/redis.conf" -priority=2 -autostart=true -autorestart=false -stdout_logfile=syslog -stderr_logfile=syslog - diff --git a/dockers/docker-database/supervisord.conf.j2 b/dockers/docker-database/supervisord.conf.j2 new file mode 100644 index 000000000000..9e4a42d6b3a4 --- /dev/null +++ b/dockers/docker-database/supervisord.conf.j2 @@ -0,0 +1,24 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[program:rsyslogd] +command=/bin/bash -c "rm -f /var/run/rsyslogd.pid && /usr/sbin/rsyslogd -n" +priority=1 +autostart=true +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog + +{% if INSTANCES %} +{% for redis_inst, redis_items in INSTANCES.iteritems() %} +[program: {{ redis_inst }}] +command=/bin/bash -c "{ [[ -s /var/lib/{{ redis_inst }}/dump.rdb ]] || rm -f /var/lib/{{ redis_inst }}/dump.rdb; } && mkdir -p /var/lib/{{ redis_inst }} && exec /usr/bin/redis-server /etc/redis/redis.conf --port {{ redis_items['port'] }} --unixsocket {{ redis_items['socket'] }} --pidfile /var/run/redis/{{ redis_inst }}.pid --dir /var/lib/{{ redis_inst }}" +priority=2 +autostart=true +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +{% endfor %} +{% endif %} diff --git a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 index bbc24ecc091c..4462ff3d7fdc 100644 --- a/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 +++ b/dockers/docker-dhcp-relay/docker-dhcp-relay.supervisord.conf.j2 @@ -43,8 +43,16 @@ isc-dhcp-relay-{{ vlan_name }} {# Create a program entry for each DHCP relay agent instance #} +{% set relay_for_ipv4 = { 'flag': False } %} {% for vlan_name in VLAN %} {% if VLAN[vlan_name]['dhcp_servers'] %} +{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} +{% if dhcp_server | ipv4 %} +{% set _dummy = relay_for_ipv4.update({'flag': True}) %} +{% endif %} +{% endfor %} +{% if relay_for_ipv4.flag %} +{% set _dummy = relay_for_ipv4.update({'flag': False}) %} [program:isc-dhcp-relay-{{ vlan_name }}] {# We treat this VLAN as a downstream interface (-id), as we only want to listen for requests #} command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /tmp/port-name-alias-map.txt -id {{ vlan_name }} @@ -58,7 +66,9 @@ command=/usr/sbin/dhcrelay -d -m discard -a %%h:%%p %%P --name-alias-map-file /t {% for (name, prefix) in PORTCHANNEL_INTERFACE|pfx_filter %} {% if prefix | ipv4 %} -iu {{ name }}{% endif -%} {% endfor %} -{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} {{ dhcp_server }}{% endfor %} +{% for dhcp_server in VLAN[vlan_name]['dhcp_servers'] %} +{%- if dhcp_server | ipv4 %} {{ dhcp_server }}{% endif -%} +{% endfor %} priority=3 autostart=false @@ -66,6 +76,7 @@ autorestart=false stdout_logfile=syslog stderr_logfile=syslog +{% endif %} {% endif %} {% endfor %} {% endif %} diff --git a/dockers/docker-fpm-frr/bgpcfgd b/dockers/docker-fpm-frr/bgpcfgd index 012a766c20b9..f6d0b86385b5 100755 --- a/dockers/docker-fpm-frr/bgpcfgd +++ b/dockers/docker-fpm-frr/bgpcfgd @@ -1,65 +1,124 @@ #!/usr/bin/env python import sys +import copy +import Queue import redis import subprocess import syslog -from swsssdk import ConfigDBConnector +import os +from swsscommon import swsscommon -class BGPConfigDaemon: + +def run_command(command): + syslog.syslog(syslog.LOG_DEBUG, "execute command {}.".format(command)) + p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + stdout = p.communicate()[0] + p.wait() + if p.returncode != 0: + syslog.syslog(syslog.LOG_ERR, 'command execution returned {}. Command: "{}", stdout: "{}"'.format(p.returncode, command, stdout)) + + +class BGPConfigManager(object): + def __init__(self, daemon): + self.daemon = daemon + self.bgp_asn = None + self.bgp_message = Queue.Queue(0) + daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_DEVICE_METADATA_TABLE_NAME, self.__metadata_handler) + daemon.add_manager(swsscommon.CONFIG_DB, swsscommon.CFG_BGP_NEIGHBOR_TABLE_NAME, self.__bgp_handler) + + def __metadata_handler(self, key, op, data): + if key != "localhost" \ + or "bgp_asn" not in data \ + or self.bgp_asn == data["bgp_asn"]: + return + + # TODO add ASN update commands + + self.bgp_asn = data["bgp_asn"] + self.__update_bgp() + + def __update_bgp(self): + while not self.bgp_message.empty(): + key, op, data = self.bgp_message.get() + syslog.syslog(syslog.LOG_INFO, 'value for {} changed to {}'.format(key, data)) + if op == swsscommon.SET_COMMAND: + command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} remote-as {}'".format(self.bgp_asn, key, data['asn']) + run_command(command) + if "name" in data: + command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} description {}'".format(self.bgp_asn, key, data['name']) + run_command(command) + if "admin_status" in data: + command_mod = "no " if data["admin_status"] == "up" else "" + command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c '{}neighbor {} shutdown'".format(self.bgp_asn, command_mod, key) + run_command(command) + elif op == swsscommon.DEL_COMMAND: + # Neighbor is deleted + command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {}'".format(self.bgp_asn, key) + run_command(command) + + def __bgp_handler(self, key, op, data): + self.bgp_message.put((key, op, data)) + # If ASN is not set, we just cache this message until the ASN is set. + if self.bgp_asn == None: + return + self.__update_bgp() + + +class Daemon(object): + + SELECT_TIMEOUT = 1000 + SUPPORT_DATABASE_LIST = (swsscommon.APPL_DB, swsscommon.CONFIG_DB) def __init__(self): - self.config_db = ConfigDBConnector() - self.config_db.connect() - self.bgp_asn = self.config_db.get_entry('DEVICE_METADATA', 'localhost')['bgp_asn'] - self.bgp_neighbor = self.config_db.get_table('BGP_NEIGHBOR') - - def __run_command(self, command): -# print command - p = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) - stdout = p.communicate()[0] - p.wait() - if p.returncode != 0: - syslog.syslog(syslog.LOG_ERR, '[bgp cfgd] command execution returned {}. Command: "{}", stdout: "{}"'.format(p.returncode, command, stdout)) - - def metadata_handler(self, key, data): - if key == 'localhost' and data.has_key('bgp_asn'): - if data['bgp_asn'] != self.bgp_asn: - syslog.syslog(syslog.LOG_INFO, '[bgp cfgd] ASN changed to {} from {}, restart BGP...'.format(data['bgp_asn'], self.bgp_asn)) - self.__run_command("supervisorctl restart start.sh") - self.__run_command("service quagga restart") - self.bgp_asn = data['bgp_asn'] - - def bgp_handler(self, key, data): - syslog.syslog(syslog.LOG_INFO, '[bgp cfgd] value for {} changed to {}'.format(key, data)) - if not data: - # Neighbor is deleted - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'no neighbor {}'".format(self.bgp_asn, key) - self.__run_command(command) - self.bgp_neighbor.pop(key) - else: - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} remote-as {}'".format(self.bgp_asn, key, data['asn']) - self.__run_command(command) - if data.has_key('name'): - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c 'neighbor {} description {}'".format(self.bgp_asn, key, data['name']) - self.__run_command(command) - if data.has_key('admin_status'): - command_mod = 'no ' if data['admin_status'] == 'up' else '' - command = "vtysh -c 'configure terminal' -c 'router bgp {}' -c '{}neighbor {} shutdown'".format(self.bgp_asn, command_mod, key) - self.__run_command(command) - self.bgp_neighbor[key] = data + self.appl_db = swsscommon.DBConnector(swsscommon.APPL_DB, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) + self.conf_db = swsscommon.DBConnector(swsscommon.CONFIG_DB, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) + self.selector = swsscommon.Select() + self.db_connectors = {} + self.callbacks = {} + self.subscribers = set() + + def get_db_connector(self, db): + if db not in Daemon.SUPPORT_DATABASE_LIST: + raise ValueError("database {} not Daemon support list {}.".format(db, SUPPORT_DATABASE_LIST)) + # if this database connector has been initialized + if db not in self.db_connectors: + self.db_connectors[db] = swsscommon.DBConnector(db, swsscommon.DBConnector.DEFAULT_UNIXSOCKET, 0) + return self.db_connectors[db] + + def add_manager(self, db, table_name, callback): + if db not in self.callbacks: + self.callbacks[db] = {} + if table_name not in self.callbacks[db]: + self.callbacks[db][table_name] = [] + conn = self.get_db_connector(db) + subscriber = swsscommon.SubscriberStateTable(conn, table_name) + self.subscribers.add(subscriber) + self.selector.addSelectable(subscriber) + self.callbacks[db][table_name].append(callback) def start(self): - self.config_db.subscribe('BGP_NEIGHBOR', - lambda table, key, data: self.bgp_handler(key, data)) - self.config_db.subscribe('DEVICE_METADATA', - lambda table, key, data: self.metadata_handler(key, data)) - self.config_db.listen() + while True: + state, selectable = self.selector.select(Daemon.SELECT_TIMEOUT) + if not selectable: + continue + for subscriber in self.subscribers: + key, op, fvs = subscriber.pop() + # if no new message + if not key: + continue + data = dict(fvs) + syslog.syslog(syslog.LOG_DEBUG, "Receive message : {}".format((key, op, fvs))) + for callback in self.callbacks[subscriber.getDbConnector().getDbId()][subscriber.getTableName()]: + callback(key, op, data) def main(): - daemon = BGPConfigDaemon() + syslog.openlog("bgpcfgd") + daemon = Daemon() + bgp_manager = BGPConfigManager(daemon) daemon.start() + syslog.closelog() if __name__ == "__main__": main() diff --git a/dockers/docker-orchagent/switch.json.j2 b/dockers/docker-orchagent/switch.json.j2 index a7dafd40f267..f8beffbc9ad7 100644 --- a/dockers/docker-orchagent/switch.json.j2 +++ b/dockers/docker-orchagent/switch.json.j2 @@ -6,6 +6,8 @@ {% set hash_seed = 0 %} {% elif DEVICE_METADATA.localhost.type == "LeafRouter" %} {% set hash_seed = 10 %} +{% elif DEVICE_METADATA.localhost.type == "SpineRouter" %} +{% set hash_seed = 15 %} {% endif %} {% endif %} [ diff --git a/files/build_scripts/generate_asic_config_checksum.py b/files/build_scripts/generate_asic_config_checksum.py new file mode 100644 index 000000000000..ca83f4f26a6f --- /dev/null +++ b/files/build_scripts/generate_asic_config_checksum.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +import syslog +import os +import hashlib + +SYSLOG_IDENTIFIER = 'asic_config_checksum' + +CHUNK_SIZE = 8192 + +CONFIG_FILES = { + os.path.abspath('./src/sonic-swss/swssconfig/sample/'): ['netbouncer.json', '00-copp.config.json'] +} + +OUTPUT_FILE = os.path.abspath('./asic_config_checksum') + +def log_info(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_INFO, msg) + syslog.closelog() + +def log_error(msg): + syslog.openlog(SYSLOG_IDENTIFIER) + syslog.syslog(syslog.LOG_ERR, msg) + syslog.closelog() + +def get_config_files(config_file_map): + ''' + Generates a list of absolute paths to ASIC config files. + ''' + config_files = [] + for path, files in config_file_map.items(): + for config_file in files: + config_files.append(os.path.join(path, config_file)) + return config_files + +def generate_checksum(checksum_files): + ''' + Generates a checksum for a given list of files. Returns None if an error + occurs while reading the files. + + NOTE: The checksum is performed in the order provided. This function does + NOT do any re-ordering of the files before creating the checksum. + ''' + checksum = hashlib.sha1() + for checksum_file in checksum_files: + try: + with open(checksum_file, 'r') as f: + for chunk in iter(lambda: f.read(CHUNK_SIZE), b""): + checksum.update(chunk) + except IOError as e: + log_error('Error processing ASIC config file ' + checksum_file + ':' + e.strerror) + return None + + return checksum.hexdigest() + +def main(): + config_files = sorted(get_config_files(CONFIG_FILES)) + checksum = generate_checksum(config_files) + if checksum == None: + exit(1) + + with open(OUTPUT_FILE, 'w') as output: + output.write(checksum + '\n') + +if __name__ == '__main__': + main() diff --git a/files/build_templates/database.service.j2 b/files/build_templates/database.service.j2 index efa98b168beb..472b9d328b7d 100644 --- a/files/build_templates/database.service.j2 +++ b/files/build_templates/database.service.j2 @@ -2,6 +2,7 @@ Description=Database container Requires=docker.service After=docker.service +After=rc-local.service [Service] User=root diff --git a/files/build_templates/docker_image_ctl.j2 b/files/build_templates/docker_image_ctl.j2 index 9966728988bd..756ce16a2bc0 100644 --- a/files/build_templates/docker_image_ctl.j2 +++ b/files/build_templates/docker_image_ctl.j2 @@ -71,10 +71,7 @@ function postStartAction() { {%- if docker_container_name == "database" %} # Wait until redis starts - REDIS_SOCK="/var/run/redis/redis.sock" - until [[ $(/usr/bin/docker exec database redis-cli -s $REDIS_SOCK ping | grep -c PONG) -gt 0 ]]; do - sleep 1; - done + /usr/bin/docker exec database ping_pong_db_insts if [[ ("$BOOT_TYPE" == "warm" || "$BOOT_TYPE" == "fastfast") && -f $WARM_DIR/dump.rdb ]]; then rm -f $WARM_DIR/dump.rdb else @@ -163,6 +160,11 @@ start() { {%- if docker_container_name == "database" %} echo "Creating new {{docker_container_name}} container" + # if database_config exists in old_config, use it; otherwise use the default one in new image + if [ -f /etc/sonic/old_config/database_config.json ]; then + echo "Use database_config.json from old system..." + mv /etc/sonic/old_config/database_config.json /etc/sonic/ + fi {%- else %} echo "Creating new {{docker_container_name}} container with HWSKU $HWSKU" {%- endif %} diff --git a/files/image_config/platform/rc.local b/files/image_config/platform/rc.local index 76fe390be3cd..1df03718da3c 100755 --- a/files/image_config/platform/rc.local +++ b/files/image_config/platform/rc.local @@ -121,6 +121,8 @@ program_console_speed() #### Begin Main Body #### +logger "SONiC version ${SONIC_VERSION} starting up..." + # If the machine.conf is absent, it indicates that the unit booted # into SONiC from another NOS. Extract the machine.conf from ONIE. if [ ! -e /host/machine.conf ]; then diff --git a/platform/barefoot/sonic-platform-modules-arista b/platform/barefoot/sonic-platform-modules-arista index 8c45a8e11153..73dd2e0fe144 160000 --- a/platform/barefoot/sonic-platform-modules-arista +++ b/platform/barefoot/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 8c45a8e111534f9d4337d3552eaf08881fb19d30 +Subproject commit 73dd2e0fe144e2bb6778d39d3e051c597bb1c9d8 diff --git a/platform/broadcom/docker-syncd-brcm-rpc.mk b/platform/broadcom/docker-syncd-brcm-rpc.mk index bb31e82ef61d..ed7fc1b5265e 100644 --- a/platform/broadcom/docker-syncd-brcm-rpc.mk +++ b/platform/broadcom/docker-syncd-brcm-rpc.mk @@ -20,5 +20,6 @@ endif $(DOCKER_SYNCD_BRCM_RPC)_CONTAINER_NAME = syncd $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += --net=host --privileged -t $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf +$(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /host/warmboot:/var/warmboot $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd $(DOCKER_SYNCD_BRCM_RPC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 0d69d63c02e2..451e22ba3722 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -51,7 +51,8 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ALPHANETWORKS_SNH60A0_320FV2_PLATFORM_MODULE) \ $(ALPHANETWORKS_SNH60B0_640F_PLATFORM_MODULE) \ $(BRCM_XLR_GTS_PLATFORM_MODULE) \ - $(DELTA_AG9032V2A_PLATFORM_MODULE) + $(DELTA_AG9032V2A_PLATFORM_MODULE) \ + $(JUNIPER_QFX5210_PLATFORM_MODULE) ifeq ($(INSTALL_DEBUG_TOOLS),y) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) $(SONIC_ONE_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES)) diff --git a/platform/broadcom/platform-modules-dell.mk b/platform/broadcom/platform-modules-dell.mk index 1d0c41956bcf..34e404cfae45 100644 --- a/platform/broadcom/platform-modules-dell.mk +++ b/platform/broadcom/platform-modules-dell.mk @@ -36,3 +36,6 @@ $(DELL_S5232F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5232f_c3538-r0 $(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5232F_PLATFORM_MODULE))) SONIC_STRETCH_DEBS += $(DELL_Z9100_PLATFORM_MODULE) + +#flashrom tool +$(shell ./$(PLATFORM_PATH)/sonic-platform-modules-dell/tools/flashrom.sh > /dev/null 2>&1) diff --git a/platform/broadcom/platform-modules-juniper.mk b/platform/broadcom/platform-modules-juniper.mk new file mode 100755 index 000000000000..083dabda6d97 --- /dev/null +++ b/platform/broadcom/platform-modules-juniper.mk @@ -0,0 +1,13 @@ +# Juniper Platform modules + +JUNIPER_QFX5210_PLATFORM_MODULE_VERSION = 1.1 + +export JUNIPER_QFX5210_PLATFORM_MODULE_VERSION + +JUNIPER_QFX5210_PLATFORM_MODULE = sonic-platform-juniper-qfx5210_$(JUNIPER_QFX5210_PLATFORM_MODULE_VERSION)_amd64.deb +$(JUNIPER_QFX5210_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-juniper +$(JUNIPER_QFX5210_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +$(JUNIPER_QFX5210_PLATFORM_MODULE)_PLATFORM = x86_64-juniper_qfx5210-r0 +SONIC_DPKG_DEBS += $(JUNIPER_QFX5210_PLATFORM_MODULE) + +SONIC_STRETCH_DEBS += $(JUNIPER_QFX5210_PLATFORM_MODULE) diff --git a/platform/broadcom/rules.mk b/platform/broadcom/rules.mk index 884a50a1ac0d..8dd7b2c8cbb2 100644 --- a/platform/broadcom/rules.mk +++ b/platform/broadcom/rules.mk @@ -10,6 +10,7 @@ include $(PLATFORM_PATH)/platform-modules-cel.mk include $(PLATFORM_PATH)/platform-modules-delta.mk include $(PLATFORM_PATH)/platform-modules-quanta.mk #include $(PLATFORM_PATH)/platform-modules-mitac.mk +include $(PLATFORM_PATH)/platform-modules-juniper.mk include $(PLATFORM_PATH)/platform-modules-brcm-xlr-gts.mk include $(PLATFORM_PATH)/docker-syncd-brcm.mk include $(PLATFORM_PATH)/docker-syncd-brcm-rpc.mk diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/fanutil.py index ca0f3f9da1e3..52889cd5895d 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/fanutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/fanutil.py @@ -1,26 +1,22 @@ #!/usr/bin/env python +# Copyright (c) 2019 Edgecore Networks Corporation # -# Copyright (C) 2017 Accton Technology Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# # ------------------------------------------------------------------ # HISTORY: # mm/dd/yyyy (A.D.) -# 11/13/2017: Polly Hsu, Create -# 1/10/2018: Jostar modify for as7716_32 -# 12/03/2018: Jostar modify for as7726_32 +# 8/27/2019:Jostar craete for as9716_32d # ------------------------------------------------------------------ try: @@ -46,8 +42,8 @@ class FanUtil(object): FAN_NODE_FAULT_IDX_OF_MAP = 1 FAN_NODE_DIR_IDX_OF_MAP = 2 - BASE_VAL_PATH = '/sys/bus/i2c/devices/54-0066/{0}' - FAN_DUTY_PATH = '/sys/bus/i2c/devices/54-0066/fan_duty_cycle_percentage' + BASE_VAL_PATH = '/sys/bus/i2c/devices/17-0066/{0}' + FAN_DUTY_PATH = '/sys/bus/i2c/devices/17-0066/fan_duty_cycle_percentage' #logfile = '' #loglevel = logging.INFO @@ -56,14 +52,14 @@ class FanUtil(object): key1 = fan id index (integer) starting from 1 key2 = fan node index (interger) starting from 1 value = path to fan device file (string) """ - _fan_to_device_path_mapping = {} + _fan_device_path_mapping = {} #fan1_direction #fan1_fault #fan1_present #(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage', - _fan_to_device_node_mapping = { + _fan_device_node_mapping = { (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault', (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction', @@ -83,8 +79,8 @@ class FanUtil(object): (FAN_NUM_6_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan6_direction', } - def _get_fan_to_device_node(self, fan_num, node_num): - return self._fan_to_device_node_mapping[(fan_num, node_num)] + def _get_fan_device_node(self, fan_num, node_num): + return self._fan_device_node_mapping[(fan_num, node_num)] def _get_fan_node_val(self, fan_num, node_num): if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: @@ -95,7 +91,7 @@ def _get_fan_node_val(self, fan_num, node_num): logging.debug('GET. Parameter error. node_num:%d', node_num) return None - device_path = self.get_fan_to_device_path(fan_num, node_num) + device_path = self.get_fan_device_path(fan_num, node_num) try: val_file = open(device_path, 'r') @@ -131,7 +127,7 @@ def _set_fan_node_val(self, fan_num, node_num, val): logging.debug('GET. content is NULL. device_path:%s', device_path) return None - device_path = self.get_fan_to_device_path(fan_num, node_num) + device_path = self.get_fan_device_path(fan_num, node_num) try: val_file = open(device_path, 'w') except IOError as e: @@ -153,8 +149,8 @@ def __init__(self): for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1): for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1): - self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format( - self._fan_to_device_node_mapping[(fan_num, node_num)]) + self._fan_device_path_mapping[(fan_num, node_num)] = fan_path.format( + self._fan_device_node_mapping[(fan_num, node_num)]) def get_num_fans(self): return self.FAN_NUM_ON_MAIN_BROAD @@ -169,20 +165,17 @@ def get_idx_node_start(self): return self.FAN_NODE_FAULT_IDX_OF_MAP def get_size_node_map(self): - return len(self._fan_to_device_node_mapping) + return len(self._fan_device_node_mapping) def get_size_path_map(self): - return len(self._fan_to_device_path_mapping) + return len(self._fan_device_path_mapping) - def get_fan_to_device_path(self, fan_num, node_num): - return self._fan_to_device_path_mapping[(fan_num, node_num)] + def get_fan_device_path(self, fan_num, node_num): + return self._fan_device_path_mapping[(fan_num, node_num)] def get_fan_fault(self, fan_num): return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) - #def get_fan_speed(self, fan_num): - # return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP) - def get_fan_dir(self, fan_num): return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) @@ -198,28 +191,18 @@ def get_fan_duty_cycle(self): val_file.close() return int(content) - #self._get_fan_node_val(fan_num, self.FAN_NODE_DUTY_IDX_OF_MAP) -#static u32 reg_val_to_duty_cycle(u8 reg_val) -#{ -# reg_val &= FAN_DUTY_CYCLE_REG_MASK; -# return ((u32)(reg_val+1) * 625 + 75)/ 100; -#} -# + def set_fan_duty_cycle(self, val): - try: fan_file = open(self.FAN_DUTY_PATH, 'r+') except IOError as e: print "Error: unable to open file: %s" % str(e) return False - #val = ((val + 1 ) * 625 +75 ) / 100 + fan_file.write(str(val)) fan_file.close() return True - - #def get_fanr_fault(self, fan_num): - # return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP) - + def get_fanr_speed(self, fan_num): return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP) @@ -232,20 +215,4 @@ def get_fan_status(self, fan_num): logging.debug('GET. FAN fault. fan_num, %d', fan_num) return False - #if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0: - # logging.debug('GET. FANR fault. fan_num, %d', fan_num) - # return False - - return True -#def main(): -# fan = FanUtil() -# -# print 'get_size_node_map : %d' % fan.get_size_node_map() -# print 'get_size_path_map : %d' % fan.get_size_path_map() -# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): -# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1): -# print fan.get_fan_to_device_path(x, y) -# -#if __name__ == '__main__': -# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/thermalutil.py index 00c9950d52b6..abbc5e819a8a 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/thermalutil.py +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/classes/thermalutil.py @@ -1,24 +1,22 @@ #!/usr/bin/env python +# Copyright (c) 2019 Edgecore Networks Corporation # -# Copyright (C) 2017 Accton Technology Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# # ------------------------------------------------------------------ # HISTORY: # mm/dd/yyyy (A.D.) -# 12/18/2018:Jostar craete for as9716_32d +# 8/27/2019:Jostar craete for as9716_32d # ------------------------------------------------------------------ try: @@ -34,38 +32,29 @@ class ThermalUtil(object): """Platform-specific ThermalUtil class""" THERMAL_NUM_MAX = 8 - THERMAL_NUM_1_IDX = 1 # 1_ON_MAIN_BROAD. LM75 - THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75 - THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75 - THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75 - THERMAL_NUM_5_IDX = 5 # 5_ON_MAIN_BROAD. LM75 - THERMAL_NUM_6_IDX = 6 # 6_ON_MAIN_BROAD. LM75 - THERMAL_NUM_7_IDX = 7 # 7_ON_MAIN_BROAD. LM75 - THERMAL_NUM_8_IDX = 8 # 8_ON_MAIN_BROAD. LM75 - + THERMAL_NUM_1_IDX = 1 # 1~7 are mainboard thermal sensors + THERMAL_NUM_2_IDX = 2 + THERMAL_NUM_3_IDX = 3 + THERMAL_NUM_4_IDX = 4 + THERMAL_NUM_5_IDX = 5 + THERMAL_NUM_6_IDX = 6 + THERMAL_NUM_7_IDX = 7 # CPU core + THERMAL_NUM_8_IDX = 8 + """ Dictionary where key1 = thermal id index (integer) starting from 1 value = path to fan device file (string) """ #_thermal_to_device_path_mapping = {} - - _thermal_to_device_node_mapping = { - THERMAL_NUM_1_IDX: ['18', '48'], - THERMAL_NUM_2_IDX: ['18', '49'], - THERMAL_NUM_3_IDX: ['18', '4a'], - THERMAL_NUM_4_IDX: ['18', '4b'], - THERMAL_NUM_5_IDX: ['18', '4c'], - THERMAL_NUM_6_IDX: ['18', '4e'], - THERMAL_NUM_7_IDX: ['18', '4f'], - } + thermal_sysfspath ={ THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-0048/hwmon/hwmon*/temp1_input"], THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/18-0049/hwmon/hwmon*/temp1_input"], - THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/18-004a/hwmon/hwmon*/temp1_input"], - THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon*/temp1_input"], - THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/18-004c/hwmon/hwmon*/temp1_input"], - THERMAL_NUM_6_IDX: ["/sys/bus/i2c/devices/18-004e/hwmon/hwmon*/temp1_input"], - THERMAL_NUM_7_IDX: ["/sys/bus/i2c/devices/18-004f/hwmon/hwmon*/temp1_input"], - THERMAL_NUM_8_IDX: ["/sys/class/hwmon/hwmon0/temp1_input"], + THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/18-004a/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/18-004c/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_5_IDX: ["/sys/bus/i2c/devices/18-004e/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_6_IDX: ["/sys/bus/i2c/devices/18-004f/hwmon/hwmon*/temp1_input"], + THERMAL_NUM_7_IDX: ["/sys/class/hwmon/hwmon0/temp1_input"], + THERMAL_NUM_8_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon*/temp1_input"], } #def __init__(self): @@ -75,7 +64,7 @@ def _get_thermal_val(self, thermal_num): logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) return None - device_path = self.get_thermal_to_device_path(thermal_num) + device_path = self.get_thermal_path(thermal_num) for filename in glob.glob(device_path): try: val_file = open(filename, 'r') @@ -97,39 +86,17 @@ def _get_thermal_val(self, thermal_num): return 0 def get_num_thermals(self): - return self.THERMAL_NUM_MAX - - def get_idx_thermal_start(self): - return self.THERMAL_NUM_1_IDX - - def get_size_node_map(self): - return len(self._thermal_to_device_node_mapping) + return self.THERMAL_NUM_MAX def get_size_path_map(self): return len(self.thermal_sysfspath) - def get_thermal_to_device_path(self, thermal_num): + def get_thermal_path(self, thermal_num): return self.thermal_sysfspath[thermal_num][0] - - def get_thermal_temp(self): - return (self._get_thermal_node_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_node_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_node_val(self.THERMAL_NUM_3_IDX)) + def main(): - thermal = ThermalUtil() - print "termal1=%d" %thermal._get_thermal_val(1) - print "termal2=%d" %thermal._get_thermal_val(2) - print "termal3=%d" %thermal._get_thermal_val(3) - print "termal4=%d" %thermal._get_thermal_val(4) - print "termal5=%d" %thermal._get_thermal_val(5) - print "termal7=%d" %thermal._get_thermal_val(6) - print "termal8=%d" %thermal._get_thermal_val(7) - print "termal9=%d" %thermal._get_thermal_val(8) - -# -# print 'get_size_node_map : %d' % thermal.get_size_node_map() -# print 'get_size_path_map : %d' % thermal.get_size_path_map() -# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1): -# print thermal.get_thermal_to_device_path(x) -# + thermal = ThermalUtil() + if __name__ == '__main__': main() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py index f80c1223a83c..3752161d3ebc 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as9716-32d/utils/accton_as9716_32d_monitor.py @@ -1,28 +1,27 @@ #!/usr/bin/env python +# -*- coding: utf-8 -* +# Copyright (c) 2019 Edgecore Networks Corporation # -# Copyright (C) 2017 Accton Technology Corporation +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. # -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see . - -# ------------------------------------------------------------------ +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# # HISTORY: # mm/dd/yyyy (A.D.)# -# 12/19/2018:Jostar create for as9716_32d thermal plan +# 8/27/2019:Jostar create for as9716_32d thermal plan # ------------------------------------------------------------------ try: import os + import commands import sys, getopt import subprocess import click @@ -41,31 +40,11 @@ # Deafults VERSION = '1.0' -FUNCTION_NAME = '/usr/local/bin/accton_as9716_32x_monitor' +FUNCTION_NAME = '/usr/local/bin/accton_as9716_32d_monitor' global log_file global log_level - -# Air Flow Front to Back : -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=38C : Keep 37.5%(0x04) Fan speed -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 38C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 46C : Change Fan speed from 62.5%(0x08) to 100%(0x0E) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 58C : Send alarm message -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 66C : Shut down system -# One Fan fail : Change Fan speed to 100%(0x0E) - - -# Air Flow Back to Front : -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 <=34C : Keep 37.5%(0x04) Fan speed -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 34C : Change Fan speed from 37.5%(0x04) to 62.5%(0x08) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 44C : Change Fan speed from 62.5%(0x08) to 100%(0x0E) -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 59C : Send alarm message -# (Thermal sensor_LM75_4A + Thermal sensor_LM75_CPU) /2 > 67C : Shut down system -# One Fan fail: Change Fan speed to 100%(0x0E) -# sensor_LM75_CPU == sensor_LM75_4B - - class switch(object): def __init__(self, value): self.value = value @@ -87,20 +66,217 @@ def match(self, *args): return False -fan_policy_state=1 + +# Read fanN_direction=1: The air flow of Fan6 is “AFI-Back to Front” +# 0: The air flow of Fan6 is “AFO-Front to back” +# +# Thermal policy: +# a.Defaut fan duty_cycle=100% +# b.One fan fail, set to fan duty_cycle=100% +# 1.For AFI: +# Default fan duty_cycle will be 100%(fan_policy_state=LEVEL_FAN_MAX). +# If all below case meet with, set to 75%(LEVEL_FAN_MID). +# MB board +# LM75-1(0X48)<=57 +# LM75-2(0X49)<=47.3 +# LM75-3(0X4A)<=45 +# LM75-4(0X4C)<=45.1 +# LM75-5(0X4E)<=40.75 +# LM75-6(0X4F)<=42.1 +# CPU board +# Core<=44 +# LM75-1(0X4B)<=35 + +# When fan_policy_state=LEVEL_FAN_MID, meet with below case, Fan duty_cycle will be 100%(LEVEL_FAN_DAX) +# (MB board) +# LM75-1(0X48)>=61.5 +# LM75-2(0X49)>=51.5 +# LM75-3(0X4A)>=49.4 +# LM75-4(0X4C)>=49.4 +# LM75-5(0X4E)>=45.1 +# LM75-6(0X4F)>=46.75 +# (CPU board) +# Core>=48 +# LM75-1(0X4B)>=38.5 + +# 2. For AFO: +# At default, FAN duty_cycle was 100%(LEVEL_FAN_MAX). If all below case meet with, set to 75%(LEVEL_FAN_MID). +# (MB board) +# LM75-1(0X48)<=59 +# LM75-2(0X49)<=53.5 +# LM75-3(0X4A)<=55.3 +# LM75-4(0X4C)<=50.3 +# LM75-5(0X4E)<=50 +# LM75-6(0X4F)<=52.5 +# (CPU board) +# Core<=59 +# LM75-1(0X4B)<=41.1 + +# When FAN duty_cycle was 75%(LEVEL_FAN_MID). If all below case meet with, set to 50%(LEVEL_FAN_DEF). +# (MB board) +# LM75-1(0X48)<=55.8 +# LM75-2(0X49)<=50.5 +# LM75-3(0X4A)<=51.1 +# LM75-4(0X4C)<=47.6 +# LM75-5(0X4E)<=45.75 +# LM75-6(0X4F)<=50.1 +# (CPU board) +# Core<=57 +# LM75-1(0X4B)<=36.6 + +# When fan_speed 50%(LEVEL_FAN_DEF). +# Meet with below case, Fan duty_cycle will be 75%(LEVEL_FAN_MID) +# (MB board) +# LM75-1(0X48)>=70 +# LM75-2(0X49)>=66 +# LM75-3(0X4A)>=68 +# LM75-4(0X4C)>=62 +# LM75-5(0X4E)>=62 +# LM75-6(0X4F)>=67 +# (CPU board) +# Core>=77 +# LM75-1(0X4B)>=50 + +# When FAN duty_cycle was 75%(LEVEL_FAN_MID). If all below case meet with, set to 100%(LEVEL_FAN_MAX). +# (MB board) +# LM75-1(0X48)>=67 +# LM75-2(0X49)>=62.5 +# LM75-3(0X4A)>=65 +# LM75-4(0X4C)>=59 +# LM75-5(0X4E)>=58.5 +# LM75-6(0X4F)>=63 + +# (CPU board) +# Core >=69 +# LM75-1(0X4B)>=49 + + +#Yellow Alarm +#MB board +#LM75-1(0X48)>=68 +#LM75-2(0X49)>=64 +#LM75-3(0X4A)>=65 +#LM75-4(0X4C)>=61 +#LM75-5(0X4E)>=60 +#LM75-6(0X4F)>=64 +#CPU Board +#Core>=70 +#LM75-1(0X4B)>=68 + +#Red Alarm +#MB board +#LM75-1(0X48)>=72 +#LM75-2(0X49)>=68 +#LM75-3(0X4A)>=69 +#LM75-4(0X4C)>=65 +#LM75-5(0X4E)>=64 +#LM75-6(0X4F)>=68 +#CPU Board +#Core>=74 +#LM75-1(0X4B)>=72 + +#Shut down +#MB board +#LM75-1(0X48)>=77 +#LM75-2(0X49)>=73 +#LM75-3(0X4A)>=74 +#LM75-4(0X4C)>=70 +#LM75-5(0X4E)>=69 +#LM75-6(0X4F)>=73 +#CPU Board +#Core>=79 +#LM75-1(0X4B)>=77 + + + +def power_off_dut(): + cmd_str="i2cset -y -f 19 0x60 0x60 0x10" + status, output = commands.getstatusoutput(cmd_str) + return status + +#If only one PSU insert(or one of PSU pwoer fail), and watt >800w. Must let DUT fan pwm >= 75% in AFO. +#Because the psu temp is high. +# Return 1: full load +# Return 0: Not full load +def check_psu_loading(): + psu_power_status=[1, 1] + + psu_power_good = { + 2: "/sys/bus/i2c/devices/10-0051/psu_power_good", + 1: "/sys/bus/i2c/devices/9-0050/psu_power_good", + } + psu_power_in = { + 2: "/sys/bus/i2c/devices/10-0059/psu_p_in", + 1: "/sys/bus/i2c/devices/9-0058/psu_p_in", + } + psu_power_out = { + 2: "/sys/bus/i2c/devices/10-0059/psu_p_out", + 1: "/sys/bus/i2c/devices/9-0058/psu_p_out", + } + + check_psu_watt=0 + for i in range(1,3): + node = psu_power_good[i] + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return None + + psu_power_status[i-1]=int(status) + if status==0: + check_psu_watt=1 + + if check_psu_watt: + for i in range(1,3): + if psu_power_status[i-1]==1: + #check watt + node = psu_power_in[i] + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return None + + psu_p_in= int(status) + if psu_p_in/1000 > 800: + return True + + node = psu_power_out[i] + try: + with open(node, 'r') as power_status: + status = int(power_status.read()) + except IOError: + return None + psu_p_out= int(status) + if psu_p_out/1000 > 800: + return True + else: + return False + + + return False + +fan_policy_state=0 +fan_policy_alarm=0 +send_yellow_alarm=0 +send_red_alarm=0 fan_fail=0 -alarm_state = 0 #0->default or clear, 1-->alarm detect +count_check=0 + test_temp = 0 -test_temp_list = [0, 0, 0, 0, 0, 0] +test_temp_list = [0, 0, 0, 0, 0, 0, 0, 0] temp_test_data=0 +test_temp_revert=0 + # Make a class we can use to capture stdout and sterr in the log class device_monitor(object): # static temp var temp = 0 - new_pwm = 0 - pwm=0 - ori_pwm = 0 - default_pwm=0x4 + new_duty_cycle = 0 + duty_cycle=0 + ori_duty_cycle = 0 + def __init__(self, log_file, log_level): """Needs a logger and a logger level.""" @@ -123,179 +299,197 @@ def __init__(self, log_file, log_level): sys_handler = handler = logging.handlers.SysLogHandler(address = '/dev/log') sys_handler.setLevel(logging.WARNING) logging.getLogger('').addHandler(sys_handler) - #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) - def get_state_from_fan_policy(self, temp, policy): - state=0 - - logging.debug('temp=%d', temp) - for i in range(0, len(policy)): - #logging.debug('policy[%d][0]=%d, policy[%d][1]=%d, policy[%d][2]=%d', i,policy[i][0],i, policy[i][1], i, policy[i][2]) - if temp > policy[i][2]: - if temp <= policy[i][3]: - state =i - logging.debug ('temp=%d >= policy[%d][2]=%d, temp=%d < policy[%d][3]=%d' , temp, i, policy[i][2], temp, i, policy[i][3]) - logging.debug ('fan_state=%d', state) - break - - return state - def manage_fans(self): global fan_policy_state + global fan_policy_alarm + global send_yellow_alarm + global send_red_alarm global fan_fail + global count_check global test_temp - global test_temp_list - global alarm_state + global test_temp_list global temp_test_data - - LEVEL_FAN_DEF=0 - LEVEL_FAN_MID=1 - LEVEL_FAN_MAX=2 - LEVEL_TEMP_HIGH=3 - LEVEL_TEMP_CRITICAL=4 - - - fan_policy_f2b = { - LEVEL_FAN_DEF: [38, 0x4, 0, 38000], - LEVEL_FAN_MID: [63, 0x6, 38000, 46000], - LEVEL_FAN_MAX: [100, 0xE, 46000, 58000], - LEVEL_TEMP_HIGH: [100, 0xE, 58000, 66000], - LEVEL_TEMP_CRITICAL: [100, 0xE, 58000, 200000], + global test_temp_revert + + CHECK_TIMES=3 + + LEVEL_FAN_INIT=0 + LEVEL_FAN_MIN=1 + LEVEL_FAN_MID=2 + LEVEL_FAN_MAX=3 + LEVEL_FAN_DEF=LEVEL_FAN_MAX + LEVEL_FAN_YELLOW_ALARM=4 + LEVEL_FAN_RED_ALARM=5 + LEVEL_FAN_SHUTDOWN=6 + + fan_policy_f2b = { #AFO + LEVEL_FAN_MIN: [50, 0x7], + LEVEL_FAN_MID: [75, 0xb], + LEVEL_FAN_MAX: [100, 0xf] + } + fan_policy_b2f = { #AFI + LEVEL_FAN_MID: [75, 0xb], + LEVEL_FAN_MAX: [100, 0xf] } - fan_policy_b2f = { - LEVEL_FAN_DEF: [38, 0x4, 0, 34000], - LEVEL_FAN_MID: [63, 0x8, 34000, 44000], - LEVEL_FAN_MAX: [100, 0xE, 44000, 59000], - LEVEL_TEMP_HIGH: [100, 0xE, 59000, 67000], - LEVEL_TEMP_CRITICAL: [100, 0xE, 59000, 200000], + + afi_thermal_spec={ + "mid_to_max_temp":[61500, 51500, 49400, 49400, 45100, 46750, 48000, 38500], + "max_to_mid_temp":[57000, 47300, 45000, 45100, 40750, 42100, 44000, 35000] } + afo_thermal_spec={ + "min_to_mid_temp": [70000, 66000, 68000, 62000, 62000, 67000, 77000, 50000], + "mid_to_max_temp": [67000, 62000, 65000, 59000, 58500, 63000, 69000, 49000], + "max_to_mid_temp": [59000, 53500, 55300, 50300, 50000, 52500, 59000, 41100], + "mid_to_min_temp": [55800, 50500, 51100, 47600, 45750, 50100, 57000, 36600], + "max_to_yellow_alarm": [68000, 64000, 65000, 61000, 60000, 64000, 70000, 68000], + "yellow_to_red_alarm": [72000, 68000, 69000, 65000, 64000, 68000, 74000, 72000], + "red_alarm_to_shutdown": [77000, 73000, 74000, 70000, 69000, 73000, 79000, 77000] + } + + thermal_val=[0,0,0,0,0,0,0,0] + max_to_mid=0 + mid_to_min=0 - fan_policy = fan_policy_f2b + fan = FanUtil() + if fan_policy_state==LEVEL_FAN_INIT: + fan_policy_state=LEVEL_FAN_MAX #This is default state + logging.debug("fan_policy_state=LEVEL_FAN_MAX") + return + + count_check=count_check+1 + if count_check < CHECK_TIMES: + return + else: + count_check=0 thermal = ThermalUtil() - fan = FanUtil() - fan_dir=fan.get_fan_dir(1) - if fan_dir == 1: - fan_dri=1 #something wrong, set fan_dir to default val + fan_dir=1 + fan_dir=fan.get_fan_dir(1) + + if fan_dir==1: # AFI + fan_thermal_spec = afi_thermal_spec + fan_policy=fan_policy_b2f + elif fan_dir==0: # AFO + fan_thermal_spec = afo_thermal_spec + fan_policy=fan_policy_f2b else: - fan_policy = fan_policy_b2f + logging.debug( "NULL case") - ori_pwm=fan.get_fan_duty_cycle() - new_pwm=0 - logging.debug('fan_dir=%d, ori_pwm=%d', fan_dir, ori_pwm) - logging.debug('test_temp=%d', test_temp) - if test_temp==0: - temp1 = thermal._get_thermal_val(1) - temp2 = thermal._get_thermal_val(2) - temp3 = thermal._get_thermal_val(3) - temp4 = thermal._get_thermal_val(4) - temp5 = thermal._get_thermal_val(5) + ori_duty_cycle=fan.get_fan_duty_cycle() + new_duty_cycle=0 + + if test_temp_revert==0: + temp_test_data=temp_test_data+2000 + else: + temp_test_data=temp_test_data-2000 + + if test_temp==0: + for i in range (thermal.THERMAL_NUM_1_IDX, thermal.THERMAL_NUM_MAX+1): + thermal_val[i-1]=thermal._get_thermal_val(i) else: - temp1 = test_temp_list[0] - temp2 = test_temp_list[1] - temp3 = test_temp_list[2] - temp4 = test_temp_list[3] - temp5 = test_temp_list[4] + for i in range (thermal.THERMAL_NUM_1_IDX, thermal.THERMAL_NUM_MAX+1): + thermal_val[i-1]=test_temp_list[i-1] + thermal_val[i-1]= thermal_val[i-1] + temp_test_data + fan_fail=0 - if temp3==0: - temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75% - logging.debug('lm75_49 detect fail, so set temp_get=50000, let fan to 75%') - elif temp4==0: - temp_get=50000 # if one detect sensor is fail or zero, assign temp=50000, let fan to 75% - logging.debug('lm75_4b detect fail, so set temp_get=50000, let fan to 75%') - else: - temp_get= (temp3 + temp4)/2 # Use (sensor_LM75_4a + sensor_LM75_4b) /2 - ori_state=fan_policy_state - - #temp_test_data=temp_test_data+1000 - #temp_get = temp_get + temp_test_data - #print "Unit test:temp_get=%d"%temp_get + ori_state=fan_policy_state; + current_state=fan_policy_state; + + if fan_dir==1: #AFI + for i in range (0, thermal.THERMAL_NUM_MAX): + if ori_state==LEVEL_FAN_MID: + if thermal_val[i] >= fan_thermal_spec["mid_to_max_temp"][i]: + current_state=LEVEL_FAN_MAX + logging.debug("current_state=LEVEL_FAN_MAX") + break + else: + if (thermal_val[i] <= fan_thermal_spec["max_to_mid_temp"][i]): + max_to_mid=max_to_mid+1 - fan_policy_state=self.get_state_from_fan_policy(temp_get, fan_policy) - #print "temp3=%d"%temp3 - #print "temp4=%d"%temp4 - #print "temp_get=%d"%temp_get + if max_to_mid==thermal.THERMAL_NUM_MAX and fan_policy_state==LEVEL_FAN_MAX: + current_state=LEVEL_FAN_MID + logging.debug("current_state=LEVEL_FAN_MID") + else: #AFO + psu_full_load=check_psu_loading() + for i in range (0, thermal.THERMAL_NUM_MAX): + if ori_state==LEVEL_FAN_MID: + if thermal_val[i] >= fan_thermal_spec["mid_to_max_temp"][i]: + current_state=LEVEL_FAN_MAX + break + else: + if psu_full_load!=True and thermal_val[i] <= fan_thermal_spec["mid_to_min_temp"][i]: + mid_to_min=mid_to_min+1 + elif ori_state==LEVEL_FAN_MIN: + if psu_full_load==True: + current_state=LEVEL_FAN_MID + logging.debug("psu_full_load, set current_state=LEVEL_FAN_MID") + if thermal_val[i] >= fan_thermal_spec["min_to_mid_temp"][i]: + current_state=LEVEL_FAN_MID + + else: + if thermal_val[i] <= fan_thermal_spec["max_to_mid_temp"][i] : + max_to_mid=max_to_mid+1 + if fan_policy_alarm==0: + if thermal_val[i] >= fan_thermal_spec["max_to_yellow_alarm"][i]: + if send_yellow_alarm==0: + logging.warning('Alarm-Yellow for temperature high is detected') + fan_policy_alarm=LEVEL_FAN_YELLOW_ALARM + send_yellow_alarm=1 + elif fan_policy_alarm==LEVEL_FAN_YELLOW_ALARM: + if thermal_val[i] >= fan_thermal_spec["yellow_to_red_alarm"][i]: + if send_red_alarm==0: + logging.warning('Alarm-Red for temperature high is detected') + fan_policy_alarm=LEVEL_FAN_RED_ALARM + send_red_alarm=1 + elif fan_policy_alarm==LEVEL_FAN_RED_ALARM: + if thermal_val[i] >= fan_thermal_spec["red_alarm_to_shutdown"][i]: + logging.critical('Alarm-Critical for temperature high is detected, shutdown DUT') + fan_policy_alarm=LEVEL_FAN_SHUTDOWN + time.sleep(2) + power_off_dut() - logging.debug('lm75_48=%d, lm75_49=%d, lm75_4a=%d, lm_4b=%d, lm_4b=%d', temp1,temp2,temp3,temp4,temp5) - logging.debug('ori_state=%d, fan_policy_state=%d', ori_state, fan_policy_state) - new_pwm = fan_policy[fan_policy_state][0] - if fan_fail==0: - logging.debug('new_fan_cycle=%d', new_pwm) - - if fan_fail==0: - if new_pwm!=ori_pwm: - fan.set_fan_duty_cycle(new_pwm) - logging.info('Set fan speed from %d to %d', ori_pwm, new_pwm) - + if max_to_mid==thermal.THERMAL_NUM_MAX and ori_state==LEVEL_FAN_MAX: + current_state=LEVEL_FAN_MID + if fan_policy_alarm!=0: + logging.warning('Alarm for temperature high is cleared') + fan_policy_alarm=0 + send_yellow_alarm=0 + send_red_alarm=0 + test_temp_revert=0 + logging.debug("current_state=LEVEL_FAN_MID") + + if mid_to_min==thermal.THERMAL_NUM_MAX and ori_state==LEVEL_FAN_MID: + if psu_full_load==0: + current_state=LEVEL_FAN_MIN + logging.debug("current_state=LEVEL_FAN_MIN") + #Check Fan status for i in range (fan.FAN_NUM_1_IDX, fan.FAN_NUM_ON_MAIN_BROAD+1): if fan.get_fan_status(i)==0: - new_pwm=100 - logging.debug('fan_%d fail, set pwm to 100',i) + new_duty_cycle=100 + logging.debug('fan_%d fail, set duty_cycle to 100',i) if test_temp==0: fan_fail=1 - fan.set_fan_duty_cycle(new_pwm) + fan.set_fan_duty_cycle(new_duty_cycle) break else: fan_fail=0 - - #if fan_policy_state == ori_state: - # return True - #else: - new_state = fan_policy_state - - #logging.warning('Temperature high alarm testing') - if ori_state==LEVEL_FAN_DEF: - if new_state==LEVEL_TEMP_HIGH: - if alarm_state==0: - logging.warning('Alarm for temperature high is detected') - alarm_state=1 - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected, reboot DUT') - time.sleep(2) - os.system('reboot') - if ori_state==LEVEL_FAN_MID: - if new_state==LEVEL_TEMP_HIGH: - if alarm_state==0: - logging.warning('Alarm for temperature high is detected') - alarm_state=1 - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected') - time.sleep(2) - os.system('reboot') - if ori_state==LEVEL_FAN_MAX: - if new_state==LEVEL_TEMP_HIGH: - if alarm_state==0: - logging.warning('Alarm for temperature high is detected') - alarm_state=1 - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected') - time.sleep(2) - os.system('reboot') - if alarm_state==1: - if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm - logging.warning('Alarm for temperature high is cleared') - alarm_state=0 - if ori_state==LEVEL_TEMP_HIGH: - if new_state==LEVEL_TEMP_CRITICAL: - logging.critical('Alarm for temperature critical is detected') - time.sleep(2) - os.system('reboot') - if new_state <= LEVEL_FAN_MID: - logging.warning('Alarm for temperature high is cleared') - alarm_state=0 - if new_state <= LEVEL_FAN_MAX: - if temp_get < (fan_policy[3][0] - 5000): #below 65 C, clear alarm - logging.warning('Alarm for temperature high is cleared') - alarm_state=0 - if ori_state==LEVEL_TEMP_CRITICAL: - if new_state <= LEVEL_FAN_MAX: - logging.warning('Alarm for temperature critical is cleared') - + + if current_state!=ori_state: + fan_policy_state=current_state + new_duty_cycle=fan_policy[current_state][0] + logging.debug("fan_policy_state=%d, new_duty_cycle=%d", fan_policy_state, new_duty_cycle) + if new_duty_cycle!=ori_duty_cycle and fan_fail==0: + fan.set_fan_duty_cycle(new_duty_cycle) + return True + if new_duty_cycle==0 and fan_fail==0: + fan.set_fan_duty_cycle(FAN_DUTY_CYCLE_MAX) + return True def main(argv): @@ -318,26 +512,25 @@ def main(argv): log_file = arg if sys.argv[1]== '-t': - if len(sys.argv)!=7: - print "temp test, need input six temp" + if len(sys.argv)!=10: + print "temp test, need input 8 temp" return 0 - i=0 - for x in range(2, 7): + for x in range(2, 10): test_temp_list[i]= int(sys.argv[x])*1000 i=i+1 - test_temp = 1 + test_temp = 1 log_level = logging.DEBUG - print test_temp_list + print test_temp_list fan = FanUtil() - fan.set_fan_duty_cycle(38) - print "set default fan speed to 37.5%" + fan.set_fan_duty_cycle(100) monitor = device_monitor(log_file, log_level) # Loop forever, doing something useful hopefully: while True: - #monitor.manage_fans() - time.sleep(5) + monitor.manage_fans() + time.sleep(10) + if __name__ == '__main__': main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-arista b/platform/broadcom/sonic-platform-modules-arista index 8c45a8e11153..73dd2e0fe144 160000 --- a/platform/broadcom/sonic-platform-modules-arista +++ b/platform/broadcom/sonic-platform-modules-arista @@ -1 +1 @@ -Subproject commit 8c45a8e111534f9d4337d3552eaf08881fb19d30 +Subproject commit 73dd2e0fe144e2bb6778d39d3e051c597bb1c9d8 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init index 99d0aab3fd61..1e124565a41d 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.init @@ -141,6 +141,8 @@ start) sleep 0.1 done + /bin/sh /usr/local/bin/platform_api_mgnt.sh init + echo "done." ;; diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install index b25d47022b08..8570fa1eae84 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.install @@ -1,3 +1,5 @@ dx010/scripts/dx010_check_qsfp.sh usr/local/bin dx010/cfg/dx010-modules.conf etc/modules-load.d dx010/systemd/platform-modules-dx010.service lib/systemd/system +dx010/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_seastone-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst index baff704171c7..15243c935ca3 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-dx010.postinst @@ -1,3 +1,6 @@ depmod -a systemctl enable platform-modules-dx010.service systemctl start platform-modules-dx010.service + +/usr/local/bin/platform_api_mgnt.sh install + diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init index 6c2d4483ac9d..1dc0ea5cfeeb 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.init @@ -69,6 +69,8 @@ start) echo "both" > /sys/devices/platform/e1031.smc/SFP/modabs_trig echo 0 > /sys/devices/platform/e1031.smc/SFP/modabs_mask + /bin/sh /usr/local/bin/platform_api_mgnt.sh init + echo "done." ;; diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install index 312e9c78a5e7..df78b7a34ea4 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.install @@ -3,3 +3,5 @@ haliburton/systemd/platform-modules-haliburton.service lib/systemd/system haliburton/script/fancontrol.sh etc/init.d services/fancontrol/fancontrol.service lib/systemd/system services/fancontrol/fancontrol usr/local/bin +haliburton/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_e1031-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.postinst index ac05d40d702f..e62799bd591c 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-haliburton.postinst @@ -3,4 +3,6 @@ systemctl enable platform-modules-haliburton.service systemctl enable fancontrol.service systemctl start platform-modules-haliburton.service -systemctl start fancontrol.service \ No newline at end of file +systemctl start fancontrol.service + +/usr/local/bin/platform_api_mgnt.sh install diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index 5086302b70b2..6f35290bce26 100755 --- a/platform/broadcom/sonic-platform-modules-cel/debian/rules +++ b/platform/broadcom/sonic-platform-modules-cel/debian/rules @@ -13,6 +13,9 @@ MODULE_DIRS:= dx010 haliburton override_dh_auto_build: (for mod in $(MODULE_DIRS); do \ make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + cd $(MOD_SRC_DIR); \ done) override_dh_auto_install: diff --git a/platform/broadcom/sonic-platform-modules-cel/dx010/setup.py b/platform/broadcom/sonic-platform-modules-cel/dx010/setup.py new file mode 100644 index 000000000000..8183788184a7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/dx010/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'celestica' +HW_SKU = 'x86_64-cel_seastone-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Celestica Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Wirut Getbamrung', + maintainer_email='wgetbumr@celestica.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-cel/haliburton/setup.py b/platform/broadcom/sonic-platform-modules-cel/haliburton/setup.py new file mode 100644 index 000000000000..17056855106e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/haliburton/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'celestica' +HW_SKU = 'x86_64-cel_e1031-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Celestica Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Wirut Getbamrung', + maintainer_email='wgetbumr@celestica.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh new file mode 100755 index 000000000000..e1d330357894 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +PREV_REBOOT_CAUSE="/host/reboot-cause/" +DEVICE="/usr/share/sonic/device" +PLATFORM=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) +FILES=$DEVICE/$PLATFORM/api_files + +install() { + # Install sonic-platform package + if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl ]; then + pip install $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl + fi +} + +init() { + # mount needed files for sonic-platform package + mkdir -p $FILES + + mkdir -p $FILES/reboot-cause + mount -B $PREV_REBOOT_CAUSE $FILES/reboot-cause +} + +deinit() { + # deinit sonic-platform package + umount -f $PREV_REBOOT_CAUSE $FILES/reboot-cause >/dev/null 2>/dev/null +} + +uninstall() { + # Uninstall sonic-platform package + pip uninstall -y sonic-platform >/dev/null 2>/dev/null +} + +case "$1" in +install | uninstall | init | deinit) + $1 + ;; +*) + echo "Usage: $0 {install|uninstall|init|deinit}" + exit 1 + ;; +esac diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install index b9b6abbb35e0..b0c27702cb4a 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s6100.install @@ -12,3 +12,4 @@ s6100/scripts/platform_watchdog_disable.sh usr/local/bin s6100/scripts/sensors usr/bin s6100/systemd/platform-modules-s6100.service etc/systemd/system s6100/systemd/s6100-lpc-monitor.service etc/systemd/system +tools/flashrom/flashrom usr/local/bin/ diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.init b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.init index cc83662e7746..fb0b68117972 100755 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.init +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-z9264f.init @@ -22,7 +22,7 @@ start) ;; stop) - /usr/local/bin/z9100_platform.sh deinit + /usr/local/bin/z9264f_platform.sh deinit echo "done." ;; diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py index a625a796ef53..477d6b787b79 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/chassis.py @@ -9,6 +9,8 @@ try: import os + import time + import datetime from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.sfp import Sfp except ImportError as e: @@ -22,16 +24,19 @@ class Chassis(ChassisBase): MAILBOX_DIR = "/sys/devices/platform/dell-s6000-cpld.0" + sfp_control = "" + PORT_START = 0 + PORT_END = 0 reset_reason_dict = {} reset_reason_dict[0xe] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE reset_reason_dict[0x6] = ChassisBase.REBOOT_CAUSE_NON_HARDWARE def __init__(self): # Initialize SFP list - PORT_START = 0 - PORT_END = 31 + self.PORT_START = 0 + self.PORT_END = 31 EEPROM_OFFSET = 20 - PORTS_IN_BLOCK = (PORT_END + 1) + PORTS_IN_BLOCK = (self.PORT_END + 1) # sfp.py will read eeprom contents and retrive the eeprom data. # It will also provide support sfp controls like reset and setting @@ -39,12 +44,16 @@ def __init__(self): # We pass the eeprom path and sfp control path from chassis.py # So that sfp.py implementation can be generic to all platforms eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" - sfp_control = "/sys/devices/platform/dell-s6000-cpld.0/" + self.sfp_control = "/sys/devices/platform/dell-s6000-cpld.0/" + for index in range(0, PORTS_IN_BLOCK): eeprom_path = eeprom_base.format(index + EEPROM_OFFSET) - sfp_node = Sfp(index, 'QSFP', eeprom_path, sfp_control, index) + sfp_node = Sfp(index, 'QSFP', eeprom_path, self.sfp_control, index) self._sfp_list.append(sfp_node) + # Get Transceiver status + self.modprs_register = self._get_transceiver_status() + def get_register(self, reg_name): rv = 'ERR' mb_reg_file = self.MAILBOX_DIR+'/'+reg_name @@ -76,3 +85,69 @@ def get_reboot_cause(self): return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") + def _get_transceiver_status(self): + presence_ctrl = self.sfp_control + 'qsfp_modprs' + try: + reg_file = open(presence_ctrl) + + except IOError as e: + return False + + content = reg_file.readline().rstrip() + reg_file.close() + + return int(content, 16) + + def get_transceiver_change_event(self, timeout=0): + """ + Returns a dictionary containing sfp changes which have + experienced a change at chassis level + """ + start_time = time.time() + port_dict = {} + port = self.PORT_START + forever = False + + if timeout == 0: + forever = True + elif timeout > 0: + timeout = timeout / float(1000) # Convert to secs + else: + return False, {} + end_time = start_time + timeout + + if (start_time > end_time): + return False, {} # Time wrap or possibly incorrect timeout + + while (timeout >= 0): + # Check for OIR events and return updated port_dict + reg_value = self._get_transceiver_status() + if (reg_value != self.modprs_register): + changed_ports = (self.modprs_register ^ reg_value) + while (port >= self.PORT_START and port <= self.PORT_END): + # Mask off the bit corresponding to our port + mask = (1 << port) + if (changed_ports & mask): + # ModPrsL is active low + if reg_value & mask == 0: + port_dict[port] = '1' + else: + port_dict[port] = '0' + port += 1 + + # Update reg value + self.modprs_register = reg_value + return True, port_dict + + if forever: + time.sleep(1) + else: + timeout = end_time - time.time() + if timeout >= 1: + time.sleep(1) # We poll at 1 second granularity + else: + if timeout > 0: + time.sleep(timeout) + return True, {} + return False, {} + diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py deleted file mode 120000 index 84af7963bb3d..000000000000 --- a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py +++ /dev/null @@ -1 +0,0 @@ -../../s6100/sonic_platform/sfp.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py new file mode 100644 index 000000000000..a334aa7a7f97 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s6000/sonic_platform/sfp.py @@ -0,0 +1,876 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +PAGE_OFFSET = 0 +KEY_OFFSET = 1 +KEY_WIDTH = 2 +FUNC_NAME = 3 + +INFO_OFFSET = 128 +DOM_OFFSET = 0 +DOM_OFFSET1 = 384 + +cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)', + 'Length OM1(m)', 'Length Cable Assembly(m)') + +compliance_code_tup = ( + '10/40G Ethernet Compliance Code', + 'SONET Compliance codes', + 'SAS/SATA compliance codes', + 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', + 'Fibre Channel Speed') + +info_dict_keys = ['type', 'hardwarerev', 'serialnum', + 'manufacturename', 'modelname', 'Connector', + 'encoding', 'ext_identifier', 'ext_rateselect_compliance', + 'cable_type', 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'vendor_date', 'vendor_oui'] + +dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', + 'power_lpmode', 'tx_disable', 'tx_disable_channel', + 'temperature', 'voltage', 'rx1power', + 'rx2power', 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', 'tx3bias', + 'tx4bias', 'tx1power', 'tx2power', + 'tx3power', 'tx4power'] + +threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +sff8436_parser = { + 'reset_status': [DOM_OFFSET, 2, 1, 'parse_dom_status_indicator'], + 'rx_los': [DOM_OFFSET, 3, 1, 'parse_dom_tx_rx_los'], + 'tx_fault': [DOM_OFFSET, 4, 1, 'parse_dom_tx_fault'], + 'tx_disable': [DOM_OFFSET, 86, 1, 'parse_dom_tx_disable'], + 'power_lpmode': [DOM_OFFSET, 93, 1, 'parse_dom_power_control'], + 'power_override': [DOM_OFFSET, 93, 1, 'parse_dom_power_control'], + 'Temperature': [DOM_OFFSET, 22, 2, 'parse_temperature'], + 'Voltage': [DOM_OFFSET, 26, 2, 'parse_voltage'], + 'ChannelMonitor': [DOM_OFFSET, 34, 16, 'parse_channel_monitor_params'], + + 'cable_type': [INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'cable_length': [INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'Connector': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'type': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'encoding': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'ext_identifier': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'ext_rateselect_compliance': + [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'nominal_bit_rate': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'specification_compliance': + [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'manufacturename': [INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'vendor_oui': [INFO_OFFSET, 37, 3, 'parse_vendor_oui'], + 'modelname': [INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardwarerev': [INFO_OFFSET, 56, 2, 'parse_vendor_rev'], + 'serialnum': [INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'vendor_date': [INFO_OFFSET, 84, 8, 'parse_vendor_date'], + 'ModuleThreshold': [DOM_OFFSET1, 128, 24, 'parse_module_threshold_values'], + 'ChannelThreshold': [DOM_OFFSET1, 176, 16, 'parse_channel_threshold_values'], +} + + +class Sfp(SfpBase): + """ + DELLEMC Platform-specific Sfp class + """ + + def __init__(self, index, sfp_type, eeprom_path, + sfp_control, sfp_ctrl_idx): + SfpBase.__init__(self) + self.sfp_type = sfp_type + self.index = index + self.eeprom_path = eeprom_path + self.sfp_control = sfp_control + self.sfp_ctrl_idx = sfp_ctrl_idx + self.sfpInfo = sff8436InterfaceId() + self.sfpDomInfo = sff8436Dom() + + def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): + eeprom_raw = [] + try: + eeprom = 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: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _get_eeprom_data(self, eeprom_key): + eeprom_data = None + page_offset = None + + if (self.sfpInfo is None): + return None + + page_offset = sff8436_parser[eeprom_key][PAGE_OFFSET] + eeprom_data_raw = self._read_eeprom_bytes( + self.eeprom_path, + (sff8436_parser[eeprom_key][PAGE_OFFSET] + + sff8436_parser[eeprom_key][KEY_OFFSET]), + sff8436_parser[eeprom_key][KEY_WIDTH]) + if (eeprom_data_raw is not None): + # Offset 128 is used to retrieve sff8436InterfaceId Info + # Offset 0 is used to retrieve sff8436Dom Info + if (page_offset == 128): + eeprom_data = getattr( + self.sfpInfo, sff8436_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + else: + eeprom_data = getattr( + self.sfpDomInfo, sff8436_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + + return eeprom_data + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + """ + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(info_dict_keys, 'N/A') + + # BaseInformation + iface_data = self._get_eeprom_data('type') + if (iface_data is not None): + connector = iface_data['data']['Connector']['value'] + encoding = iface_data['data']['EncodingCodes']['value'] + ext_id = iface_data['data']['Extended Identifier']['value'] + rate_identifier = iface_data['data']['RateIdentifier']['value'] + identifier = iface_data['data']['type']['value'] + bit_rate = str( + iface_data['data']['Nominal Bit Rate(100Mbs)']['value']) + + for key in compliance_code_tup: + if key in iface_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value'] + for key in cable_length_tup: + if key in iface_data['data']: + cable_type = key + cable_length = str(iface_data['data'][key]['value']) + else: + return None + + # Vendor Date + vendor_date_data = self._get_eeprom_data('vendor_date') + if (vendor_date_data is not None): + vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + else: + return None + + # Vendor Name + vendor_name_data = self._get_eeprom_data('manufacturename') + if (vendor_name_data is not None): + vendor_name = vendor_name_data['data']['Vendor Name']['value'] + else: + return None + + # Vendor OUI + vendor_oui_data = self._get_eeprom_data('vendor_oui') + if (vendor_oui_data is not None): + vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] + else: + return None + + # Vendor PN + vendor_pn_data = self._get_eeprom_data('modelname') + if (vendor_pn_data is not None): + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + else: + return None + + # Vendor Revision + vendor_rev_data = self._get_eeprom_data('hardwarerev') + if (vendor_rev_data is not None): + vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] + else: + return None + + # Vendor Serial Number + vendor_sn_data = self._get_eeprom_data('serialnum') + if (vendor_sn_data is not None): + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + else: + return None + + # Fill The Dictionary and return + transceiver_info_dict['type'] = identifier + transceiver_info_dict['hardwarerev'] = vendor_rev + transceiver_info_dict['serialnum'] = vendor_sn + transceiver_info_dict['manufacturename'] = vendor_name + transceiver_info_dict['modelname'] = vendor_pn + transceiver_info_dict['Connector'] = connector + transceiver_info_dict['encoding'] = encoding + transceiver_info_dict['ext_identifier'] = ext_id + transceiver_info_dict['ext_rateselect_compliance'] = rate_identifier + transceiver_info_dict['cable_type'] = cable_type + transceiver_info_dict['cable_length'] = cable_length + transceiver_info_dict['nominal_bit_rate'] = bit_rate + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['vendor_date'] = vendor_date + transceiver_info_dict['vendor_oui'] = vendor_oui + + return transceiver_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + """ + transceiver_dom_threshold_dict = {} + transceiver_dom_threshold_dict = dict.fromkeys( + threshold_dict_keys, 'N/A') + + # Module Threshold + module_threshold_data = self._get_eeprom_data('ModuleThreshold') + if (module_threshold_data is not None): + tempHighAlarm = module_threshold_data['data']['TempHighAlarm']['value'] + tempLowAlarm = module_threshold_data['data']['TempLowAlarm']['value'] + tempHighWarn = module_threshold_data['data']['TempHighWarning']['value'] + tempLowWarn = module_threshold_data['data']['TempLowWarning']['value'] + vccHighAlarm = module_threshold_data['data']['VccHighAlarm']['value'] + vccLowAlarm = module_threshold_data['data']['VccLowAlarm']['value'] + vccHighWarn = module_threshold_data['data']['VccHighWarning']['value'] + vccLowWarn = module_threshold_data['data']['VccLowWarning']['value'] + else: + return None + + # Channel Threshold + channel_threshold_data = self._get_eeprom_data('ChannelThreshold') + if (channel_threshold_data is not None): + rxPowerHighAlarm = channel_threshold_data['data']['RxPowerHighAlarm']['value'] + rxPowerLowAlarm = channel_threshold_data['data']['RxPowerLowAlarm']['value'] + rxPowerHighWarn = channel_threshold_data['data']['RxPowerHighWarning']['value'] + rxPowerLowWarn = channel_threshold_data['data']['RxPowerLowWarning']['value'] + txBiasHighAlarm = channel_threshold_data['data']['TxBiasHighAlarm']['value'] + txBiasLowAlarm = channel_threshold_data['data']['TxBiasLowAlarm']['value'] + txBiasHighWarn = channel_threshold_data['data']['TxBiasHighWarning']['value'] + txBiasLowWarn = channel_threshold_data['data']['TxBiasLowWarning']['value'] + else: + return None + + transceiver_dom_threshold_dict['temphighalarm'] = tempHighAlarm + transceiver_dom_threshold_dict['templowalarm'] = tempLowAlarm + transceiver_dom_threshold_dict['temphighwarning'] = tempHighWarn + transceiver_dom_threshold_dict['templowwarning'] = tempLowWarn + transceiver_dom_threshold_dict['vcchighalarm'] = vccHighAlarm + transceiver_dom_threshold_dict['vcclowalarm'] = vccLowAlarm + transceiver_dom_threshold_dict['vcchighwarning'] = vccHighWarn + transceiver_dom_threshold_dict['vcclowwarning'] = vccLowWarn + transceiver_dom_threshold_dict['rxpowerhighalarm'] = rxPowerHighAlarm + transceiver_dom_threshold_dict['rxpowerlowalarm'] = rxPowerLowAlarm + transceiver_dom_threshold_dict['rxpowerhighwarning'] = rxPowerHighWarn + transceiver_dom_threshold_dict['rxpowerlowwarning'] = rxPowerLowWarn + transceiver_dom_threshold_dict['txbiashighalarm'] = txBiasHighAlarm + transceiver_dom_threshold_dict['txbiaslowalarm'] = txBiasLowAlarm + transceiver_dom_threshold_dict['txbiashighwarning'] = txBiasHighWarn + transceiver_dom_threshold_dict['txbiaslowwarning'] = txBiasLowWarn + + return transceiver_dom_threshold_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + """ + tx_bias_list = [] + rx_power_list = [] + transceiver_dom_dict = {} + transceiver_dom_dict = dict.fromkeys(dom_dict_keys, 'N/A') + + # RxLos + rx_los = self.get_rx_los() + + # TxFault + tx_fault = self.get_tx_fault() + + # ResetStatus + reset_state = self.get_reset_status() + + # LowPower Mode + lp_mode = self.get_lpmode() + + # TxDisable + tx_disable = self.get_tx_disable() + + # TxDisable Channel + tx_disable_channel = self.get_tx_disable_channel() + + # Temperature + temperature = self.get_temperature() + + # Voltage + voltage = self.get_voltage() + + # Channel Monitor + channel_monitor_data = self._get_eeprom_data('ChannelMonitor') + if (channel_monitor_data is not None): + tx_bias = channel_monitor_data['data']['TX1Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = channel_monitor_data['data']['TX2Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = channel_monitor_data['data']['TX3Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = channel_monitor_data['data']['TX4Bias']['value'] + tx_bias_list.append(tx_bias) + rx_power = channel_monitor_data['data']['RX1Power']['value'] + rx_power_list.append(rx_power) + rx_power = channel_monitor_data['data']['RX2Power']['value'] + rx_power_list.append(rx_power) + rx_power = channel_monitor_data['data']['RX3Power']['value'] + rx_power_list.append(rx_power) + rx_power = channel_monitor_data['data']['RX4Power']['value'] + rx_power_list.append(rx_power) + else: + return None + + transceiver_dom_dict['rx_los'] = rx_los + transceiver_dom_dict['tx_fault'] = tx_fault + transceiver_dom_dict['reset_status'] = reset_state + transceiver_dom_dict['power_lpmode'] = lp_mode + transceiver_dom_dict['tx_disable'] = tx_disable + transceiver_dom_dict['tx_disable_channel'] = tx_disable_channel + transceiver_dom_dict['temperature'] = temperature + transceiver_dom_dict['voltage'] = voltage + transceiver_dom_dict['tx1bias'] = tx_bias_list[0] + transceiver_dom_dict['tx2bias'] = tx_bias_list[1] + transceiver_dom_dict['tx3bias'] = tx_bias_list[2] + transceiver_dom_dict['tx4bias'] = tx_bias_list[3] + transceiver_dom_dict['rx1power'] = rx_power_list[0] + transceiver_dom_dict['rx2power'] = rx_power_list[1] + transceiver_dom_dict['rx3power'] = rx_power_list[2] + transceiver_dom_dict['rx4power'] = rx_power_list[3] + + return transceiver_dom_dict + + def get_name(self): + """ + Retrieves the name of the sfp + Returns : QSFP or QSFP+ or QSFP28 + """ + iface_data = self._get_eeprom_data('type') + if (iface_data is not None): + identifier = iface_data['data']['type']['value'] + else: + return None + + return identifier + + def get_presence(self): + """ + Retrieves the presence of the sfp + """ + presence_ctrl = self.sfp_control + 'qsfp_modprs' + try: + reg_file = open(presence_ctrl) + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + mask = (1 << self.sfp_ctrl_idx) + + # ModPrsL is active low + if ((reg_value & mask) == 0): + return True + + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the sfp + """ + vendor_pn_data = self._get_eeprom_data('modelname') + if (vendor_pn_data is not None): + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + else: + return None + + return vendor_pn + + def get_serial(self): + """ + Retrieves the serial number of the sfp + """ + vendor_sn_data = self._get_eeprom_data('serialnum') + if (vendor_sn_data is not None): + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + else: + return None + + return vendor_sn + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + """ + reset_status = None + reset_ctrl = self.sfp_control + 'qsfp_reset' + try: + reg_file = open(reset_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + if ((reg_value & mask) == 0): + reset_status = True + else: + reset_status = False + + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + """ + rx_los = None + rx_los_list = [] + + rx_los_data = self._get_eeprom_data('rx_los') + if (rx_los_data is not None): + rx_los = rx_los_data['data']['Rx1LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx2LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx3LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx4LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + + if (rx_los_list[0] and rx_los_list[1] + and rx_los_list[2] and rx_los_list[3]): + rx_los = True + else: + rx_los = False + + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + """ + tx_fault = None + tx_fault_list = [] + + tx_fault_data = self._get_eeprom_data('tx_fault') + if (tx_fault_data is not None): + tx_fault = tx_fault_data['data']['Tx1Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx2Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx3Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx4Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + + if (tx_fault_list[0] and tx_fault_list[1] + and tx_fault_list[2] and tx_fault_list[3]): + tx_fault = True + else: + tx_fault = False + + return tx_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + """ + tx_disable = None + tx_disable_list = [] + + tx_disable_data = self._get_eeprom_data('tx_disable') + if (tx_disable_data is not None): + tx_disable = tx_disable_data['data']['Tx1Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx2Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx3Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx4Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + + if (tx_disable_list[0] and tx_disable_list[1] + and tx_disable_list[2] and tx_disable_list[3]): + tx_disable = True + else: + tx_disable = False + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + """ + tx_disable = None + tx_disable_list = [] + + tx_disable_data = self._get_eeprom_data('tx_disable') + if (tx_disable_data is not None): + tx_disable = tx_disable_data['data']['Tx1Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx2Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx3Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx4Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + + bit4 = int(tx_disable_list[3]) * 8 + bit3 = int(tx_disable_list[2]) * 4 + bit2 = int(tx_disable_list[1]) * 2 + bit1 = int(tx_disable_list[0]) * 1 + + tx_disable_channel = hex(bit4 + bit3 + bit2 + bit1) + + return tx_disable_channel + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + """ + lpmode_ctrl = self.sfp_control + 'qsfp_lpmode' + try: + reg_file = open(lpmode_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + if ((reg_value & mask) == 0): + lpmode_state = False + else: + lpmode_state = True + + return lpmode_state + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + """ + power_override_state = None + + # Reset Status + power_override_data = self._get_eeprom_data('power_override') + if (power_override_data is not None): + power_override = power_override_data['data']['PowerOverRide']['value'] + if (power_override is 'On'): + power_override_state = True + else: + power_override_state = False + + return power_override_state + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + """ + temperature = None + + temperature_data = self._get_eeprom_data('Temperature') + if (temperature_data is not None): + temperature = temperature_data['data']['Temperature']['value'] + + return temperature + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + """ + voltage = None + + voltage_data = self._get_eeprom_data('Voltage') + if (voltage_data is not None): + voltage = voltage_data['data']['Vcc']['value'] + + return voltage + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + """ + tx_bias = None + tx_bias_list = [] + + tx_bias_data = self._get_eeprom_data('ChannelMonitor') + if (tx_bias_data is not None): + tx_bias = tx_bias_data['data']['TX1Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX2Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX3Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX4Bias']['value'] + tx_bias_list.append(tx_bias) + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + """ + rx_power = None + rx_power_list = [] + + rx_power_data = self._get_eeprom_data('ChannelMonitor') + if (rx_power_data is not None): + rx_power = rx_power_data['data']['RX1Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX2Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX3Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX4Power']['value'] + rx_power_list.append(rx_power) + + return rx_power_list + + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + """ + tx_power = None + tx_power_list = [] + + tx_power_list.append('-infdBm') + tx_power_list.append('-infdBm') + tx_power_list.append('-infdBm') + tx_power_list.append('-infdBm') + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + """ + reset_ctrl = self.sfp_control + 'qsfp_reset' + try: + # Open reset_ctrl in both read & write mode + reg_file = open(reset_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + # Mask off the bit corresponding to our port + mask = (1 << index) + + # ResetL is active low + reg_value = (reg_value & ~mask) + + # Convert our register value back to a + # hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + # Flip the bit back high and write back to the + # register to take port out of reset + try: + reg_file = open(reset_ctrl, "w") + except IOError as e: + return False + + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + """ + lpmode_ctrl = self.sfp_control + 'qsfp_lpmode' + try: + reg_file = open(lpmode_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + # 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 + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + """ + return False + + def get_status(self): + """ + Retrieves the operational status of the device + """ + reset = self.get_reset_status() + + if (reset == True): + status = False + else: + status = True + + return status diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py index 53d4eadaec0a..5d569d9e70ef 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/chassis.py @@ -10,6 +10,13 @@ try: import os + import sys + import click + import subprocess + import glob + import sonic_device_util + from commands import getstatusoutput + from sonic_platform_base.platform_base import PlatformBase from sonic_platform_base.chassis_base import ChassisBase from sonic_platform.sfp import Sfp from sonic_platform.psu import Psu @@ -48,15 +55,15 @@ class Chassis(ChassisBase): 8: [6, 74], 9: [6, 75], 10: [6, 76], 11: [6, 77], 12: [6, 78], 13: [6, 79], 14: [6, 80], 15: [6, 81], # IOM 2 - 16: [8, 50], 17: [8, 51], 18: [8, 52], 19: [8, 53], - 20: [8, 54], 21: [8, 55], 22: [8, 56], 23: [8, 57], - 24: [8, 58], 25: [8, 59], 26: [8, 60], 27: [8, 61], - 28: [8, 62], 29: [8, 63], 30: [8, 64], 31: [8, 65], + 16: [8, 34], 17: [8, 35], 18: [8, 36], 19: [8, 37], + 20: [8, 38], 21: [8, 39], 22: [8, 40], 23: [8, 41], + 24: [8, 42], 25: [8, 43], 26: [8, 44], 27: [8, 45], + 28: [8, 46], 29: [8, 47], 30: [8, 48], 31: [8, 49], # IOM 3 - 32: [7, 34], 33: [7, 35], 34: [7, 36], 35: [7, 37], - 36: [7, 38], 37: [7, 39], 38: [7, 40], 39: [7, 41], - 40: [7, 42], 41: [7, 43], 42: [7, 44], 43: [7, 45], - 44: [7, 46], 45: [7, 47], 46: [7, 48], 47: [7, 49], + 32: [7, 50], 33: [7, 51], 34: [7, 52], 35: [7, 53], + 36: [7, 54], 37: [7, 55], 38: [7, 56], 39: [7, 57], + 40: [7, 58], 41: [7, 59], 42: [7, 60], 43: [7, 61], + 44: [7, 62], 45: [7, 63], 46: [7, 64], 47: [7, 65], # IOM 4 48: [9, 18], 49: [9, 19], 50: [9, 20], 51: [9, 21], 52: [9, 22], 53: [9, 23], 54: [9, 24], 55: [9, 25], @@ -76,6 +83,8 @@ class Chassis(ChassisBase): power_reason_dict[33] = ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC power_reason_dict[44] = ChassisBase.REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED + _component_name_list = ["BIOS", "CPLD1", "CPLD2", "FPGA"] + def __init__(self): ChassisBase.__init__(self) @@ -141,6 +150,19 @@ def _get_pmc_register(self, reg_name): rv = rv.lstrip(" ") return rv + # Run bash command and print output to stdout + def run_command(self, command): + click.echo(click.style("Command: ", fg='cyan') + + click.style(command, fg='green')) + + proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + (out, err) = proc.communicate() + + click.echo(out) + + if proc.returncode != 0: + sys.exit(proc.returncode) + def get_name(self): """ Retrieves the name of the device @@ -230,3 +252,127 @@ def get_reboot_cause(self): return (self.reset_reason_dict[reset_reason], None) return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") + + def get_component_name_list(self): + """ + Retrieves chassis components list such as BIOS, CPLD, FPGA, etc. + + Returns: + A list containing component name. + """ + return self._component_name_list + + def get_firmware_version(self, component_name): + + version = None + + if component_name in self._component_name_list: + + if component_name == self._component_name_list[0]: # BIOS + status, version = getstatusoutput( + "dmidecode -s system-version") + + elif component_name == self._component_name_list[1]: # CPLD1 + version = None + + elif component_name == self._component_name_list[2]: # CPLD2 + version = None + + elif component_name == self._component_name_list[3]: # SMF + version = None + + return version + + def install_component_firmware(self, component_name, image_path): + + bios_image = None + bios_version = "3.25.0." + bios_file_name = "S6100*BIOS*" + flashrom = "/usr/local/bin/flashrom" + PLATFORM_ROOT_PATH = '/usr/share/sonic/device' + machine_info = sonic_device_util.get_machine_info() + platform = sonic_device_util.get_platform_info(machine_info) + platform_path = "/".join([PLATFORM_ROOT_PATH, platform, "bin"]) + + warning = """ + ******************************************************************** + * Warning - Upgrading BIOS is inherently risky and should only be * + * attempted when necessary. A failure at this upgrade may cause * + * a board RMA. Proceed with caution ! * + ******************************************************************** + """ + + if component_name in self._component_name_list: + if component_name == self._component_name_list[0]: # BIOS + + # current BIOS version + current_bios_version = self.get_firmware_version("BIOS") + + # Construct BIOS image path + if image_path is not None: + image_path = image_path + platform_path + for name in glob.glob( + os.path.join(image_path, bios_file_name)): + bios_image = image_path = name + + if not bios_image: + print "BIOS image file not found:", image_path + return False + + # Extract BIOS image version + bios_image = os.path.basename(bios_image) + bios_image = bios_image.strip('S6100-BIOS-') + bios_image_version = bios_image.strip('.bin') + + if bios_image_version.startswith(bios_version): + bios_image_minor = bios_image_version.replace( + bios_image_version[:7], '') + if bios_image_minor.startswith("2"): + bios_image_minor = bios_image_minor.split("-")[1] + + if current_bios_version.startswith(bios_version): + current_bios_minor = current_bios_version.replace( + current_bios_version[:7], '') + if current_bios_minor.startswith("2"): + current_bios_minor = current_bios_minor.split("-")[1] + + # BIOS version check + if bios_image_minor > current_bios_minor: + + print warning + prompt_text = "New BIOS image " + bios_image_version + \ + " available to install, continue?" + yes = click.confirm(prompt_text) + + elif current_bios_minor > bios_image_minor: + + print warning + prompt_text = "Do you want to downgrade BIOS image from " \ + + current_bios_version + " to " + \ + bios_image_version + " continue?" + + yes = click.confirm(prompt_text) + + else: + print("BIOS is already with {} latest version".format( + current_bios_version)) + return True + + if yes: + command = flashrom + " -p" + " internal" + " -w " + \ + image_path + self.run_command(command) + + elif component_name == self._component_name_list[1]: # CPLD1 + return False + + elif component_name == self._component_name_list[2]: # CPLD2 + return False + + elif component_name == self._component_name_list[3]: # SMF + return False + else: + print "Invalid component Name:", component_name + + return True + diff --git a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py index b312a52c7b42..8f8f63266f7b 100755 --- a/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-dell/s6100/sonic_platform/sfp.py @@ -418,7 +418,13 @@ def get_presence(self): reg_value = int(reg_hex, 16) # Mask off the bit corresponding to our port - mask = (1 << self.sfp_ctrl_idx) + if (self.sfp_ctrl_idx > 15): + index = self.sfp_ctrl_idx % 16 + else: + index = self.sfp_ctrl_idx + + # Mask off the bit corresponding to our port + mask = (1 << index) # ModPrsL is active low if ((reg_value & mask) == 0): @@ -849,3 +855,40 @@ def set_lpmode(self, lpmode): reg_file.close() return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + """ + return False + + def get_status(self): + """ + Retrieves the operational status of the device + """ + reset = self.get_reset_status() + + if (reset == True): + status = False + else: + status = True + + return status diff --git a/platform/broadcom/sonic-platform-modules-dell/tools/0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch b/platform/broadcom/sonic-platform-modules-dell/tools/0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch new file mode 100644 index 000000000000..ab77df9c4d3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/tools/0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch @@ -0,0 +1,8510 @@ +From 482e06109190eb918208820fd94c8f4a6963f77e Mon Sep 17 00:00:00 2001 +From: paavaanan +Date: Tue, 21 May 2019 10:40:59 -0400 +Subject: [PATCH] Intel-Rangeley-stripped-code-changes + +--- + 82802ab.c | 1 + + Makefile | 109 +++- + README | 26 +- + at45db.c | 562 ++++++++++++++++ + atahpt.c | 2 + + board_enable.c | 19 +- + buspirate_spi.c | 7 +- + cbtable.c | 7 +- + chipdrivers.h | 21 +- + chipset_enable.c | 610 +++++++++++------ + cli_classic.c | 40 +- + dmi.c | 332 ++++++++-- + dnv_smi_spi.c | 185 ++++++ + drkaiser.c | 14 +- + flash.h | 56 +- + flashchips.c | 791 +++++++++++++++++++---- + flashchips.h | 27 +- + flashrom.c | 162 ++++- + ft2232_spi.c | 6 + + gfxnvidia.c | 14 +- + hwaccess.h | 6 + + ich_descriptors.c | 104 +++ + ich_descriptors.h | 104 +++ + ichspi.c | 557 ++++++++++++++-- + internal.c | 5 +- + it85spi.c | 3 + + it87spi.c | 47 +- + layout.c | 126 +++- + linux_spi.c | 12 +- + mcp6x_spi.c | 15 +- + nic3com.c | 2 + + nicintel.c | 29 +- + nicintel_spi.c | 26 +- + nicnatsemi.c | 2 + + nicrealtek.c | 2 + + ogp_spi.c | 14 +- + pcidev.c | 2 +- + physmap.c | 170 +++-- + pony_spi.c | 1 + + print.c | 15 +- + programmer.h | 28 +- + rayer_spi.c | 196 ++++-- + satamv.c | 19 +- + satasii.c | 18 +- + sb600spi.c | 208 +++++- + serial.c | 113 ++-- + serprog.c | 165 +++-- + spi25.c | 35 +- + spi25_statusreg.c | 2 +- + stm50.c | 115 ++++ + udelay.c | 10 +- + util/getrevision.sh | 311 +++++++++ + util/ich_descriptors_tool/ich_descriptors_tool.c | 8 +- + util/z60_flashrom.rules | 4 + + 54 files changed, 4553 insertions(+), 912 deletions(-) + create mode 100644 at45db.c + create mode 100644 dnv_smi_spi.c + create mode 100644 stm50.c + create mode 100755 util/getrevision.sh + +diff --git a/82802ab.c b/82802ab.c +index 608995d..2a43813 100644 +--- a/82802ab.c ++++ b/82802ab.c +@@ -89,6 +89,7 @@ int probe_82802ab(struct flashctx *flash) + return 1; + } + ++/* FIXME: needs timeout */ + uint8_t wait_82802ab(struct flashctx *flash) + { + uint8_t status; +diff --git a/Makefile b/Makefile +index 6e41e5d..d66039a 100644 +--- a/Makefile ++++ b/Makefile +@@ -39,6 +39,7 @@ CFLAGS ?= -Os -Wall -Wshadow + EXPORTDIR ?= . + AR ?= ar + RANLIB ?= ranlib ++DOSLIBS_BASE ?= .. + # The following parameter changes the default programmer that will be used if there is no -p/--programmer + # argument given when running flashrom. The predefined setting does not enable any default so that every + # user has to declare the programmer he wants to use on every run. The rationale for this to be not set +@@ -50,7 +51,8 @@ RANLIB ?= ranlib + # values are those specified in enum programmer in programmer.h (which depend on other CONFIG_* options + # evaluated below, namely those that enable/disable the various programmers). + # Compilation will fail for unspecified values. +-CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INVALID ++#CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INVALID ++CONFIG_DEFAULT_PROGRAMMER ?= PROGRAMMER_INTERNAL + + # If your compiler spits out excessive warnings, run make WARNERROR=no + # You shouldn't have to change this flag. +@@ -61,10 +63,13 @@ CFLAGS += -Werror + endif + + ############################################################################### +-# General OS/architecture specific settings. ++# General OS-specific settings. ++# 1. Prepare for later by gathering information about host and target OS ++# 2. Set compiler flags and parameters according to OSes ++# 3. Likewise verify user-supplied CONFIG_* variables. + + # HOST_OS is only used to work around local toolchain issues. +-HOST_OS ?= $(shell uname) ++HOST_OS ?= $(shell uname) + ifeq ($(HOST_OS), MINGW32_NT-5.1) + # Explicitly set CC = gcc on MinGW, otherwise: "cc: command not found". + CC = gcc +@@ -94,13 +99,24 @@ CPPFLAGS += -I/usr/local/include + LDFLAGS += -L/usr/local/lib + endif + ++ifeq ($(TARGET_OS), NetBSD) ++CPPFLAGS += -I/usr/pkg/include ++LDFLAGS += -L/usr/pkg/lib ++endif ++ ++ifeq ($(TARGET_OS), DragonFlyBSD) ++CPPFLAGS += -I/usr/pkg/include ++LDFLAGS += -L/usr/pkg/lib ++endif ++ + ifeq ($(TARGET_OS), DOS) + EXEC_SUFFIX := .exe +-CPPFLAGS += -I../libgetopt ++CPPFLAGS += -I$(DOSLIBS_BASE)/libgetopt + # DJGPP has odd uint*_t definitions which cause lots of format string warnings. + CFLAGS += -Wno-format + # FIXME Check if we can achieve the same effect with -L../libgetopt -lgetopt +-LIBS += ../libgetopt/libgetopt.a ++LIBS += -lgetopt ++LDFLAGS += -L$(DOSLIBS_BASE)/libgetopt/ + # Bus Pirate, Serprog and PonyProg are not supported under DOS (missing serial support). + ifeq ($(CONFIG_BUSPIRATE_SPI), yes) + UNSUPPORTED_FEATURES += CONFIG_BUSPIRATE_SPI=yes +@@ -215,6 +231,10 @@ endif + endif + + ifeq ($(TARGET_OS), libpayload) ++ifeq ($(MAKECMDGOALS),) ++.DEFAULT_GOAL := libflashrom.a ++$(info Setting default goal to libflashrom.a) ++endif + FLASHROM_CFLAGS += -DSTANDALONE + ifeq ($(CONFIG_DUMMY), yes) + UNSUPPORTED_FEATURES += CONFIG_DUMMY=yes +@@ -263,6 +283,10 @@ override CONFIG_LINUX_SPI = no + endif + endif + ++############################################################################### ++# General architecture-specific settings. ++# Like above for the OS, below we verify user-supplied options depending on the target architecture. ++ + # Determine the destination processor architecture. + # IMPORTANT: The following line must be placed before ARCH is ever used + # (of course), but should come after any lines setting CC because the line +@@ -307,10 +331,10 @@ endif + ############################################################################### + # Flash chip drivers and bus support infrastructure. + +-CHIP_OBJS = jedec.o stm50flw0x0x.o w39.o w29ee011.o \ ++CHIP_OBJS = jedec.o stm50.o w39.o w29ee011.o \ + sst28sf040.o m29f400bt.o 82802ab.o pm49fl00x.o \ + sst49lfxxxc.o sst_fwhub.o flashchips.o spi.o spi25.o spi25_statusreg.o \ +- opaque.o sfdp.o en29lv640b.o ++ opaque.o sfdp.o en29lv640b.o at45db.o + + ############################################################################### + # Library code. +@@ -322,18 +346,22 @@ LIB_OBJS = layout.o flashrom.o udelay.o programmer.o + + CLI_OBJS = cli_classic.o cli_output.o print.o + +-# Set the flashrom version string from the highest revision number +-# of the checked out flashrom files. ++# Set the flashrom version string from the highest revision number of the checked out flashrom files. + # Note to packagers: Any tree exported with "make export" or "make tarball" + # will not require subversion. The downloadable snapshots are already exported. +-SVNVERSION := $(shell LC_ALL=C svnversion -cn . 2>/dev/null | sed -e "s/.*://" -e "s/\([0-9]*\).*/\1/" | grep "[0-9]" || LC_ALL=C svn info . 2>/dev/null | awk '/^Revision:/ {print $$2 }' | grep "[0-9]" || LC_ALL=C git svn info . 2>/dev/null | awk '/^Revision:/ {print $$2 }' | grep "[0-9]" || echo unknown) ++SVNVERSION := r1781 + + RELEASE := 0.9.7 +-VERSION := $(RELEASE)-r$(SVNVERSION) ++VERSION := $(RELEASE)-$(SVNVERSION) + RELEASENAME ?= $(VERSION) + + SVNDEF := -D'FLASHROM_VERSION="$(VERSION)"' + ++F10FLAGS := -DFORCE10_SPI_CHANGE ++ ++############################################################################### ++# Default settings of CONFIG_* variables. ++ + # Always enable internal/onboard support for now. + CONFIG_INTERNAL ?= yes + +@@ -425,16 +453,39 @@ endif + endif + + ############################################################################### ++# Handle CONFIG_* variables that depend on others set (and verified) above. ++ ++# The external DMI decoder (dmidecode) does not work in libpayload. Bail out if the internal one got disabled. ++ifeq ($(TARGET_OS), libpayload) ++ifeq ($(CONFIG_INTERNAL), yes) ++ifeq ($(CONFIG_INTERNAL_DMI), no) ++UNSUPPORTED_FEATURES += CONFIG_INTERNAL_DMI=no ++else ++override CONFIG_INTERNAL_DMI = yes ++endif ++endif ++endif ++ ++# Use internal DMI/SMBIOS decoder by default instead of relying on dmidecode. ++CONFIG_INTERNAL_DMI ?= yes ++ ++############################################################################### + # Programmer drivers and programmer support infrastructure. ++# Depending on the CONFIG_* variables set and verified above we set compiler flags and parameters below. ++ ++FEATURE_CFLAGS += -DDELL_DENVERTON_SUPPORT -DDELL_AVOTON_SUPPORT + + FEATURE_CFLAGS += -D'CONFIG_DEFAULT_PROGRAMMER=$(CONFIG_DEFAULT_PROGRAMMER)' + + ifeq ($(CONFIG_INTERNAL), yes) + FEATURE_CFLAGS += -D'CONFIG_INTERNAL=1' +-PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o dmi.o internal.o ++PROGRAMMER_OBJS += processor_enable.o chipset_enable.o board_enable.o cbtable.o internal.o + ifeq ($(ARCH), x86) + PROGRAMMER_OBJS += it87spi.o it85spi.o sb600spi.o amd_imc.o wbsio_spi.o mcp6x_spi.o +-PROGRAMMER_OBJS += ichspi.o ich_descriptors.o ++PROGRAMMER_OBJS += ichspi.o ich_descriptors.o dmi.o dnv_smi_spi.o ++ifeq ($(CONFIG_INTERNAL_DMI), yes) ++FEATURE_CFLAGS += -D'CONFIG_INTERNAL_DMI=1' ++endif + else + endif + NEED_PCI := yes +@@ -597,9 +648,9 @@ PCILIBS += -lpciutils -lpci + PCILIBS += -l$(shell uname -p) + else + ifeq ($(TARGET_OS), DOS) +-# FIXME There needs to be a better way to do this +-CPPFLAGS += -I../libpci/include +-PCILIBS += ../libpci/lib/libpci.a ++CPPFLAGS += -I$(DOSLIBS_BASE)/libpci/include ++LDFLAGS += -L$(DOSLIBS_BASE)/libpci/lib/ ++PCILIBS += -lpci + else + PCILIBS += -lpci + ifeq ($(TARGET_OS), OpenBSD) +@@ -635,10 +686,11 @@ FEATURE_LIBS += $(shell LC_ALL=C grep -q "NEEDLIBZ := yes" .libdeps && printf "% + LIBFLASHROM_OBJS = $(CHIP_OBJS) $(PROGRAMMER_OBJS) $(LIB_OBJS) + OBJS = $(CLI_OBJS) $(LIBFLASHROM_OBJS) + +-all: hwlibs features $(PROGRAM)$(EXEC_SUFFIX) ++all: hwlibs features $(PROGRAM)$(EXEC_SUFFIX) $(PROGRAM).8 + ifeq ($(ARCH), x86) + @+$(MAKE) -C util/ich_descriptors_tool/ TARGET_OS=$(TARGET_OS) EXEC_SUFFIX=$(EXEC_SUFFIX) + endif ++default: all + + $(PROGRAM)$(EXEC_SUFFIX): $(OBJS) + $(CC) $(LDFLAGS) -o $(PROGRAM)$(EXEC_SUFFIX) $(OBJS) $(LIBS) $(PCILIBS) $(FEATURE_LIBS) $(USBLIBS) +@@ -653,13 +705,13 @@ libflashrom.a: $(LIBFLASHROM_OBJS) + TAROPTIONS = $(shell LC_ALL=C tar --version|grep -q GNU && echo "--owner=root --group=root") + + %.o: %.c .features +- $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FLASHROM_CFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) -o $@ -c $< ++ $(CC) -MMD $(CFLAGS) $(CPPFLAGS) $(FLASHROM_CFLAGS) $(FEATURE_CFLAGS) $(SVNDEF) $(F10FLAGS) -o $@ -c $< + + # Make sure to add all names of generated binaries here. + # This includes all frontends and libflashrom. + # We don't use EXEC_SUFFIX here because we want to clean everything. + clean: +- rm -f $(PROGRAM) $(PROGRAM).exe libflashrom.a *.o *.d ++ rm -f $(PROGRAM) $(PROGRAM).exe libflashrom.a *.o *.d $(PROGRAM).8 + @+$(MAKE) -C util/ich_descriptors_tool/ clean + + distclean: clean +@@ -698,11 +750,20 @@ compiler: featuresavailable + @echo $(TARGET_OS)|wc -w|grep -q '^[[:blank:]]*1[[:blank:]]*$$' || \ + ( echo "unknown. Aborting."; exit 1) + @printf "%s\n" '$(TARGET_OS)' ++ifeq ($(TARGET_OS), libpayload) ++ @$(CC) --version 2>&1 | grep -q coreboot || \ ++ ( echo "Warning: It seems you are not using coreboot's reference compiler."; \ ++ echo "This might work but usually does not, please beware." ) ++endif + + define LIBPCI_TEST + /* Avoid a failing test due to libpci header symbol shadowing breakage */ + #define index shadow_workaround_index ++#if !defined __NetBSD__ && !defined __DragonFly__ + #include ++#else ++#include ++#endif + struct pci_access *pacc; + int main(int argc, char **argv) + { +@@ -853,16 +914,20 @@ endif + @$(DIFF) -q .features.tmp .features >/dev/null 2>&1 && rm .features.tmp || mv .features.tmp .features + @rm -f .featuretest.c .featuretest$(EXEC_SUFFIX) + +-install: $(PROGRAM)$(EXEC_SUFFIX) ++$(PROGRAM).8: $(PROGRAM).8.tmpl ++ @sed -e '1 s#".*".*#"$(shell ./util/getrevision.sh -d $(PROGRAM).8.tmpl)" "$(VERSION)"#' <$< >$@ ++ ++install: $(PROGRAM)$(EXEC_SUFFIX) $(PROGRAM).8 + mkdir -p $(DESTDIR)$(PREFIX)/sbin + mkdir -p $(DESTDIR)$(MANDIR)/man8 + $(INSTALL) -m 0755 $(PROGRAM)$(EXEC_SUFFIX) $(DESTDIR)$(PREFIX)/sbin + $(INSTALL) -m 0644 $(PROGRAM).8 $(DESTDIR)$(MANDIR)/man8 + +-export: ++export: $(PROGRAM).8 + @rm -rf $(EXPORTDIR)/flashrom-$(RELEASENAME) + @svn export -r BASE . $(EXPORTDIR)/flashrom-$(RELEASENAME) + @sed "s/^SVNVERSION.*/SVNVERSION := $(SVNVERSION)/" Makefile >$(EXPORTDIR)/flashrom-$(RELEASENAME)/Makefile ++ @cp $(PROGRAM).8 "$(EXPORTDIR)/flashrom-$(RELEASENAME)/$(PROGRAM).8" + @LC_ALL=C svn log >$(EXPORTDIR)/flashrom-$(RELEASENAME)/ChangeLog + @echo Exported $(EXPORTDIR)/flashrom-$(RELEASENAME)/ + +@@ -876,6 +941,6 @@ djgpp-dos: clean + libpayload: clean + make CC="CC=i386-elf-gcc lpgcc" AR=i386-elf-ar RANLIB=i386-elf-ranlib + +-.PHONY: all clean distclean compiler hwlibs features export tarball dos featuresavailable ++.PHONY: all install clean distclean compiler hwlibs features export tarball dos featuresavailable + + -include $(OBJS:.o=.d) +diff --git a/README b/README +index 7f24cca..b3e50a6 100644 +--- a/README ++++ b/README +@@ -80,11 +80,9 @@ To compile on Solaris, use: + + gmake LDFLAGS="-L$pathtolibpci" CC="gcc -I$pathtopciheaders" CFLAGS=-O2 + +-To compile on NetBSD or DragonFly BSD, use: ++To compile on NetBSD or DragonFly BSD (with pciutils, libftdi, libusb installed in /usr/pkg/), use: + +- ln -s /usr/pkg/include/pciutils pci +- gmake CPPFLAGS="-I. -I/usr/pkg/include" \ +- LDFLAGS="-L/usr/pkg/lib -Wl,-rpath-link,/usr/pkg/lib" ++ gmake + + To compile on OpenBSD, use: + +@@ -105,20 +103,24 @@ To cross-compile on Linux for DOS: + djcrx-2.04pre_20090725-13ap.i386.rpm + The cross toolchain packages for your distribution may have slightly different + names (look for packages named *djgpp*). +- Download pciutils 3.1.5 and apply http://assembler.cz/flashrom/pciutils.patch +- Download and compile http://assembler.cz/flashrom/libgetopt/ ++ ++ You will need the following library source trees containing their compiled ++ static libraries either in the parent directory of the flashrom source or ++ specify the base folder on compile time with the DOSLIBS_BASE parameter. ++ The default as described above is equal to calling ++ 'make djgpp-dos DOSLIBS_BASE=..' ++ ++ To get and build said libraries... ++ Download pciutils 3.1.5 and apply http://flashrom.org/File:Pciutils.patch.gz + Compile pciutils, see README.DJGPP for instructions. ++ Download and compile http://flashrom.org/File:Libgetopt.tar.gz + Enter the flashrom directory. +- ../libpci should contain pciutils source and binaries. +- ../libgetopt should contain getopt.a from libgetopt. + Run either (change settings where appropriate) + make CC=i586-pc-msdosdjgpp-gcc STRIP=i586-pc-msdosdjgpp-strip + or (above settings hardcoded) + make djgpp-dos +- You might have to add WARNERROR=no to the make command line. +- To run flashrom.exe, download and unpack +- http://homer.rice.edu/~sandmann/cwsdpmi/csdpmi7b.zip and make sure +- CWSDPMI.EXE is in the current directory. ++ To run flashrom.exe, download http://flashrom.org/File:Csdpmi7b.zip and ++ unpack CWSDPMI.EXE into the current directory or one in PATH. + + To cross-compile on Linux for Windows: + +diff --git a/at45db.c b/at45db.c +new file mode 100644 +index 0000000..5c90418 +--- /dev/null ++++ b/at45db.c +@@ -0,0 +1,562 @@ ++/* ++ * Support for Atmel AT45DB series DataFlash chips. ++ * This file is part of the flashrom project. ++ * ++ * Copyright (C) 2012 Aidan Thornton ++ * Copyright (C) 2013 Stefan Tauner ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; version 2 of the License. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++#include ++#include "flash.h" ++#include "chipdrivers.h" ++#include "programmer.h" ++#include "spi.h" ++ ++/* Status register bits */ ++#define AT45DB_READY (1<<7) ++#define AT45DB_CMP (1<<6) ++#define AT45DB_PROT (1<<1) ++#define AT45DB_POWEROF2 (1<<0) ++ ++/* Opcodes */ ++#define AT45DB_STATUS 0xD7 /* NB: this is a block erase command on most other chips(!). */ ++#define AT45DB_DISABLE_PROTECT 0x3D, 0x2A, 0x7F, 0x9A ++#define AT45DB_READ_ARRAY 0xE8 ++#define AT45DB_READ_PROTECT 0x32 ++#define AT45DB_READ_LOCKDOWN 0x35 ++#define AT45DB_PAGE_ERASE 0x81 ++#define AT45DB_BLOCK_ERASE 0x50 ++#define AT45DB_SECTOR_ERASE 0x7C ++#define AT45DB_CHIP_ERASE 0xC7 ++#define AT45DB_CHIP_ERASE_ADDR 0x94809A /* Magic address. See usage. */ ++#define AT45DB_BUFFER1_WRITE 0x84 ++#define AT45DB_BUFFER1_PAGE_PROGRAM 0x88 ++/* Buffer 2 is unused yet. ++#define AT45DB_BUFFER2_WRITE 0x87 ++#define AT45DB_BUFFER2_PAGE_PROGRAM 0x89 ++*/ ++ ++static uint8_t at45db_read_status_register(struct flashctx *flash, uint8_t *status) ++{ ++ static const uint8_t cmd[] = { AT45DB_STATUS }; ++ ++ int ret = spi_send_command(flash, sizeof(cmd), 1, cmd, status); ++ if (ret != 0) ++ msg_cerr("Reading the status register failed!\n"); ++ else ++ msg_cspew("Status register: 0x%02x.\n", *status); ++ return ret; ++} ++ ++int spi_disable_blockprotect_at45db(struct flashctx *flash) ++{ ++ static const uint8_t cmd[4] = { AT45DB_DISABLE_PROTECT }; /* NB: 4 bytes magic number */ ++ int ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); ++ if (ret != 0) { ++ msg_cerr("Sending disable lockdown failed!\n"); ++ return ret; ++ } ++ uint8_t status; ++ ret = at45db_read_status_register(flash, &status); ++ if (ret != 0 || ((status & AT45DB_PROT) != 0)) { ++ msg_cerr("Disabling lockdown failed!\n"); ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static unsigned int at45db_get_sector_count(struct flashctx *flash) ++{ ++ unsigned int i, j; ++ unsigned int cnt = 0; ++ for (i = 0; i < NUM_ERASEFUNCTIONS; i++) { ++ if (flash->chip->block_erasers[i].block_erase == &spi_erase_at45db_sector) { ++ for (j = 0; j < NUM_ERASEREGIONS; j++) { ++ cnt += flash->chip->block_erasers[i].eraseblocks[j].count; ++ } ++ } ++ } ++ msg_cspew("%s: number of sectors=%u\n", __func__, cnt); ++ return cnt; ++} ++ ++/* Reads and prettyprints protection/lockdown registers. ++ * Some elegance of the printouts had to be cut down a bit to share this code. */ ++static uint8_t at45db_prettyprint_protection_register(struct flashctx *flash, uint8_t opcode, const char *regname) ++{ ++ const uint8_t cmd[] = { opcode, 0, 0, 0 }; ++ /* The first two sectors share the first result byte. */ ++ uint8_t buf[at45db_get_sector_count(flash) - 1]; ++ ++ int ret = spi_send_command(flash, sizeof(cmd), sizeof(buf), cmd, buf); ++ if (ret != 0) { ++ msg_cerr("Reading the %s register failed!\n", regname); ++ return ret; ++ } ++ ++ unsigned int i; ++ for (i = 0; i < sizeof(buf); i++) { ++ if (buf[i] != 0x00) ++ break; ++ if (i == sizeof(buf) - 1) { ++ msg_cdbg("No Sector is %sed.\n", regname); ++ return 0; ++ } ++ } ++ ++ /* TODO: print which addresses are mapped to (un)locked sectors. */ ++ msg_cdbg("Sector 0a is %s%sed.\n", ((buf[0] & 0xC0) == 0x00) ? "un" : "", regname); ++ msg_cdbg("Sector 0b is %s%sed.\n", ((buf[0] & 0x30) == 0x00) ? "un" : "", regname); ++ for (i = 1; i < sizeof(buf); i++) ++ msg_cdbg("Sector %2u is %s%sed.\n", i, (buf[i] == 0x00) ? "un" : "", regname); ++ ++ return 0; ++} ++ ++/* bit 7: busy flag ++ * bit 6: memory/buffer compare result ++ * bit 5-2: density (encoding see below) ++ * bit 1: protection enabled (soft or hard) ++ * bit 0: "power of 2" page size indicator (e.g. 1 means 256B; 0 means 264B) ++ * ++ * 5-2 encoding: bit 2 is always 1, bits 3-5 encode the density as "2^(bits - 1)" in Mb e.g.: ++ * AT45DB161D 1011 16Mb */ ++int spi_prettyprint_status_register_at45db(struct flashctx *flash) ++{ ++ uint8_t status; ++ if (at45db_read_status_register(flash, &status) != 0) { ++ return 1; ++ } ++ ++ /* AT45DB321C does not support lockdown or a page size of a power of 2... */ ++ const bool isAT45DB321C = (strcmp(flash->chip->name, "AT45DB321C") == 0); ++ msg_cdbg("Chip status register is 0x%02x\n", status); ++ msg_cdbg("Chip status register: Bit 7 / Ready is %sset\n", (status & AT45DB_READY) ? "" : "not "); ++ msg_cdbg("Chip status register: Bit 6 / Compare match is %sset\n", (status & AT45DB_CMP) ? "" : "not "); ++ spi_prettyprint_status_register_bit(status, 5); ++ spi_prettyprint_status_register_bit(status, 4); ++ spi_prettyprint_status_register_bit(status, 3); ++ spi_prettyprint_status_register_bit(status, 2); ++ const uint8_t dens = (status >> 3) & 0x7; /* Bit 2 is always 1, we use the other bits only */ ++ msg_cdbg("Chip status register: Density is %u Mb\n", 1 << (dens - 1)); ++ msg_cdbg("Chip status register: Bit 1 / Protection is %sset\n", (status & AT45DB_PROT) ? "" : "not "); ++ ++ if (isAT45DB321C) ++ spi_prettyprint_status_register_bit(status, 0); ++ else ++ msg_cdbg("Chip status register: Bit 0 / \"Power of 2\" is %sset\n", ++ (status & AT45DB_POWEROF2) ? "" : "not "); ++ ++ if (status & AT45DB_PROT) ++ at45db_prettyprint_protection_register(flash, AT45DB_READ_PROTECT, "protect"); ++ ++ if (!isAT45DB321C) ++ at45db_prettyprint_protection_register(flash, AT45DB_READ_LOCKDOWN, "lock"); ++ ++ return 0; ++} ++ ++/* Probe function for AT45DB* chips that support multiple page sizes. */ ++int probe_spi_at45db(struct flashctx *flash) ++{ ++ uint8_t status; ++ struct flashchip *chip = flash->chip; ++ ++ if (!probe_spi_rdid(flash)) ++ return 0; ++ ++ /* Some AT45DB* chips support two different page sizes each (e.g. 264 and 256 B). In order to tell which ++ * page size this chip has we need to read the status register. */ ++ if (at45db_read_status_register(flash, &status) != 0) ++ return 0; ++ ++ /* We assume sane power-of-2 page sizes and adjust the chip attributes in case this is not the case. */ ++ if ((status & AT45DB_POWEROF2) == 0) { ++ chip->total_size = (chip->total_size / 32) * 33; ++ chip->page_size = (chip->page_size / 32) * 33; ++ ++ unsigned int i, j; ++ for (i = 0; i < NUM_ERASEFUNCTIONS; i++) { ++ struct block_eraser *eraser = &chip->block_erasers[i]; ++ for (j = 0; j < NUM_ERASEREGIONS; j++) { ++ eraser->eraseblocks[j].size = (eraser->eraseblocks[j].size / 32) * 33; ++ } ++ } ++ } ++ ++ switch (chip->page_size) { ++ case 256: chip->gran = write_gran_256bytes; break; ++ case 264: chip->gran = write_gran_264bytes; break; ++ case 512: chip->gran = write_gran_512bytes; break; ++ case 528: chip->gran = write_gran_528bytes; break; ++ case 1024: chip->gran = write_gran_1024bytes; break; ++ case 1056: chip->gran = write_gran_1056bytes; break; ++ default: ++ msg_cerr("%s: unknown page size %d.\n", __func__, chip->page_size); ++ return 0; ++ } ++ ++ msg_cdbg2("%s: total size %i kB, page size %i B\n", __func__, chip->total_size * 1024, chip->page_size); ++ ++ return 1; ++} ++ ++/* Returns the minimum number of bits needed to represent the given address. ++ * FIXME: use mind-blowing implementation. ++ * FIXME: move to utility module. */ ++static uint32_t address_to_bits(uint32_t addr) ++{ ++ unsigned int lzb = 0; ++ while (((1 << (31 - lzb)) & ~addr) != 0) ++ lzb++; ++ return 32 - lzb; ++} ++ ++/* In case of non-power-of-two page sizes we need to convert the address flashrom uses to the address the ++ * DataFlash chips use. The latter uses a segmented address space where the page address is encoded in the ++ * more significant bits and the offset within the page is encoded in the less significant bits. The exact ++ * partition depends on the page size. ++ */ ++static unsigned int at45db_convert_addr(unsigned int addr, unsigned int page_size) ++{ ++ unsigned int page_bits = address_to_bits(page_size - 1); ++ unsigned int at45db_addr = ((addr / page_size) << page_bits) | (addr % page_size); ++ msg_cspew("%s: addr=0x%x, page_size=%u, page_bits=%u -> at45db_addr=0x%x\n", ++ __func__, addr, page_size, page_bits, at45db_addr); ++ return at45db_addr; ++} ++ ++int spi_read_at45db(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ if ((addr + len) > total_size) { ++ msg_cerr("%s: tried to read beyond flash boundary: addr=%u, len=%u, size=%u\n", ++ __func__, addr, len, total_size); ++ return 1; ++ } ++ ++ /* We have to split this up into chunks to fit within the programmer's read size limit, but those ++ * chunks can cross page boundaries. */ ++ const unsigned int max_data_read = flash->pgm->spi.max_data_read; ++ const unsigned int max_chunk = (max_data_read > 0) ? max_data_read : page_size; ++ while (addr < len) { ++ unsigned int chunk = min(max_chunk, len); ++ int ret = spi_nbyte_read(flash, at45db_convert_addr(addr, page_size), buf + addr, chunk); ++ if (ret) { ++ msg_cerr("%s: error sending read command!\n", __func__); ++ return ret; ++ } ++ addr += chunk; ++ } ++ ++ return 0; ++} ++ ++/* Legacy continuous read, used where spi_read_at45db() is not available. ++ * The first 4 (dummy) bytes read need to be discarded. */ ++int spi_read_at45db_e8(struct flashctx *flash, uint8_t *buf, unsigned int addr, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ if ((addr + len) > total_size) { ++ msg_cerr("%s: tried to read beyond flash boundary: addr=%u, len=%u, size=%u\n", ++ __func__, addr, len, total_size); ++ return 1; ++ } ++ ++ /* We have to split this up into chunks to fit within the programmer's read size limit, but those ++ * chunks can cross page boundaries. */ ++ const unsigned int max_data_read = flash->pgm->spi.max_data_read; ++ const unsigned int max_chunk = (max_data_read > 0) ? max_data_read : page_size; ++ while (addr < len) { ++ const unsigned int addr_at45 = at45db_convert_addr(addr, page_size); ++ const unsigned char cmd[] = { ++ AT45DB_READ_ARRAY, ++ (addr_at45 >> 16) & 0xff, ++ (addr_at45 >> 8) & 0xff, ++ (addr_at45 >> 0) & 0xff ++ }; ++ /* We need to leave place for 4 dummy bytes and handle them explicitly. */ ++ unsigned int chunk = min(max_chunk, len + 4); ++ uint8_t tmp[chunk]; ++ int ret = spi_send_command(flash, sizeof(cmd), chunk, cmd, tmp); ++ if (ret) { ++ msg_cerr("%s: error sending read command!\n", __func__); ++ return ret; ++ } ++ /* Copy result without dummy bytes into buf and advance address counter respectively. */ ++ memcpy(buf + addr, tmp + 4, chunk - 4); ++ addr += chunk - 4; ++ } ++ return 0; ++} ++ ++/* Returns 0 when ready, 1 on errors and timeouts. */ ++static int at45db_wait_ready (struct flashctx *flash, unsigned int us, unsigned int retries) ++{ ++ while (true) { ++ uint8_t status; ++ int ret = at45db_read_status_register(flash, &status); ++ if ((status & AT45DB_READY) == AT45DB_READY) ++ return 0; ++ if (ret != 0 || retries-- == 0) ++ return 1; ++ programmer_delay(us); ++ } ++} ++ ++static int at45db_erase(struct flashctx *flash, uint8_t opcode, unsigned int at45db_addr, unsigned int stepsize, unsigned int retries) ++{ ++ const uint8_t cmd[] = { ++ opcode, ++ (at45db_addr >> 16) & 0xff, ++ (at45db_addr >> 8) & 0xff, ++ (at45db_addr >> 0) & 0xff ++ }; ++ ++ /* Send erase command. */ ++ int ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); ++ if (ret != 0) { ++ msg_cerr("%s: error sending erase command!\n", __func__); ++ return ret; ++ } ++ ++ /* Wait for completion. */ ++ ret = at45db_wait_ready(flash, stepsize, retries); ++ if (ret != 0) ++ msg_cerr("%s: chip did not became ready again after sending the erase command!\n", __func__); ++ ++ return ret; ++} ++ ++int spi_erase_at45db_page(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr % page_size) != 0 || (blocklen % page_size) != 0) { ++ msg_cerr("%s: cannot erase partial pages: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a block beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically about 35 ms for completion, so let's wait 100 ms in 500 us steps. */ ++ return at45db_erase(flash, AT45DB_PAGE_ERASE, at45db_convert_addr(addr, page_size), 500, 200); ++} ++ ++int spi_erase_at45db_block(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr % page_size) != 0 || (blocklen % page_size) != 0) { // FIXME: should check blocks not pages ++ msg_cerr("%s: cannot erase partial pages: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a block beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically between 20 and 100 ms for completion, so let's wait 300 ms in 1 ms steps. */ ++ return at45db_erase(flash, AT45DB_BLOCK_ERASE, at45db_convert_addr(addr, page_size), 1000, 300); ++} ++ ++int spi_erase_at45db_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr % page_size) != 0 || (blocklen % page_size) != 0) { // FIXME: should check sectors not pages ++ msg_cerr("%s: cannot erase partial pages: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a sector beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically about 5 s for completion, so let's wait 20 seconds in 200 ms steps. */ ++ return at45db_erase(flash, AT45DB_SECTOR_ERASE, at45db_convert_addr(addr, page_size), 200000, 100); ++} ++ ++int spi_erase_at45db_chip(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ /* Needs typically from about 5 to over 60 s for completion, so let's wait 100 s in 500 ms steps. ++ * NB: the address is not a real address but a magic number. This hack allows to share code. */ ++ return at45db_erase(flash, AT45DB_CHIP_ERASE, AT45DB_CHIP_ERASE_ADDR, 500000, 200); ++} ++ ++/* This one is really special and works only for AT45CS1282. It uses two different opcodes depending on the ++ * address and has an asymmetric layout. */ ++int spi_erase_at45cs_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size * 1024; ++ const struct block_eraser be = flash->chip->block_erasers[0]; ++ const unsigned int sec_0a_top = be.eraseblocks[0].size; ++ const unsigned int sec_0b_top = be.eraseblocks[0].size + be.eraseblocks[1].size; ++ ++ if ((addr + blocklen) > total_size) { ++ msg_cerr("%s: tried to erase a sector beyond flash boundary: addr=%u, blocklen=%u, size=%u\n", ++ __func__, addr, blocklen, total_size); ++ return 1; ++ } ++ ++ bool partial_range = false; ++ uint8_t opcode = 0x7C; /* Used for all but sector 0a. */ ++ if (addr < sec_0a_top) { ++ opcode = 0x50; ++ /* One single sector of 8 pages at address 0. */ ++ if (addr != 0 || blocklen != (8 * page_size)) ++ partial_range = true; ++ } else if (addr < sec_0b_top) { ++ /* One single sector of 248 pages adjacent to the first. */ ++ if (addr != sec_0a_top || blocklen != (248 * page_size)) ++ partial_range = true; ++ } else { ++ /* The rest is filled by 63 aligned sectors of 256 pages. */ ++ if ((addr % (256 * page_size)) != 0 || (blocklen % (256 * page_size)) != 0) ++ partial_range = true; ++ } ++ if (partial_range) { ++ msg_cerr("%s: cannot erase partial sectors: addr=%u, blocklen=%u\n", __func__, addr, blocklen); ++ return 1; ++ } ++ ++ /* Needs up to 4 s for completion, so let's wait 20 seconds in 200 ms steps. */ ++ return at45db_erase(flash, opcode, at45db_convert_addr(addr, page_size), 200000, 100); ++} ++ ++static int at45db_fill_buffer1(struct flashctx *flash, uint8_t *bytes, unsigned int off, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ if ((off + len) > page_size) { ++ msg_cerr("Tried to write %u bytes at offset %u into a buffer of only %u B.\n", ++ len, off, page_size); ++ return 1; ++ } ++ ++ /* Create a suitable buffer to store opcode, address and data chunks for buffer1. */ ++ const unsigned int max_data_write = flash->pgm->spi.max_data_write; ++ const unsigned int max_chunk = (max_data_write > 0 && max_data_write <= page_size) ? ++ max_data_write : page_size; ++ uint8_t buf[4 + max_chunk]; ++ ++ buf[0] = AT45DB_BUFFER1_WRITE; ++ while (off < page_size) { ++ unsigned int cur_chunk = min(max_chunk, page_size - off); ++ buf[1] = (off >> 16) & 0xff; ++ buf[2] = (off >> 8) & 0xff; ++ buf[3] = (off >> 0) & 0xff; ++ memcpy(&buf[4], bytes + off, cur_chunk); ++ int ret = spi_send_command(flash, 4 + cur_chunk, 0, buf, NULL); ++ if (ret != 0) { ++ msg_cerr("%s: error sending buffer write!\n", __func__); ++ return ret; ++ } ++ off += cur_chunk; ++ } ++ return 0; ++} ++ ++static int at45db_commit_buffer1(struct flashctx *flash, unsigned int at45db_addr) ++{ ++ const uint8_t cmd[] = { ++ AT45DB_BUFFER1_PAGE_PROGRAM, ++ (at45db_addr >> 16) & 0xff, ++ (at45db_addr >> 8) & 0xff, ++ (at45db_addr >> 0) & 0xff ++ }; ++ ++ /* Send buffer to device. */ ++ int ret = spi_send_command(flash, sizeof(cmd), 0, cmd, NULL); ++ if (ret != 0) { ++ msg_cerr("%s: error sending buffer to main memory command!\n", __func__); ++ return ret; ++ } ++ ++ /* Wait for completion (typically a few ms). */ ++ ret = at45db_wait_ready(flash, 250, 200); // 50 ms ++ if (ret != 0) { ++ msg_cerr("%s: chip did not became ready again!\n", __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int at45db_program_page(struct flashctx *flash, uint8_t *buf, unsigned int at45db_addr) ++{ ++ int ret = at45db_fill_buffer1(flash, buf, 0, flash->chip->page_size); ++ if (ret != 0) { ++ msg_cerr("%s: filling the buffer failed!\n", __func__); ++ return ret; ++ } ++ ++ ret = at45db_commit_buffer1(flash, at45db_addr); ++ if (ret != 0) { ++ msg_cerr("%s: committing page failed!\n", __func__); ++ return ret; ++ } ++ ++ return 0; ++} ++ ++int spi_write_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len) ++{ ++ const unsigned int page_size = flash->chip->page_size; ++ const unsigned int total_size = flash->chip->total_size; ++ ++ if ((start % page_size) != 0 || (len % page_size) != 0) { ++ msg_cerr("%s: cannot write partial pages: start=%u, len=%u\n", __func__, start, len); ++ return 1; ++ } ++ ++ if ((start + len) > (total_size * 1024)) { ++ msg_cerr("%s: tried to write beyond flash boundary: start=%u, len=%u, size=%u\n", ++ __func__, start, len, total_size); ++ return 1; ++ } ++ ++ unsigned int i; ++ for (i = 0; i < len; i += page_size) { ++ if (at45db_program_page(flash, buf + i, at45db_convert_addr(start + i, page_size)) != 0) { ++ msg_cerr("Writing page %u failed!\n", i); ++ return 1; ++ } ++ } ++ return 0; ++} +diff --git a/atahpt.c b/atahpt.c +index f8be8c4..242e14a 100644 +--- a/atahpt.c ++++ b/atahpt.c +@@ -69,6 +69,8 @@ int atahpt_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_4); ++ if (!io_base_addr) ++ return 1; + + /* Enable flash access. */ + reg32 = pci_read_long(dev, REG_FLASH_ACCESS); +diff --git a/board_enable.c b/board_enable.c +index 074cabb..e2a5fe2 100644 +--- a/board_enable.c ++++ b/board_enable.c +@@ -1488,6 +1488,7 @@ static int intel_ich_gpio_set(int gpio, int raise) + {0x24D0, 0x58, 0x1BFF0000, 0x00030305, 0}, /* 82801EB/ER (ICH5/ICH5R) */ + {0x2640, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FB/FR (ICH6/ICH6R) */ + {0x2641, 0x48, 0x1BFF0000, 0x00030307, 0}, /* 82801FBM (ICH6M) */ ++ {0x27B0, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GDH (ICH7 DH) */ + {0x27B8, 0x48, 0xFFFFFFFF, 0x000300FF, 0}, /* 82801GB/GR (ICH7 Family) */ + {0x27B9, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GBM (ICH7-M) */ + {0x27BD, 0x48, 0xFFEBFFFE, 0x000300FE, 0}, /* 82801GHM (ICH7-M DH) */ +@@ -1665,6 +1666,7 @@ static int intel_ich_gpio_set(int gpio, int raise) + * - abit IP35 Pro: Intel P35 + ICH9R + * - ASUS P5LD2 + * - ASUS P5LD2-VM ++ * - ASUS P5LD2-VM DH + */ + static int intel_ich_gpio16_raise(void) + { +@@ -2266,13 +2268,13 @@ static int p2_whitelist_laptop(void) + * NOTE: Please add boards that _don't_ need such enables or don't work yet + * to the respective tables in print.c. Thanks! + * +- * We use 2 sets of IDs here, you're free to choose which is which. This ++ * We use 2 sets of PCI IDs here, you're free to choose which is which. This + * is to provide a very high degree of certainty when matching a board on + * the basis of subsystem/card IDs. As not every vendor handles + * subsystem/card IDs in a sane manner. + * + * Keep the second set NULLed if it should be ignored. Keep the subsystem IDs +- * NULLed if they don't identify the board fully and if you can't use DMI. ++ * and the dmi identifier NULLed if they don't identify the board fully to disable autodetection. + * But please take care to provide an as complete set of pci ids as possible; + * autodetection is the preferred behaviour and we would like to make sure that + * matches are unique. +@@ -2306,6 +2308,7 @@ const struct board_match board_matches[] = { + #if defined(__i386__) || defined(__x86_64__) + {0x10DE, 0x0547, 0x147B, 0x1C2F, 0x10DE, 0x0548, 0x147B, 0x1C2F, NULL, NULL, NULL, P3, "abit", "AN-M2", 0, NT, nvidia_mcp_gpio2_raise}, + {0x1106, 0x0282, 0x147B, 0x1415, 0x1106, 0x3227, 0x147B, 0x1415, "^AV8 ", NULL, NULL, P3, "abit", "AV8", 0, OK, board_abit_av8}, ++ {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, NULL /* "^I440BX-W977$" */, "abit", "bf6", P3, "abit", "BF6", 0, OK, intel_piix4_gpo26_lower}, + {0x8086, 0x7190, 0, 0, 0x8086, 0x7110, 0, 0, "^i440BX-W977 (BM6)$", NULL, NULL, P3, "abit", "BM6", 0, OK, intel_piix4_gpo26_lower}, + {0x8086, 0x24d3, 0x147b, 0x1014, 0x8086, 0x2578, 0x147b, 0x1014, NULL, NULL, NULL, P3, "abit", "IC7", 0, NT, intel_ich_gpio23_raise}, + {0x8086, 0x2930, 0x147b, 0x1084, 0x11ab, 0x4364, 0x147b, 0x1084, NULL, NULL, NULL, P3, "abit", "IP35", 0, OK, intel_ich_gpio16_raise}, +@@ -2330,6 +2333,7 @@ const struct board_match board_matches[] = { + {0x8086, 0x2570, 0x1849, 0x2570, 0x8086, 0x24d3, 0x1849, 0x24d0, NULL, NULL, NULL, P3, "ASRock", "775i65G", 0, OK, intel_ich_gpio23_raise}, + {0x10DE, 0x0060, 0x1043, 0x80AD, 0x10DE, 0x01E0, 0x1043, 0x80C0, NULL, NULL, NULL, P3, "ASUS", "A7N8X-VM/400", 0, OK, it8712f_gpio12_raise}, + {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3065, 0x1043, 0x80ED, NULL, NULL, NULL, P3, "ASUS", "A7V600-X", 0, OK, it8712f_gpio31_raise}, ++ {0x1106, 0x3177, 0x1043, 0x80F9, 0x1106, 0x3205, 0x1043, 0x80F9, NULL, NULL, NULL, P3, "ASUS", "A7V8X-MX", 0, OK, w836xx_memw_enable_2e}, + {0x1106, 0x3177, 0x1043, 0x80A1, 0x1106, 0x3205, 0x1043, 0x8118, NULL, NULL, NULL, P3, "ASUS", "A7V8X-MX SE", 0, OK, w836xx_memw_enable_2e}, + {0x1106, 0x3189, 0x1043, 0x807F, 0x1106, 0x3177, 0x1043, 0x808C, NULL, NULL, NULL, P3, "ASUS", "A7V8X", 0, OK, it8703f_gpio51_raise}, + {0x1106, 0x3099, 0x1043, 0x807F, 0x1106, 0x3147, 0x1043, 0x808C, NULL, NULL, NULL, P3, "ASUS", "A7V333", 0, OK, it8703f_gpio51_raise}, +@@ -2372,12 +2376,14 @@ const struct board_match board_matches[] = { + {0x8086, 0x27b8, 0x1043, 0x2a22, 0x8086, 0x2770, 0x1043, 0x2a22, "^P5LP-LE$", NULL, NULL, P3, "ASUS", "P5LP-LE (Epson OEM)", 0, OK, intel_ich_gpio34_raise}, + {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2$", NULL, NULL, P3, "ASUS", "P5LD2", 0, NT, intel_ich_gpio16_raise}, + {0x8086, 0x27da, 0x1043, 0x8179, 0x8086, 0x27b8, 0x1043, 0x8179, "^P5LD2-VM$", NULL, NULL, P3, "ASUS", "P5LD2-VM", 0, NT, intel_ich_gpio16_raise}, ++ {0x8086, 0x27b0, 0x1043, 0x8179, 0x8086, 0x2770, 0x1043, 0x817a, "^P5LD2-VM DH$", NULL, NULL, P3, "ASUS", "P5LD2-VM DH", 0, OK, intel_ich_gpio16_raise}, + {0x10DE, 0x0030, 0x1043, 0x818a, 0x8086, 0x100E, 0x1043, 0x80EE, NULL, NULL, NULL, P3, "ASUS", "P5ND2-SLI Deluxe", 0, OK, nvidia_mcp_gpio10_raise}, + {0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x829E, "^P5N-D$", NULL, NULL, P3, "ASUS", "P5N-D", 0, OK, it8718f_gpio63_raise}, + {0x10DE, 0x0260, 0x1043, 0x81BC, 0x10DE, 0x026C, 0x1043, 0x8249, "^P5N-E SLI$",NULL, NULL, P3, "ASUS", "P5N-E SLI", 0, NT, it8718f_gpio63_raise}, + {0x8086, 0x24dd, 0x1043, 0x80a6, 0x8086, 0x2570, 0x1043, 0x8157, NULL, NULL, NULL, P3, "ASUS", "P5PE-VM", 0, OK, intel_ich_gpio21_raise}, + {0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^CUSL2-C", NULL, NULL, P3, "ASUS", "CUSL2-C", 0, OK, intel_ich_gpio21_raise}, + {0x8086, 0x2443, 0x1043, 0x8027, 0x8086, 0x1130, 0x1043, 0x8027, "^TUSL2-C", NULL, NULL, P3, "ASUS", "TUSL2-C", 0, NT, intel_ich_gpio21_raise}, ++ {0x1106, 0x3059, 0x1106, 0x4161, 0x1106, 0x3065, 0x1106, 0x0102, NULL, NULL, NULL, P3, "Bcom/Clientron", "WinNET P680", 0, OK, w836xx_memw_enable_2e}, + {0x1106, 0x3177, 0x1106, 0x3177, 0x1106, 0x3116, 0x1106, 0x3116, "^KM266-8235$", "biostar", "m7viq", P3, "Biostar", "M7VIQ", 0, NT, w83697xx_memw_enable_2e}, + {0x10b7, 0x9055, 0x1028, 0x0082, 0x8086, 0x7190, 0, 0, NULL, NULL, NULL, P3, "Dell", "OptiPlex GX1", 0, OK, intel_piix4_gpo30_lower}, + {0x8086, 0x3590, 0x1028, 0x016c, 0x1000, 0x0030, 0x1028, 0x016c, NULL, NULL, NULL, P3, "Dell", "PowerEdge 1850", 0, OK, intel_ich_gpio23_raise}, +@@ -2452,6 +2458,12 @@ const struct board_match board_matches[] = { + {0x1106, 0x0259, 0x1106, 0xAA07, 0x1106, 0x3227, 0x1106, 0xAA07, NULL, NULL, NULL, P3, "VIA", "EPIA EK", 0, NT, via_vt823x_gpio9_raise}, + {0x1106, 0x3177, 0x1106, 0xAA01, 0x1106, 0x3123, 0x1106, 0xAA01, NULL, NULL, NULL, P3, "VIA", "EPIA M/MII/...", 0, OK, via_vt823x_gpio15_raise}, + {0x1106, 0x0259, 0x1106, 0x3227, 0x1106, 0x3065, 0x1106, 0x3149, NULL, NULL, NULL, P3, "VIA", "EPIA-N/NL", 0, OK, via_vt823x_gpio9_raise}, ++#ifdef DELL_AVOTON_SUPPORT ++ {0x8086, 0x1f38, 0x8086, 0x7270, 0, 0, 0, 0, NULL, NULL, NULL, P2, "DELL", "AVOTON", 0, OK, p2_not_a_laptop}, ++#endif ++#if DELL_DENVERTON_SUPPORT == 1 ++ {0x8086, 0x19dc, 0x8086, 0x7270, 0, 0, 0, 0, NULL, NULL, NULL, P2, "DELL", "DENVERTON", 0, OK, p2_not_a_laptop}, ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + #endif + { 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, P3, NULL, NULL, 0, NT, NULL}, /* end marker */ + }; +@@ -2559,6 +2571,7 @@ const static struct board_match *board_match_pci_ids(enum board_match_phase phas + } + } + ++#if defined(__i386__) || defined(__x86_64__) + if (board->dmi_pattern) { + if (!has_dmi_support) { + msg_pwarn("Warning: Can't autodetect %s %s, DMI info unavailable.\n", +@@ -2571,7 +2584,7 @@ const static struct board_match *board_match_pci_ids(enum board_match_phase phas + continue; + } + } +- ++#endif // defined(__i386__) || defined(__x86_64__) + return board; + } + +diff --git a/buspirate_spi.c b/buspirate_spi.c +index 9d229f4..f0e84bc 100644 +--- a/buspirate_spi.c ++++ b/buspirate_spi.c +@@ -250,6 +250,7 @@ int buspirate_spi_init(void) + if (!bp_commbuf) { + bp_commbufsize = 0; + msg_perr("Out of memory!\n"); ++ free(dev); + return ERROR_OOM; + } + bp_commbufsize = DEFAULT_BUFSIZE; +@@ -263,8 +264,12 @@ int buspirate_spi_init(void) + return ret; + } + +- if (register_shutdown(buspirate_spi_shutdown, NULL)) ++ if (register_shutdown(buspirate_spi_shutdown, NULL) != 0) { ++ bp_commbufsize = 0; ++ free(bp_commbuf); ++ bp_commbuf = NULL; + return 1; ++ } + + /* This is the brute force version, but it should work. + * It is likely to fail if a previous flashrom run was aborted during a write with the new SPI commands +diff --git a/cbtable.c b/cbtable.c +index e262a84..c100bbb 100644 +--- a/cbtable.c ++++ b/cbtable.c +@@ -261,7 +261,7 @@ int cb_parse_table(const char **vendor, const char **model) + #else + start = 0x0; + #endif +- table_area = physmap_try_ro("low megabyte", start, BYTES_TO_MAP - start); ++ table_area = physmap_ro_unaligned("low megabyte", start, BYTES_TO_MAP - start); + if (ERROR_PTR == table_area) { + msg_perr("Failed getting access to coreboot low tables.\n"); + return -1; +@@ -276,8 +276,9 @@ int cb_parse_table(const char **vendor, const char **model) + if (forward->tag == LB_TAG_FORWARD) { + start = forward->forward; + start &= ~(getpagesize() - 1); +- physunmap(table_area, BYTES_TO_MAP); +- table_area = physmap_try_ro("high tables", start, BYTES_TO_MAP); ++ physunmap_unaligned(table_area, BYTES_TO_MAP); ++ // FIXME: table_area is never unmapped below, nor is it unmapped above in the no-forward case ++ table_area = physmap_ro_unaligned("high tables", start, BYTES_TO_MAP); + if (ERROR_PTR == table_area) { + msg_perr("Failed getting access to coreboot high tables.\n"); + return -1; +diff --git a/chipdrivers.h b/chipdrivers.h +index 091d14c..851e90a 100644 +--- a/chipdrivers.h ++++ b/chipdrivers.h +@@ -64,6 +64,7 @@ int spi_write_chunked(struct flashctx *flash, uint8_t *buf, unsigned int start, + /* spi25_statusreg.c */ + uint8_t spi_read_status_register(struct flashctx *flash); + int spi_write_status_register(struct flashctx *flash, int status); ++void spi_prettyprint_status_register_bit(uint8_t status, int bit); + int spi_prettyprint_status_register_plain(struct flashctx *flash); + int spi_prettyprint_status_register_default_welwip(struct flashctx *flash); + int spi_prettyprint_status_register_default_bp1(struct flashctx *flash); +@@ -109,6 +110,19 @@ int read_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsign + int write_opaque(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); + int erase_opaque(struct flashctx *flash, unsigned int blockaddr, unsigned int blocklen); + ++/* at45db.c */ ++int probe_spi_at45db(struct flashctx *flash); ++int spi_prettyprint_status_register_at45db(struct flashctx *flash); ++int spi_disable_blockprotect_at45db(struct flashctx *flash); ++int spi_read_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); ++int spi_read_at45db_e8(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); ++int spi_write_at45db(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); ++int spi_erase_at45db_page(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45db_block(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45db_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45db_chip(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++int spi_erase_at45cs_sector(struct flashctx *flash, unsigned int addr, unsigned int blocklen); ++ + /* 82802ab.c */ + uint8_t wait_82802ab(struct flashctx *flash); + int probe_82802ab(struct flashctx *flash); +@@ -179,9 +193,10 @@ int printlock_at49f(struct flashctx *flash); + /* w29ee011.c */ + int probe_w29ee011(struct flashctx *flash); + +-/* stm50flw0x0x.c */ +-int erase_sector_stm50flw0x0x(struct flashctx *flash, unsigned int block, unsigned int blocksize); +-int unlock_stm50flw0x0x(struct flashctx *flash); ++/* stm50.c */ ++int erase_sector_stm50(struct flashctx *flash, unsigned int block, unsigned int blocksize); ++int unlock_stm50_uniform(struct flashctx *flash); ++int unlock_stm50_nonuniform(struct flashctx *flash); + + /* en29lv640b.c */ + int probe_en29lv640b(struct flashctx *flash); +diff --git a/chipset_enable.c b/chipset_enable.c +index a2df263..8a8ab66 100644 +--- a/chipset_enable.c ++++ b/chipset_enable.c +@@ -41,6 +41,17 @@ + + #if defined(__i386__) || defined(__x86_64__) + ++#if DELL_AVOTON_SUPPORT == 1 ++uint8_t is_avoton = 0; ++#endif /* DELL_AVOTON_SUPPORT == 1 */ ++ ++#if DELL_DENVERTON_SUPPORT == 1 ++uint8_t is_dnv = 0; ++uint32_t dnv_bios_region_start = 0x00; ++uint32_t dnv_bios_region_size = 0x00; ++uint32_t dnv_bios_region_limit = 0x00; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + static int enable_flash_ali_m1533(struct pci_dev *dev, const char *name) + { + uint8_t tmp; +@@ -260,20 +271,44 @@ static int enable_flash_piix4(struct pci_dev *dev, const char *name) + return 0; + } + +-/* +- * See ie. page 375 of "Intel I/O Controller Hub 7 (ICH7) Family Datasheet" +- * http://download.intel.com/design/chipsets/datashts/30701303.pdf +- */ +-static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_cntl) ++/* Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Poulsbo, Tunnel Creek and other Atom ++ * chipsets/SoCs it is even 32b, but just treating it as 8 bit wide seems to work fine in practice. */ ++static int enable_flash_ich_bios_cntl(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl) + { + uint8_t old, new, wanted; + +- /* +- * Note: the ICH0-ICH5 BIOS_CNTL register is actually 16 bit wide, in Tunnel Creek it is even 32b, but +- * just treating it as 8 bit wide seems to work fine in practice. +- */ +- wanted = old = pci_read_byte(dev, bios_cntl); ++ switch (ich_generation) { ++ case CHIPSET_ICH_UNKNOWN: ++ return ERROR_FATAL; ++ /* Non-SPI-capable */ ++ case CHIPSET_ICH: ++ case CHIPSET_ICH2345: ++ break; ++ /* Atom chipsets are special: The second byte of BIOS_CNTL (D9h) contains a prefetch bit similar to what ++ * other SPI-capable chipsets have at DCh. ++ * The Tunnel Creek datasheet contains a lot of details about the SPI controller, among other things it ++ * mentions that the prefetching and caching does only happen for direct memory reads. ++ * Therefore - at least for Tunnel Creek - it should not matter to flashrom because we use the ++ * programmed access only and not memory mapping. */ ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_POULSBO: ++ case CHIPSET_CENTERTON: ++ old = pci_read_byte(dev, bios_cntl + 1); ++ msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis"); ++ break; ++ case CHIPSET_ICH7: ++ default: /* Future version might behave the same */ ++ old = (pci_read_byte(dev, bios_cntl) >> 2) & 0x3; ++ msg_pdbg("SPI Read Configuration: "); ++ if (old == 3) ++ msg_pdbg("invalid prefetching/caching settings, "); ++ else ++ msg_pdbg("prefetching %sabled, caching %sabled, ", ++ (old & 0x2) ? "en" : "dis", ++ (old & 0x1) ? "dis" : "en"); ++ } + ++ wanted = old = pci_read_byte(dev, bios_cntl); + /* + * Quote from the 6 Series datasheet (Document Number: 324645-004): + * "Bit 5: SMM BIOS Write Protect Disable (SMM_BWP) +@@ -283,11 +318,23 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_ + * + * Try to unset it in any case. + * It won't hurt and makes sense in some cases according to Stefan Reinauer. ++ * ++ * At least in Centerton aforementioned bit is located at bit 7. It is unspecified in all other Atom ++ * and Desktop chipsets before Ibex Peak/5 Series, but we reset bit 5 anyway. + */ +- wanted &= ~(1 << 5); ++ int smm_bwp_bit; ++ if (ich_generation == CHIPSET_CENTERTON) ++ smm_bwp_bit = 7; ++ else ++ smm_bwp_bit = 5; ++ wanted &= ~(1 << smm_bwp_bit); + +- /* Set BIOS Write Enable */ +- wanted |= (1 << 0); ++ /* Tunnel Creek has a cache disable at bit 2 of the lowest BIOS_CNTL byte. */ ++ if (ich_generation == CHIPSET_TUNNEL_CREEK) ++ wanted |= (1 << 2); ++ ++ wanted |= (1 << 0); /* Set BIOS Write Enable */ ++ wanted &= ~(1 << 1); /* Disable lock (futile) */ + + /* Only write the register if it's necessary */ + if (wanted != old) { +@@ -299,64 +346,79 @@ static int enable_flash_ich(struct pci_dev *dev, const char *name, uint8_t bios_ + msg_pdbg("\nBIOS_CNTL = 0x%02x: ", new); + msg_pdbg("BIOS Lock Enable: %sabled, ", (new & (1 << 1)) ? "en" : "dis"); + msg_pdbg("BIOS Write Enable: %sabled\n", (new & (1 << 0)) ? "en" : "dis"); +- if (new & (1 << 5)) ++ if (new & (1 << smm_bwp_bit)) + msg_pwarn("Warning: BIOS region SMM protection is enabled!\n"); + +- + if (new != wanted) +- msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x on %s failed.\n" +- "New value is 0x%02x.\n", bios_cntl, old, wanted, name, new); ++ msg_pwarn("Warning: Setting Bios Control at 0x%x from 0x%02x to 0x%02x failed.\n" ++ "New value is 0x%02x.\n", bios_cntl, old, wanted, new); + +- /* Return an error if we could not set the write enable */ ++ /* Return an error if we could not set the write enable only. */ + if (!(new & (1 << 0))) + return -1; + + return 0; + } + +-static int enable_flash_ich_4e(struct pci_dev *dev, const char *name) ++static int enable_flash_ich_fwh_decode(struct pci_dev *dev, enum ich_chipset ich_generation) + { +- /* +- * Note: ICH5 has registers similar to FWH_SEL1, FWH_SEL2 and +- * FWH_DEC_EN1, but they are called FB_SEL1, FB_SEL2, FB_DEC_EN1 and +- * FB_DEC_EN2. +- */ +- internal_buses_supported = BUS_FWH; +- return enable_flash_ich(dev, name, 0x4e); +-} +- +-static int enable_flash_ich_dc(struct pci_dev *dev, const char *name) +-{ +- uint32_t fwh_conf; +- int i, tmp; +- char *idsel = NULL; +- int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0; +- int contiguous = 1; ++ uint8_t fwh_sel1 = 0, fwh_sel2 = 0, fwh_dec_en_lo = 0, fwh_dec_en_hi = 0; /* silence compilers */ ++ bool implemented = 0; ++ switch (ich_generation) { ++ case CHIPSET_ICH: ++ /* FIXME: Unlike later chipsets, ICH and ICH-0 do only support mapping of the top-most 4MB ++ * and therefore do only feature FWH_DEC_EN (E3h, different default too) and FWH_SEL (E8h). */ ++ break; ++ case CHIPSET_ICH2345: ++ fwh_sel1 = 0xe8; ++ fwh_sel2 = 0xee; ++ fwh_dec_en_lo = 0xf0; ++ fwh_dec_en_hi = 0xe3; ++ implemented = 1; ++ break; ++ case CHIPSET_POULSBO: ++ case CHIPSET_TUNNEL_CREEK: ++ /* FIXME: Similar to ICH and ICH-0, Tunnel Creek and Poulsbo do only feature one register each, ++ * FWH_DEC_EN (D7h) and FWH_SEL (D0h). */ ++ break; ++ case CHIPSET_CENTERTON: ++ /* FIXME: Similar to above FWH_DEC_EN (D4h) and FWH_SEL (D0h). */ ++ break; ++ case CHIPSET_ICH6: ++ case CHIPSET_ICH7: ++ default: /* Future version might behave the same */ ++ fwh_sel1 = 0xd0; ++ fwh_sel2 = 0xd4; ++ fwh_dec_en_lo = 0xd8; ++ fwh_dec_en_hi = 0xd9; ++ implemented = 1; ++ break; ++ } + +- idsel = extract_programmer_param("fwh_idsel"); ++ char *idsel = extract_programmer_param("fwh_idsel"); + if (idsel && strlen(idsel)) { +- uint64_t fwh_idsel_old, fwh_idsel; ++ if (!implemented) { ++ msg_perr("Error: fwh_idsel= specified, but (yet) unsupported on this chipset.\n"); ++ goto idsel_garbage_out; ++ } + errno = 0; + /* Base 16, nothing else makes sense. */ +- fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16); ++ uint64_t fwh_idsel = (uint64_t)strtoull(idsel, NULL, 16); + if (errno) { +- msg_perr("Error: fwh_idsel= specified, but value could " +- "not be converted.\n"); ++ msg_perr("Error: fwh_idsel= specified, but value could not be converted.\n"); + goto idsel_garbage_out; + } + if (fwh_idsel & 0xffff000000000000ULL) { +- msg_perr("Error: fwh_idsel= specified, but value had " +- "unused bits set.\n"); ++ msg_perr("Error: fwh_idsel= specified, but value had unused bits set.\n"); + goto idsel_garbage_out; + } +- fwh_idsel_old = pci_read_long(dev, 0xd0); ++ uint64_t fwh_idsel_old = pci_read_long(dev, fwh_sel1); + fwh_idsel_old <<= 16; +- fwh_idsel_old |= pci_read_word(dev, 0xd4); +- msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to " +- "0x%012" PRIx64 " for top 16 MB.", fwh_idsel_old, +- fwh_idsel); +- rpci_write_long(dev, 0xd0, (fwh_idsel >> 16) & 0xffffffff); +- rpci_write_word(dev, 0xd4, fwh_idsel & 0xffff); ++ fwh_idsel_old |= pci_read_word(dev, fwh_sel2); ++ msg_pdbg("\nSetting IDSEL from 0x%012" PRIx64 " to 0x%012" PRIx64 " for top 16 MB.", ++ fwh_idsel_old, fwh_idsel); ++ rpci_write_long(dev, fwh_sel1, (fwh_idsel >> 16) & 0xffffffff); ++ rpci_write_word(dev, fwh_sel2, fwh_idsel & 0xffff); + /* FIXME: Decode settings are not changed. */ + } else if (idsel) { + msg_perr("Error: fwh_idsel= specified, but no value given.\n"); +@@ -366,15 +428,23 @@ idsel_garbage_out: + } + free(idsel); + ++ if (!implemented) { ++ msg_pdbg2("FWH IDSEL handling is not implemented on this chipset."); ++ return 0; ++ } ++ + /* Ignore all legacy ranges below 1 MB. + * We currently only support flashing the chip which responds to + * IDSEL=0. To support IDSEL!=0, flashbase and decode size calculations + * have to be adjusted. + */ ++ int max_decode_fwh_idsel = 0, max_decode_fwh_decode = 0; ++ bool contiguous = 1; ++ uint32_t fwh_conf = pci_read_long(dev, fwh_sel1); ++ int i; + /* FWH_SEL1 */ +- fwh_conf = pci_read_long(dev, 0xd0); + for (i = 7; i >= 0; i--) { +- tmp = (fwh_conf >> (i * 4)) & 0xf; ++ int tmp = (fwh_conf >> (i * 4)) & 0xf; + msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x", + (0x1ff8 + i) * 0x80000, + (0x1ff0 + i) * 0x80000, +@@ -386,9 +456,9 @@ idsel_garbage_out: + } + } + /* FWH_SEL2 */ +- fwh_conf = pci_read_word(dev, 0xd4); ++ fwh_conf = pci_read_word(dev, fwh_sel2); + for (i = 3; i >= 0; i--) { +- tmp = (fwh_conf >> (i * 4)) & 0xf; ++ int tmp = (fwh_conf >> (i * 4)) & 0xf; + msg_pdbg("\n0x%08x/0x%08x FWH IDSEL: 0x%x", + (0xff4 + i) * 0x100000, + (0xff0 + i) * 0x100000, +@@ -401,9 +471,11 @@ idsel_garbage_out: + } + contiguous = 1; + /* FWH_DEC_EN1 */ +- fwh_conf = pci_read_word(dev, 0xd8); ++ fwh_conf = pci_read_byte(dev, fwh_dec_en_hi); ++ fwh_conf <<= 8; ++ fwh_conf |= pci_read_byte(dev, fwh_dec_en_lo); + for (i = 7; i >= 0; i--) { +- tmp = (fwh_conf >> (i + 0x8)) & 0x1; ++ int tmp = (fwh_conf >> (i + 0x8)) & 0x1; + msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled", + (0x1ff8 + i) * 0x80000, + (0x1ff0 + i) * 0x80000, +@@ -415,7 +487,7 @@ idsel_garbage_out: + } + } + for (i = 3; i >= 0; i--) { +- tmp = (fwh_conf >> i) & 0x1; ++ int tmp = (fwh_conf >> i) & 0x1; + msg_pdbg("\n0x%08x/0x%08x FWH decode %sabled", + (0xff4 + i) * 0x100000, + (0xff0 + i) * 0x100000, +@@ -429,99 +501,66 @@ idsel_garbage_out: + max_rom_decode.fwh = min(max_decode_fwh_idsel, max_decode_fwh_decode); + msg_pdbg("\nMaximum FWH chip size: 0x%x bytes", max_rom_decode.fwh); + +- /* If we're called by enable_flash_ich_dc_spi, it will override +- * internal_buses_supported anyway. +- */ +- internal_buses_supported = BUS_FWH; +- return enable_flash_ich(dev, name, 0xdc); ++ return 0; + } + +-static int enable_flash_poulsbo(struct pci_dev *dev, const char *name) ++static int enable_flash_ich_fwh(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl) + { +- uint16_t old, new; + int err; + +- if ((err = enable_flash_ich(dev, name, 0xd8)) != 0) ++ /* Configure FWH IDSEL decoder maps. */ ++ if ((err = enable_flash_ich_fwh_decode(dev, ich_generation)) != 0) + return err; + +- old = pci_read_byte(dev, 0xd9); +- msg_pdbg("BIOS Prefetch Enable: %sabled, ", +- (old & 1) ? "en" : "dis"); +- new = old & ~1; +- +- if (new != old) +- rpci_write_byte(dev, 0xd9, new); +- + internal_buses_supported = BUS_FWH; +- return 0; ++ return enable_flash_ich_bios_cntl(dev, ich_generation, bios_cntl); + } + +-static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name) ++static int enable_flash_ich0(struct pci_dev *dev, const char *name) + { +- uint16_t old, new; +- uint32_t tmp, bnt; +- void *rcrb; +- int ret; +- +- /* Enable Flash Writes */ +- ret = enable_flash_ich(dev, name, 0xd8); +- if (ret == ERROR_FATAL) +- return ret; +- +- /* Make sure BIOS prefetch mechanism is disabled */ +- old = pci_read_byte(dev, 0xd9); +- msg_pdbg("BIOS Prefetch Enable: %sabled, ", (old & 1) ? "en" : "dis"); +- new = old & ~1; +- if (new != old) +- rpci_write_byte(dev, 0xd9, new); +- +- /* Get physical address of Root Complex Register Block */ +- tmp = pci_read_long(dev, 0xf0) & 0xffffc000; +- msg_pdbg("\nRoot Complex Register Block address = 0x%x\n", tmp); +- +- /* Map RCBA to virtual memory */ +- rcrb = physmap("ICH RCRB", tmp, 0x4000); +- +- /* Test Boot BIOS Strap Status */ +- bnt = mmio_readl(rcrb + 0x3410); +- if (bnt & 0x02) { +- /* If strapped to LPC, no SPI initialization is required */ +- internal_buses_supported = BUS_FWH; +- return 0; +- } ++ return enable_flash_ich_fwh(dev, CHIPSET_ICH, 0x4e); ++} + +- /* This adds BUS_SPI */ +- if (ich_init_spi(dev, tmp, rcrb, 7) != 0) { +- if (!ret) +- ret = ERROR_NONFATAL; +- } ++static int enable_flash_ich2345(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_fwh(dev, CHIPSET_ICH2345, 0x4e); ++} + +- return ret; ++static int enable_flash_ich6(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_fwh(dev, CHIPSET_ICH6, 0xdc); + } + +-static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, +- enum ich_chipset ich_generation) ++static int enable_flash_poulsbo(struct pci_dev *dev, const char *name) + { +- int ret, ret_spi; +- uint8_t bbs, buc; +- uint32_t tmp, gcs; +- void *rcrb; +- const char *const *straps_names; ++ return enable_flash_ich_fwh(dev, CHIPSET_POULSBO, 0xd8); ++} + ++static int enable_flash_ich_spi(struct pci_dev *dev, enum ich_chipset ich_generation, uint8_t bios_cntl) ++{ + static const char *const straps_names_EP80579[] = { "SPI", "reserved", "reserved", "LPC" }; + static const char *const straps_names_ich7_nm10[] = { "reserved", "SPI", "PCI", "LPC" }; ++ static const char *const straps_names_tunnel_creek[] = { "SPI", "LPC" }; + static const char *const straps_names_ich8910[] = { "SPI", "SPI", "PCI", "LPC" }; + static const char *const straps_names_pch567[] = { "LPC", "reserved", "PCI", "SPI" }; + static const char *const straps_names_pch8[] = { "LPC", "reserved", "reserved", "SPI" }; +- static const char *const straps_names_pch8_lp[] = { "SPI", "LPC", "unknown", "unknown" }; ++ static const char *const straps_names_pch8_lp[] = { "SPI", "LPC" }; + static const char *const straps_names_unknown[] = { "unknown", "unknown", "unknown", "unknown" }; ++#ifdef DELL_AVOTON_SUPPORT ++ static const char *const straps_names_avoton[] = { "LPC", "reserved", "reserved", "SPI" }; ++ uint32_t tmp; ++ int ret_fwh = 0; ++ uint32_t new, old; ++ void *spibar; ++#endif + ++ const char *const *straps_names; + switch (ich_generation) { + case CHIPSET_ICH7: + /* EP80579 may need further changes, but this is the least + * intrusive way to get correct BOOT Strap printing without + * changing the rest of its code path). */ +- if (strcmp(name, "EP80579") == 0) ++ if (dev->device_id == 0x5031) + straps_names = straps_names_EP80579; + else + straps_names = straps_names_ich7_nm10; +@@ -531,6 +570,9 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + case CHIPSET_ICH10: + straps_names = straps_names_ich8910; + break; ++ case CHIPSET_TUNNEL_CREEK: ++ straps_names = straps_names_tunnel_creek; ++ break; + case CHIPSET_5_SERIES_IBEX_PEAK: + case CHIPSET_6_SERIES_COUGAR_POINT: + case CHIPSET_7_SERIES_PANTHER_POINT: +@@ -543,33 +585,41 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + straps_names = straps_names_pch8_lp; + break; + case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet ++ case CHIPSET_CENTERTON: // FIXME: Datasheet does not mention GCS at all + straps_names = straps_names_unknown; + break; ++#ifdef DELL_AVOTON_SUPPORT ++ case CHIPSET_AVOTON: ++ straps_names = straps_names_avoton; ++ break; ++#endif + default: +- msg_gerr("%s: unknown ICH generation. Please report!\n", +- __func__); ++ msg_gerr("%s: unknown ICH generation. Please report!\n", __func__); + straps_names = straps_names_unknown; + break; + } + +- /* Enable Flash Writes */ +- ret = enable_flash_ich_dc(dev, name); +- if (ret == ERROR_FATAL) +- return ret; +- + /* Get physical address of Root Complex Register Block */ +- tmp = pci_read_long(dev, 0xf0) & 0xffffc000; +- msg_pdbg("Root Complex Register Block address = 0x%x\n", tmp); ++ uint32_t rcra = pci_read_long(dev, 0xf0) & 0xffffc000; ++ msg_pdbg("Root Complex Register Block address = 0x%x\n", rcra); + + /* Map RCBA to virtual memory */ +- rcrb = physmap("ICH RCRB", tmp, 0x4000); ++ void *rcrb = rphysmap("ICH RCRB", rcra, 0x4000); ++ if (rcrb == ERROR_PTR) ++ return ERROR_FATAL; + +- gcs = mmio_readl(rcrb + 0x3410); ++#ifdef DELL_AVOTON_SUPPORT ++ if (ich_generation != CHIPSET_AVOTON) { ++#endif ++ uint32_t gcs = mmio_readl(rcrb + 0x3410); + msg_pdbg("GCS = 0x%x: ", gcs); +- msg_pdbg("BIOS Interface Lock-Down: %sabled, ", +- (gcs & 0x1) ? "en" : "dis"); ++ msg_pdbg("BIOS Interface Lock-Down: %sabled, ", (gcs & 0x1) ? "en" : "dis"); + ++ uint8_t bbs; + switch (ich_generation) { ++ case CHIPSET_TUNNEL_CREEK: ++ bbs = (gcs >> 1) & 0x1; ++ break; + case CHIPSET_8_SERIES_LYNX_POINT_LP: + case CHIPSET_8_SERIES_WELLSBURG: // FIXME: check datasheet + /* Lynx Point LP uses a single bit for GCS */ +@@ -582,91 +632,187 @@ static int enable_flash_ich_dc_spi(struct pci_dev *dev, const char *name, + } + msg_pdbg("Boot BIOS Straps: 0x%x (%s)\n", bbs, straps_names[bbs]); + +- buc = mmio_readb(rcrb + 0x3414); +- msg_pdbg("Top Swap : %s\n", +- (buc & 1) ? "enabled (A16 inverted)" : "not enabled"); ++ if (ich_generation != CHIPSET_TUNNEL_CREEK && ich_generation != CHIPSET_CENTERTON) { ++ uint8_t buc = mmio_readb(rcrb + 0x3414); ++ msg_pdbg("Top Swap : %s\n", (buc & 1) ? "enabled (A16(+) inverted)" : "not enabled"); ++ } + +- /* It seems the ICH7 does not support SPI and LPC chips at the same +- * time. At least not with our current code. So we prevent searching +- * on ICH7 when the southbridge is strapped to LPC +- */ +- internal_buses_supported = BUS_FWH; +- if (ich_generation == CHIPSET_ICH7) { +- if (bbs == 0x03) { +- /* If strapped to LPC, no further SPI initialization is +- * required. */ +- return ret; +- } else { +- /* Disable LPC/FWH if strapped to PCI or SPI */ +- internal_buses_supported = BUS_NONE; +- } ++ /* Handle FWH-related parameters and initialization */ ++#ifdef DELL_AVOTON_SUPPORT ++ ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl); ++#else ++ int ret_fwh = enable_flash_ich_fwh(dev, ich_generation, bios_cntl); ++#endif ++ if (ret_fwh == ERROR_FATAL) ++ return ret_fwh; ++ ++ /* SPIBAR is at RCRB+0x3020 for ICH[78], Tunnel Creek and Centerton, and RCRB+0x3800 for ICH9. */ ++ uint16_t spibar_offset; ++ switch (ich_generation) { ++ case CHIPSET_ICH_UNKNOWN: ++ return ERROR_FATAL; ++ case CHIPSET_ICH7: ++ case CHIPSET_ICH8: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: ++ spibar_offset = 0x3020; ++ break; ++ case CHIPSET_ICH9: ++ default: /* Future version might behave the same */ ++ spibar_offset = 0x3800; ++ break; + } ++ msg_pdbg("SPIBAR = 0x%0*" PRIxPTR " + 0x%04x\n", PRIxPTR_WIDTH, (uintptr_t)rcrb, spibar_offset); ++#ifndef DELL_AVOTON_SUPPORT ++ void *spibar = rcrb + spibar_offset; ++#else ++ spibar = rcrb + spibar_offset; ++ } else { ++ tmp = pci_read_long(dev, 0x54) & 0xFFFFFE00; ++ spibar = rphysmap("ICH SPIBAR", tmp, 0x4000); ++ msg_pdbg("SPIBAR = 0x%x\n", tmp); ++ ++ /* BIOS Control Register */ ++ tmp = mmio_readl(spibar + bios_cntl); ++ msg_pdbg("0xFC: 0x%08x (BIOS_CONTROL_REGISTER_BIOS : BCR)\n", tmp); ++ msg_pdbg("BIOS Write Protect Disable : %sabled, \n", ++ (tmp & (1 << 0)) ? "en" : "dis"); ++ msg_pdbg("\nBIOS Lock Enable: %sabled, \n", ++ (tmp & (1 << 1)) ? "en" : "dis"); ++ if (tmp != 1) { ++ mmio_writel(0x1, (spibar + bios_cntl)); ++ } ++ tmp = mmio_readl(spibar + bios_cntl); ++ msg_pdbg("0xFC: 0x%08x (BIOS_CONTROL_REGISTER_BIOS : BCR)\n", tmp); ++ msg_pdbg("BIOS Write Protect Disable : %sabled, \n", ++ (tmp & (1 << 0)) ? "en" : "dis"); ++ if (tmp != 1) { ++ msg_perr("Reboot and change BIOS-> IntelRCSetup -> Relax Security Config -> Disabled to Enabled\n"); ++ return ERROR_FATAL; /* Signal error */ ++ } ++ old = mmio_readb(spibar + 0xFC); ++ msg_pdbg("SPI Read Configuration: \n"); ++ new = (old >> 2) & 0x3; ++ switch (new) { ++ case 0: ++ case 1: ++ case 2: ++ msg_pdbg("prefetching %sabled, caching %sabled, \n", ++ (new & 0x2) ? "en" : "dis", ++ (new & 0x1) ? "dis" : "en"); ++ break; ++ default: ++ msg_pdbg("invalid prefetching/caching settings, \n"); ++ break; ++ } ++ } ++#endif ++ + + /* This adds BUS_SPI */ +- ret_spi = ich_init_spi(dev, tmp, rcrb, ich_generation); ++ int ret_spi = ich_init_spi(dev, spibar, ich_generation); + if (ret_spi == ERROR_FATAL) + return ret_spi; + +- if (ret || ret_spi) +- ret = ERROR_NONFATAL; ++ if (ret_fwh || ret_spi) ++ return ERROR_NONFATAL; + +- return ret; ++ return 0; ++} ++ ++static int enable_flash_tunnelcreek(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_spi(dev, CHIPSET_TUNNEL_CREEK, 0xd8); ++} ++ ++static int enable_flash_s12x0(struct pci_dev *dev, const char *name) ++{ ++ return enable_flash_ich_spi(dev, CHIPSET_CENTERTON, 0xd8); + } + + static int enable_flash_ich7(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH7); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH7, 0xdc); + } + + static int enable_flash_ich8(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH8); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH8, 0xdc); + } + + static int enable_flash_ich9(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH9); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH9, 0xdc); + } + + static int enable_flash_ich10(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_ICH10); ++ return enable_flash_ich_spi(dev, CHIPSET_ICH10, 0xdc); + } + ++#ifdef DELL_AVOTON_SUPPORT ++static int enable_flash_c2000(struct pci_dev *dev, const char *name) ++{ ++ is_avoton = 1; ++ return enable_flash_ich_spi(dev, CHIPSET_AVOTON, 0xfc); ++} ++#endif ++ ++#if DELL_DENVERTON_SUPPORT == 1 ++static int enable_flash_denverton(struct pci_dev *dev, const char *name) ++{ ++ void *spibar; ++ int32_t ret_spi; ++ uint32_t sbase; ++ enum ich_chipset ich_generation = CHIPSET_DENVERTON; ++ ++ is_dnv = 1; ++ internal_buses_supported = BUS_FWH; ++ ++ /* GET physical address of SPI Base Address and map it */ ++ sbase = pci_read_long(dev, 0x10) & 0xfffffe00; ++ msg_pdbg("SPI_BASE_ADDRESS = 0x%x\n", sbase); ++ spibar = rphysmap("DENVERTON SBASE", sbase, 512); ++ enable_flash_ich_bios_cntl(dev, ich_generation, 0xdc); ++ ret_spi = ich_init_spi(dev, spibar, ich_generation); ++ return ret_spi; ++} ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + /* Ibex Peak aka. 5 series & 3400 series */ + static int enable_flash_pch5(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_5_SERIES_IBEX_PEAK); ++ return enable_flash_ich_spi(dev, CHIPSET_5_SERIES_IBEX_PEAK, 0xdc); + } + + /* Cougar Point aka. 6 series & c200 series */ + static int enable_flash_pch6(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_6_SERIES_COUGAR_POINT); ++ return enable_flash_ich_spi(dev, CHIPSET_6_SERIES_COUGAR_POINT, 0xdc); + } + + /* Panther Point aka. 7 series */ + static int enable_flash_pch7(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_7_SERIES_PANTHER_POINT); ++ return enable_flash_ich_spi(dev, CHIPSET_7_SERIES_PANTHER_POINT, 0xdc); + } + + /* Lynx Point aka. 8 series */ + static int enable_flash_pch8(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT); ++ return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT, 0xdc); + } + +-/* Lynx Point aka. 8 series low-power */ ++/* Lynx Point LP aka. 8 series low-power */ + static int enable_flash_pch8_lp(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_LYNX_POINT_LP); ++ return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_LYNX_POINT_LP, 0xdc); + } + + /* Wellsburg (for Haswell-EP Xeons) */ + static int enable_flash_pch8_wb(struct pci_dev *dev, const char *name) + { +- return enable_flash_ich_dc_spi(dev, name, CHIPSET_8_SERIES_WELLSBURG); ++ return enable_flash_ich_spi(dev, CHIPSET_8_SERIES_WELLSBURG, 0xdc); + } + + static int via_no_byte_merge(struct pci_dev *dev, const char *name) +@@ -737,10 +883,8 @@ static int enable_flash_vt_vx(struct pci_dev *dev, const char *name) + case 0x8410: /* VX900 */ + mmio_base = pci_read_long(dev, 0xbc) << 8; + mmio_base_physmapped = physmap("VIA VX MMIO register", mmio_base, SPI_CNTL_LEN); +- if (mmio_base_physmapped == ERROR_PTR) { +- physunmap(mmio_base_physmapped, SPI_CNTL_LEN); ++ if (mmio_base_physmapped == ERROR_PTR) + return ERROR_FATAL; +- } + + /* Offset 0 - Bit 0 holds SPI Bus0 Enable Bit. */ + spi_cntl = mmio_readl(mmio_base_physmapped) + 0x00; +@@ -882,22 +1026,29 @@ static int enable_flash_sc1100(struct pci_dev *dev, const char *name) + return 0; + } + +-/* Works for AMD-8111, VIA VT82C586A/B, VIA VT82C686A/B. */ +-static int enable_flash_amd8111(struct pci_dev *dev, const char *name) ++/* Works for AMD-768, AMD-8111, VIA VT82C586A/B, VIA VT82C596, VIA VT82C686A/B. ++ * ++ * ROM decode control register matrix ++ * AMD-768 AMD-8111 VT82C586A/B VT82C596 VT82C686A/B ++ * 7 FFC0_0000h–FFFF_FFFFh <- FFFE0000h-FFFEFFFFh <- <- ++ * 6 FFB0_0000h–FFBF_FFFFh <- FFF80000h-FFFDFFFFh <- <- ++ * 5 00E8... <- <- FFF00000h-FFF7FFFFh <- ++ */ ++static int enable_flash_amd_via(struct pci_dev *dev, const char *name, uint8_t decode_val) + { + #define AMD_MAPREG 0x43 + #define AMD_ENREG 0x40 + uint8_t old, new; + +- /* Enable decoding at 0xffb00000 to 0xffffffff. */ + old = pci_read_byte(dev, AMD_MAPREG); +- new = old | 0xC0; ++ new = old | decode_val; + if (new != old) { + rpci_write_byte(dev, AMD_MAPREG, new); + if (pci_read_byte(dev, AMD_MAPREG) != new) { +- msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", ++ msg_pwarn("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", + AMD_MAPREG, new, name); +- } ++ } else ++ msg_pdbg("Changed ROM decode range to 0x%02x successfully.\n", new); + } + + /* Enable 'ROM write' bit. */ +@@ -908,14 +1059,37 @@ static int enable_flash_amd8111(struct pci_dev *dev, const char *name) + rpci_write_byte(dev, AMD_ENREG, new); + + if (pci_read_byte(dev, AMD_ENREG) != new) { +- msg_pinfo("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", ++ msg_pwarn("Setting register 0x%x to 0x%02x on %s failed (WARNING ONLY).\n", + AMD_ENREG, new, name); +- return -1; ++ return ERROR_NONFATAL; + } ++ msg_pdbg2("Set ROM enable bit successfully.\n"); + + return 0; + } + ++static int enable_flash_amd_768_8111(struct pci_dev *dev, const char *name) ++{ ++ /* Enable decoding of 0xFFB00000 to 0xFFFFFFFF (5 MB). */ ++ max_rom_decode.lpc = 5 * 1024 * 1024; ++ return enable_flash_amd_via(dev, name, 0xC0); ++} ++ ++static int enable_flash_vt82c586(struct pci_dev *dev, const char *name) ++{ ++ /* Enable decoding of 0xFFF80000 to 0xFFFFFFFF. (512 kB) */ ++ max_rom_decode.parallel = 512 * 1024; ++ return enable_flash_amd_via(dev, name, 0xC0); ++} ++ ++/* Works for VT82C686A/B too. */ ++static int enable_flash_vt82c596(struct pci_dev *dev, const char *name) ++{ ++ /* Enable decoding of 0xFFF80000 to 0xFFFFFFFF. (1 MB) */ ++ max_rom_decode.parallel = 1024 * 1024; ++ return enable_flash_amd_via(dev, name, 0xE0); ++} ++ + static int enable_flash_sb600(struct pci_dev *dev, const char *name) + { + uint32_t prot; +@@ -1257,6 +1431,8 @@ static int get_flashbase_sc520(struct pci_dev *dev, const char *name) + + /* 1. Map MMCR */ + mmcr = physmap("Elan SC520 MMCR", 0xfffef000, getpagesize()); ++ if (mmcr == ERROR_PTR) ++ return ERROR_FATAL; + + /* 2. Scan PAR0 (0x88) - PAR15 (0xc4) for + * BOOTCS region (PARx[31:29] = 100b)e +@@ -1302,8 +1478,8 @@ const struct penable chipset_enables[] = { + {0x1022, 0x2080, OK, "AMD", "CS5536", enable_flash_cs5536}, + {0x1022, 0x2090, OK, "AMD", "CS5536", enable_flash_cs5536}, + {0x1022, 0x3000, OK, "AMD", "Elan SC520", get_flashbase_sc520}, +- {0x1022, 0x7440, OK, "AMD", "AMD-768", enable_flash_amd8111}, +- {0x1022, 0x7468, OK, "AMD", "AMD8111", enable_flash_amd8111}, ++ {0x1022, 0x7440, OK, "AMD", "AMD-768", enable_flash_amd_768_8111}, ++ {0x1022, 0x7468, OK, "AMD", "AMD-8111", enable_flash_amd_768_8111}, + {0x1022, 0x780e, OK, "AMD", "FCH", enable_flash_sb600}, + {0x1039, 0x0406, NT, "SiS", "501/5101/5501", enable_flash_sis501}, + {0x1039, 0x0496, NT, "SiS", "85C496+497", enable_flash_sis85c496}, +@@ -1388,9 +1564,9 @@ const struct penable chipset_enables[] = { + {0x1106, 0x0691, OK, "VIA", "VT82C69x", via_no_byte_merge}, + {0x1106, 0x8601, NT, "VIA", "VT8601T", via_no_byte_merge}, + /* VIA southbridges */ +- {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_amd8111}, +- {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_amd8111}, +- {0x1106, 0x0686, OK, "VIA", "VT82C686A/B", enable_flash_amd8111}, ++ {0x1106, 0x0586, OK, "VIA", "VT82C586A/B", enable_flash_vt82c586}, ++ {0x1106, 0x0596, OK, "VIA", "VT82C596", enable_flash_vt82c596}, ++ {0x1106, 0x0686, OK, "VIA", "VT82C686A/B", enable_flash_vt82c596}, + {0x1106, 0x3074, OK, "VIA", "VT8233", enable_flash_vt823x}, + {0x1106, 0x3147, OK, "VIA", "VT8233A", enable_flash_vt823x}, + {0x1106, 0x3177, OK, "VIA", "VT8235", enable_flash_vt823x}, +@@ -1405,6 +1581,7 @@ const struct penable chipset_enables[] = { + {0x1166, 0x0200, OK, "Broadcom", "OSB4", enable_flash_osb4}, + {0x1166, 0x0205, OK, "Broadcom", "HT-1000", enable_flash_ht1000}, + {0x17f3, 0x6030, OK, "RDC", "R8610/R3210", enable_flash_rdc_r8610}, ++ {0x8086, 0x0c60, NT, "Intel", "S12x0", enable_flash_s12x0}, + {0x8086, 0x122e, OK, "Intel", "PIIX", enable_flash_piix4}, + {0x8086, 0x1234, NT, "Intel", "MPIIX", enable_flash_piix4}, + {0x8086, 0x1c44, OK, "Intel", "Z68", enable_flash_pch6}, +@@ -1441,21 +1618,21 @@ const struct penable chipset_enables[] = { + {0x8086, 0x1e5f, NT, "Intel", "NM70", enable_flash_pch7}, + {0x8086, 0x2310, NT, "Intel", "DH89xxCC", enable_flash_pch7}, + {0x8086, 0x2390, NT, "Intel", "Coleto Creek", enable_flash_pch7}, +- {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich_4e}, +- {0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich_4e}, +- {0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich_4e}, +- {0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich_4e}, +- {0x8086, 0x2450, NT, "Intel", "C-ICH", enable_flash_ich_4e}, +- {0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich_4e}, +- {0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich_4e}, +- {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich_4e}, +- {0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich_4e}, +- {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich_4e}, +- {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich_4e}, +- {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich_dc}, +- {0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich_dc}, +- {0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW", enable_flash_ich_dc}, +- {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich_dc}, ++ {0x8086, 0x2410, OK, "Intel", "ICH", enable_flash_ich0}, ++ {0x8086, 0x2420, OK, "Intel", "ICH0", enable_flash_ich0}, ++ {0x8086, 0x2440, OK, "Intel", "ICH2", enable_flash_ich2345}, ++ {0x8086, 0x244c, OK, "Intel", "ICH2-M", enable_flash_ich2345}, ++ {0x8086, 0x2450, NT, "Intel", "C-ICH", enable_flash_ich2345}, ++ {0x8086, 0x2480, OK, "Intel", "ICH3-S", enable_flash_ich2345}, ++ {0x8086, 0x248c, OK, "Intel", "ICH3-M", enable_flash_ich2345}, ++ {0x8086, 0x24c0, OK, "Intel", "ICH4/ICH4-L", enable_flash_ich2345}, ++ {0x8086, 0x24cc, OK, "Intel", "ICH4-M", enable_flash_ich2345}, ++ {0x8086, 0x24d0, OK, "Intel", "ICH5/ICH5R", enable_flash_ich2345}, ++ {0x8086, 0x25a1, OK, "Intel", "6300ESB", enable_flash_ich2345}, ++ {0x8086, 0x2640, OK, "Intel", "ICH6/ICH6R", enable_flash_ich6}, ++ {0x8086, 0x2641, OK, "Intel", "ICH6-M", enable_flash_ich6}, ++ {0x8086, 0x2642, NT, "Intel", "ICH6W/ICH6RW", enable_flash_ich6}, ++ {0x8086, 0x2670, OK, "Intel", "631xESB/632xESB/3100", enable_flash_ich6}, + {0x8086, 0x27b0, OK, "Intel", "ICH7DH", enable_flash_ich7}, + {0x8086, 0x27b8, OK, "Intel", "ICH7/ICH7R", enable_flash_ich7}, + {0x8086, 0x27b9, OK, "Intel", "ICH7M", enable_flash_ich7}, +@@ -1570,6 +1747,12 @@ const struct penable chipset_enables[] = { + {0x8086, 0x8d5d, NT, "Intel", "Wellsburg", enable_flash_pch8_wb}, + {0x8086, 0x8d5e, NT, "Intel", "Wellsburg", enable_flash_pch8_wb}, + {0x8086, 0x8d5f, NT, "Intel", "Wellsburg", enable_flash_pch8_wb}, ++#ifdef DELL_AVOTON_SUPPORT ++ {0x8086, 0x1f38, OK, "Intel", "C2000", enable_flash_c2000}, ++#endif ++#if DELL_DENVERTON_SUPPORT == 1 ++ {0x8086, 0x19e0, OK, "Intel", "Denverton", enable_flash_denverton}, ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + #endif + {0}, + }; +@@ -1597,14 +1780,23 @@ int chipset_flash_enable(void) + chipset_enables[i].device_name); + continue; + } ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Found chipset \"%s %s\"", ++ chipset_enables[i].vendor_name, ++ chipset_enables[i].device_name); ++#else + msg_pinfo("Found chipset \"%s %s\"", + chipset_enables[i].vendor_name, + chipset_enables[i].device_name); ++#endif + msg_pdbg(" with PCI ID %04x:%04x", + chipset_enables[i].vendor_id, + chipset_enables[i].device_id); ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg(". "); ++#else + msg_pinfo(". "); +- ++#endif + if (chipset_enables[i].status == NT) { + msg_pinfo("\nThis chipset is marked as untested. If " + "you are using an up-to-date version\nof " +@@ -1614,20 +1806,44 @@ int chipset_flash_enable(void) + "flashrom@flashrom.org including a verbose " + "(-V) log.\nThank you!\n"); + } ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Enabling flash write... "); ++#else + msg_pinfo("Enabling flash write... "); ++#endif + ret = chipset_enables[i].doit(dev, + chipset_enables[i].device_name); + if (ret == NOT_DONE_YET) { + ret = -2; ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("OK - searching further chips.\n"); ++#else + msg_pinfo("OK - searching further chips.\n"); ++#endif + } else if (ret < 0) ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("FAILED!\n"); ++#else + msg_pinfo("FAILED!\n"); ++#endif + else if (ret == 0) ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("OK.\n"); ++#else + msg_pinfo("OK.\n"); ++#endif + else if (ret == ERROR_NONFATAL) ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("PROBLEMS, continuing anyway\n"); ++#else + msg_pinfo("PROBLEMS, continuing anyway\n"); ++#endif + if (ret == ERROR_FATAL) { ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("FATAL ERROR!\n"); ++#else + msg_perr("FATAL ERROR!\n"); ++#endif + return ret; + } + } +diff --git a/cli_classic.c b/cli_classic.c +index 4c71d07..09565f4 100644 +--- a/cli_classic.c ++++ b/cli_classic.c +@@ -31,6 +31,10 @@ + #include "flashchips.h" + #include "programmer.h" + ++#if DELL_DENVERTON_SUPPORT == 1 ++extern int8_t is_dnv; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + static void cli_classic_usage(const char *name) + { + printf("Please note that the command line interface for flashrom has changed between\n" +@@ -136,9 +140,10 @@ int main(int argc, char *argv[]) + char *tempstr = NULL; + char *pparam = NULL; + ++#ifndef FORCE10_SPI_CHANGE + print_version(); + print_banner(); +- ++#endif + if (selfcheck()) + exit(1); + +@@ -221,8 +226,6 @@ int main(int argc, char *argv[]) + free(tempstr); + cli_classic_abort_usage(); + } +- /* FIXME: A pointer to the image name is saved in a static array (of size MAX_ROMLAYOUT) +- * by register_include_arg() and needs to be freed after processing them. */ + break; + case 'L': + if (++operation_specified > 1) { +@@ -295,6 +298,9 @@ int main(int argc, char *argv[]) + "specified. Aborting.\n"); + cli_classic_abort_usage(); + } ++#ifdef FORCE10_SPI_CHANGE ++ print_version(); ++#endif + exit(0); + break; + case 'h': +@@ -372,6 +378,12 @@ int main(int argc, char *argv[]) + ret = 1; + goto out; + } ++ if (layoutfile != NULL && !write_it) { ++ msg_gerr("Layout files are currently supported for write operations only.\n"); ++ ret = 1; ++ goto out; ++ } ++ + if (process_include_args()) { + ret = 1; + goto out; +@@ -393,8 +405,13 @@ int main(int argc, char *argv[]) + if (prog == PROGRAMMER_INVALID) { + if (CONFIG_DEFAULT_PROGRAMMER != PROGRAMMER_INVALID) { + prog = CONFIG_DEFAULT_PROGRAMMER; ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Using default programmer \"%s\".\n", ++ programmer_table[CONFIG_DEFAULT_PROGRAMMER].name); ++#else + msg_pinfo("Using default programmer \"%s\".\n", + programmer_table[CONFIG_DEFAULT_PROGRAMMER].name); ++#endif + } else { + msg_perr("Please select a programmer with the --programmer parameter.\n" + "Previously this was not necessary because there was a default set.\n" +@@ -489,6 +506,10 @@ int main(int argc, char *argv[]) + tempstr = flashbuses_to_text(flashes[0].chip->bustype); + msg_gdbg("Found %s flash chip \"%s\" (%d kB, %s).\n", + flashes[0].chip->vendor, flashes[0].chip->name, flashes[0].chip->total_size, tempstr); ++ if ((flashes[0].chip->total_size > flashes[0].bios_size) && (flashes[0].bios_size != 0)) { ++ msg_gdbg("BIOS Size in flash chip: %d kB\n", flashes[0].bios_size); ++ flashes[0].chip->total_size = flashes[0].bios_size; ++ } + free(tempstr); + } + +@@ -517,7 +538,19 @@ int main(int argc, char *argv[]) + * Give the chip time to settle. + */ + programmer_delay(100000); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ dnv_smi_open_res(); ++ dnv_smi_doit(0, NULL, SMI_ENABLE_SPI); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + ret |= doit(fill_flash, force, filename, read_it, write_it, erase_it, verify_it); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ dnv_smi_doit(0, NULL, SMI_DISABLE_SPI); ++ dnv_smi_release_res(); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + /* Note: doit() already calls programmer_shutdown(). */ + goto out; + +@@ -527,6 +560,7 @@ out: + for (i = 0; i < chipcount; i++) + free(flashes[i].chip); + ++ layout_cleanup(); + free(filename); + free(layoutfile); + free(pparam); +diff --git a/dmi.c b/dmi.c +index 242889f..25ddd93 100644 +--- a/dmi.c ++++ b/dmi.c +@@ -1,7 +1,10 @@ + /* + * This file is part of the flashrom project. + * ++ * Copyright (C) 2000-2002 Alan Cox ++ * Copyright (C) 2002-2010 Jean Delvare + * Copyright (C) 2009,2010 Michael Karcher ++ * Copyright (C) 2011-2013 Stefan Tauner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -26,33 +29,28 @@ + #include "flash.h" + #include "programmer.h" + +-int has_dmi_support = 0; +- +-#if STANDALONE ++#if defined(__i386__) || defined(__x86_64__) + +-/* Stub to indicate missing DMI functionality. +- * has_dmi_support is 0 by default, so nothing to do here. +- * Because dmidecode is not available on all systems, the goal is to implement +- * the DMI subset we need directly in this file. +- */ +-void dmi_init(void) +-{ +-} ++/* Enable SMBIOS decoding. Currently legacy DMI decoding is enough. */ ++#define SM_SUPPORT 0 + +-int dmi_match(const char *pattern) +-{ +- return 0; +-} ++/* Strings longer than 4096 in DMI are just insane. */ ++#define DMI_MAX_ANSWER_LEN 4096 + +-#else /* STANDALONE */ ++int has_dmi_support = 0; + +-static const char *dmidecode_names[] = { +- "system-manufacturer", +- "system-product-name", +- "system-version", +- "baseboard-manufacturer", +- "baseboard-product-name", +- "baseboard-version", ++static struct { ++ const char *const keyword; ++ const uint8_t type; ++ const uint8_t offset; ++ char *value; ++} dmi_strings[] = { ++ { "system-manufacturer", 1, 0x04, NULL }, ++ { "system-product-name", 1, 0x05, NULL }, ++ { "system-version", 1, 0x06, NULL }, ++ { "baseboard-manufacturer", 2, 0x04, NULL }, ++ { "baseboard-product-name", 2, 0x05, NULL }, ++ { "baseboard-version", 2, 0x06, NULL }, + }; + + /* This list is used to identify supposed laptops. The is_laptop field has the +@@ -66,9 +64,9 @@ static const char *dmidecode_names[] = { + * The types below are the most common ones. + */ + static const struct { +- unsigned char type; +- unsigned char is_laptop; +- const char *name; ++ uint8_t type; ++ uint8_t is_laptop; ++ char *name; + } dmi_chassis_types[] = { + {0x01, 2, "Other"}, + {0x02, 2, "Unknown"}, +@@ -86,20 +84,206 @@ static const struct { + {0x18, 0, "Sealed-case PC"}, /* used by Supermicro (X8SIE) */ + }; + +-#define DMI_COMMAND_LEN_MAX 260 +-static const char *dmidecode_command = "dmidecode"; ++#if CONFIG_INTERNAL_DMI == 1 ++#if defined(__DJGPP__) || defined(FORCE10_SPI_CHANGE) /* There is no strnlen in DJGPP. FIXME: Move this to a common utility file. */ ++size_t strnlen(const char *str, size_t n) ++{ ++ size_t i; ++ for (i = 0; i < n && str[i] != '\0'; i++) ++ ; ++ return i; ++} ++#endif + +-static char *dmistrings[ARRAY_SIZE(dmidecode_names)]; ++static bool dmi_checksum(const uint8_t * const buf, size_t len) ++{ ++ uint8_t sum = 0; ++ size_t a; + +-/* Strings longer than 4096 in DMI are just insane. */ +-#define DMI_MAX_ANSWER_LEN 4096 ++ for (a = 0; a < len; a++) ++ sum += buf[a]; ++ return (sum == 0); ++} ++ ++static char *dmi_string(uint8_t *buf, uint8_t string_id, uint8_t *limit) ++{ ++ size_t i, len; ++ ++ if (string_id == 0) ++ return "Not Specified"; ++ ++ while (string_id > 1 && string_id--) { ++ if (buf > limit) { ++ msg_perr("DMI table is broken (string portion out of bounds)!\n"); ++ return ""; ++ } ++ buf += strnlen((char *)buf, limit - buf) + 1; ++ } ++ ++ if (!*buf) /* as long as the current byte we're on isn't null */ ++ return ""; ++ ++ len = strnlen((char *)buf, limit - buf); ++ if (len > DMI_MAX_ANSWER_LEN) ++ len = DMI_MAX_ANSWER_LEN; ++ ++ /* fix junk bytes in the string */ ++ for (i = 0; i < len && buf[i] != '\0'; i++) ++ if (buf[i] < 32 || buf[i] >= 127) ++ buf[i] = ' '; ++ ++ return (char *)buf; ++} ++ ++static void dmi_chassis_type(uint8_t code) ++{ ++ int i; ++ code &= 0x7f; /* bits 6:0 are chassis type, 7th bit is the lock bit */ ++ is_laptop = 2; ++ for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) { ++ if (code == dmi_chassis_types[i].type) { ++ msg_pdbg("DMI string chassis-type: \"%s\"\n", dmi_chassis_types[i].name); ++ is_laptop = dmi_chassis_types[i].is_laptop; ++ break; ++ } ++ } ++} ++ ++static void dmi_table(uint32_t base, uint16_t len, uint16_t num) ++{ ++ int i = 0, j = 0; ++ ++ uint8_t *dmi_table_mem = physmap_ro("DMI Table", base, len); ++ if (dmi_table_mem == NULL) { ++ msg_perr("Unable to access DMI Table\n"); ++ return; ++ } ++ ++ uint8_t *data = dmi_table_mem; ++ uint8_t *limit = dmi_table_mem + len; ++ ++ /* SMBIOS structure header is always 4 B long and contains: ++ * - uint8_t type; // see dmi_chassis_types's type ++ * - uint8_t length; // data section w/ header w/o strings ++ * - uint16_t handle; ++ */ ++ while (i < num && data + 4 <= limit) { ++ /* - If a short entry is found (less than 4 bytes), not only it ++ * is invalid, but we cannot reliably locate the next entry. ++ * - If the length value indicates that this structure spreads ++ * accross the table border, something is fishy too. ++ * Better stop at this point, and let the user know his/her ++ * table is broken. ++ */ ++ if (data[1] < 4 || data + data[1] > limit) { ++ msg_perr("DMI table is broken (bogus header)!\n"); ++ break; ++ } ++ ++ if(data[0] == 3) { ++ if (data + 5 <= limit) ++ dmi_chassis_type(data[5]); ++ /* else the table is broken, but laptop detection is optional, hence continue. */ ++ } else ++ for (j = 0; j < ARRAY_SIZE(dmi_strings); j++) { ++ uint8_t offset = dmi_strings[j].offset; ++ uint8_t type = dmi_strings[j].type; ++ ++ if (data[0] != type) ++ continue; ++ ++ if (data[1] <= offset || data+offset > limit) { ++ msg_perr("DMI table is broken (offset out of bounds)!\n"); ++ goto out; ++ } ++ ++ /* Table will be unmapped, hence fill the struct with duplicated strings. */ ++ dmi_strings[j].value = strdup(dmi_string(data + data[1], data[offset], limit)); ++ } ++ /* Find next structure by skipping data and string sections */ ++ data += data[1]; ++ while (data + 1 <= limit) { ++ if (data[0] == 0 && data[1] == 0) ++ break; ++ data++; ++ } ++ data += 2; ++ i++; ++ } ++out: ++ physunmap(dmi_table_mem, len); ++} ++ ++#if SM_SUPPORT ++static int smbios_decode(uint8_t *buf) ++{ ++ /* TODO: other checks mentioned in the conformance guidelines? */ ++ if (!dmi_checksum(buf, buf[0x05]) || ++ (memcmp(buf + 0x10, "_DMI_", 5) != 0) || ++ !dmi_checksum(buf + 0x10, 0x0F)) ++ return 0; ++ ++ dmi_table(mmio_readl(buf + 0x18), mmio_readw(buf + 0x16), mmio_readw(buf + 0x1C)); ++ ++ return 1; ++} ++#endif ++ ++static int legacy_decode(uint8_t *buf) ++{ ++ if (!dmi_checksum(buf, 0x0F)) ++ return 1; ++ ++ dmi_table(mmio_readl(buf + 0x08), mmio_readw(buf + 0x06), mmio_readw(buf + 0x0C)); ++ ++ return 0; ++} ++ ++int dmi_fill(void) ++{ ++ size_t fp; ++ uint8_t *dmi_mem; ++ int ret = 1; ++ ++ msg_pdbg("Using Internal DMI decoder.\n"); ++ /* There are two ways specified to gain access to the SMBIOS table: ++ * - EFI's configuration table contains a pointer to the SMBIOS table. On linux it can be obtained from ++ * sysfs. EFI's SMBIOS GUID is: {0xeb9d2d31,0x2d88,0x11d3,0x9a,0x16,0x0,0x90,0x27,0x3f,0xc1,0x4d} ++ * - Scanning physical memory address range 0x000F0000h to 0x000FFFFF for the anchor-string(s). */ ++ dmi_mem = physmap_ro("DMI", 0xF0000, 0x10000); ++ if (dmi_mem == ERROR_PTR) ++ return ret; ++ ++ for (fp = 0; fp <= 0xFFF0; fp += 16) { ++#if SM_SUPPORT ++ if (memcmp(dmi_mem + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { ++ if (smbios_decode(dmi_mem + fp)) // FIXME: length check ++ goto out; ++ } else ++#endif ++ if (memcmp(dmi_mem + fp, "_DMI_", 5) == 0) ++ if (legacy_decode(dmi_mem + fp) == 0) { ++ ret = 0; ++ goto out; ++ } ++ } ++ msg_pinfo("No DMI table found.\n"); ++out: ++ physunmap(dmi_mem, 0x10000); ++ return ret; ++} ++ ++#else /* CONFIG_INTERNAL_DMI */ ++ ++#define DMI_COMMAND_LEN_MAX 300 ++static const char *dmidecode_command = "dmidecode"; + + static char *get_dmi_string(const char *string_name) + { + FILE *dmidecode_pipe; + char *result; +- char answerbuf[DMI_MAX_ANSWER_LEN]; +- char commandline[DMI_COMMAND_LEN_MAX + 40]; ++ char answerbuf[DMI_MAX_ANSWER_LEN + 1] = {'\0'}; ++ char commandline[DMI_COMMAND_LEN_MAX + 1] = {'\0'}; + + snprintf(commandline, sizeof(commandline), + "%s -s %s", dmidecode_command, string_name); +@@ -138,46 +322,31 @@ static char *get_dmi_string(const char *string_name) + /* Chomp trailing newline. */ + if (answerbuf[0] != 0 && answerbuf[strlen(answerbuf) - 1] == '\n') + answerbuf[strlen(answerbuf) - 1] = 0; +- msg_pdbg("DMI string %s: \"%s\"\n", string_name, answerbuf); + + result = strdup(answerbuf); +- if (!result) ++ if (result == NULL) + msg_pwarn("Warning: Out of memory - DMI support fails"); + + return result; + } + +-static int dmi_shutdown(void *data) +-{ +- int i; +- for (i = 0; i < ARRAY_SIZE(dmistrings); i++) { +- free(dmistrings[i]); +- dmistrings[i] = NULL; +- } +- return 0; +-} +- +-void dmi_init(void) ++int dmi_fill(void) + { + int i; + char *chassis_type; + +- if (register_shutdown(dmi_shutdown, NULL)) +- return; +- +- has_dmi_support = 1; +- for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) { +- dmistrings[i] = get_dmi_string(dmidecode_names[i]); +- if (!dmistrings[i]) { +- has_dmi_support = 0; +- return; +- } ++ msg_pdbg("Using External DMI decoder.\n"); ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ dmi_strings[i].value = get_dmi_string(dmi_strings[i].keyword); ++ if (dmi_strings[i].value == NULL) ++ return 1; + } + + chassis_type = get_dmi_string("chassis-type"); + if (chassis_type == NULL) +- return; ++ return 0; /* chassis-type handling is optional anyway */ + ++ msg_pdbg("DMI string chassis-type: \"%s\"\n", chassis_type); + is_laptop = 2; + for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) { + if (strcasecmp(chassis_type, dmi_chassis_types[i].name) == 0) { +@@ -185,6 +354,33 @@ void dmi_init(void) + break; + } + } ++ free(chassis_type); ++ return 0; ++} ++ ++#endif /* CONFIG_INTERNAL_DMI */ ++ ++static int dmi_shutdown(void *data) ++{ ++ int i; ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ free(dmi_strings[i].value); ++ dmi_strings[i].value = NULL; ++ } ++ return 0; ++} ++ ++void dmi_init(void) ++{ ++ /* Register shutdown function before we allocate anything. */ ++ if (register_shutdown(dmi_shutdown, NULL)) { ++ msg_pwarn("Warning: Could not register DMI shutdown function - continuing without DMI info.\n"); ++ return; ++ } ++ ++ /* dmi_fill fills the dmi_strings array, and if possible sets the global is_laptop variable. */ ++ if (dmi_fill() != 0) ++ return; + + switch (is_laptop) { + case 1: +@@ -194,7 +390,13 @@ void dmi_init(void) + msg_pdbg("DMI chassis-type is not specific enough.\n"); + break; + } +- free(chassis_type); ++ ++ has_dmi_support = 1; ++ int i; ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ msg_pdbg("DMI string %s: \"%s\"\n", dmi_strings[i].keyword, ++ (dmi_strings[i].value == NULL) ? "" : dmi_strings[i].value); ++ } + } + + /** +@@ -204,8 +406,8 @@ void dmi_init(void) + * at the beginning and '$' at the end. So you can look for "^prefix", + * "suffix$", "substring" or "^complete string$". + * +- * @param value The string to check. +- * @param pattern The pattern. ++ * @param value The non-NULL string to check. ++ * @param pattern The non-NULL pattern. + * @return Nonzero if pattern matches. + */ + static int dmi_compare(const char *value, const char *pattern) +@@ -252,11 +454,15 @@ int dmi_match(const char *pattern) + if (!has_dmi_support) + return 0; + +- for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) +- if (dmi_compare(dmistrings[i], pattern)) ++ for (i = 0; i < ARRAY_SIZE(dmi_strings); i++) { ++ if (dmi_strings[i].value == NULL) ++ continue; ++ ++ if (dmi_compare(dmi_strings[i].value, pattern)) + return 1; ++ } + + return 0; + } + +-#endif /* STANDALONE */ ++#endif // defined(__i386__) || defined(__x86_64__) +diff --git a/dnv_smi_spi.c b/dnv_smi_spi.c +new file mode 100644 +index 0000000..0317cc7 +--- /dev/null ++++ b/dnv_smi_spi.c +@@ -0,0 +1,185 @@ ++ ++/************************************************************************ ++* LEGALESE: "Copyright (c) 2018, Dell Inc. All rights reserved." ++* ++* This source code is confidential, proprietary, and contains trade ++* secrets that are the sole property of Dell Inc. ++* Copy and/or distribution of this source code or disassembly or reverse ++* engineering of the resultant object code are strictly forbidden without ++* the written consent of Dell Inc. ++* ++************************************************************************/ ++#if DELL_DENVERTON_SUPPORT == 1 ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "flash.h" ++ ++#define MEM_MODULE "/dev/mem" ++ ++DELL_SPI_MAILBOX *mailbox; ++uint64_t phy_addr; ++ ++/** ++* @brief unmap a pagesize of physical memory into virtual memory. ++* @param[in] addr - virtual memory address that is unmaped. ++*/ ++static void free_virt_mapping(void *addr) ++{ ++ munmap(addr, getpagesize()); ++} ++ ++/** ++* @brief map a pagesize of physical memory into virtual memory. ++* @param[in] addr - physical memory address. ++* @param[out] buf - pointer to buffer which storages data. ++* @return = 0 for success, otherwise for error. ++*/ ++static uint32_t getData_phy_to_virt(uint32_t addr, void** buf) ++{ ++ uint8_t *tmp; ++ uint32_t pagesize, offset, index, fd; ++ ++ pagesize = getpagesize(); ++ if ( (fd = open(MEM_MODULE, O_RDWR)) < 0 ) { ++ printf("open() %s error\n", MEM_MODULE); ++ return 1; ++ } ++ ++ offset = addr & ~(pagesize - 1); ++ index = addr & (pagesize - 1); ++ if ( (tmp = mmap(0, pagesize*2, PROT_READ|PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED ) { ++ printf("mmap() error\n"); ++ close(fd); ++ return 1; ++ } ++ *buf = tmp + index; ++ close(fd); ++ return 0; ++} ++ ++/** ++* @brief send "get communication buffer" requirement to SMM ++*/ ++uint32_t dnv_smi_open_res() ++{ ++ uint32_t mailboxAddress; ++ ++ ioperm(0xB2, 3, 1); ++ __asm__ __volatile__ ("push %%rcx" : :); ++ outb(0x27, 0xB2); ++ __asm__ __volatile__ ("movl %%ecx, %0" : "=r" (mailboxAddress)); ++ __asm__ __volatile__ ("pop %%rcx" : :); ++ ioperm(0xB2, 3, 0); ++ ++ getData_phy_to_virt(mailboxAddress, (void **)&mailbox); ++ phy_addr = mailboxAddress; ++ return 0; ++} ++ ++/** ++* @brief send "release communication buffer" requirement to SMM ++*/ ++void dnv_smi_release_res() ++{ ++ free_virt_mapping((void *)mailbox); ++} ++ ++/** ++* @brief disable SPI write protection. ++*/ ++static void dnv_trigger_smi_spi_unlock() ++{ ++ ioperm(0xB2, 3, 1); ++ __asm__ __volatile__ ("push %%rcx" : :); ++ __asm__ __volatile__ ("push %%rbx" : :); ++ __asm__ __volatile__ ("movl %0, %%ecx" : : "a" ((uint32_t)0)); ++ __asm__ __volatile__ ("movl %0, %%ebx" : : "a" ((uint32_t)phy_addr)); ++ outb(0x20, 0xB2); ++ __asm__ __volatile__ ("pop %%rbx" : :); ++ __asm__ __volatile__ ("pop %%rcx" : :); ++ ioperm(0xB2, 3, 0); ++} ++ ++/** ++* @brief enable SPI write protection. ++*/ ++static void dnv_trigger_smi_spi_lock() ++{ ++ ioperm(0xB2, 3, 1); ++ __asm__ __volatile__ ("push %%rcx" : :); ++ __asm__ __volatile__ ("push %%rbx" : :); ++ __asm__ __volatile__ ("movl %0, %%ecx" : : "a" ((uint32_t)0)); ++ __asm__ __volatile__ ("movl %0, %%ebx" : : "a" ((uint32_t)phy_addr)); ++ outb(0x24, 0xB2); ++ __asm__ __volatile__ ("pop %%rbx" : :); ++ __asm__ __volatile__ ("pop %%rcx" : :); ++ ioperm(0xB2, 3, 0); ++} ++ ++/** ++* @brief trigger smi ++*/ ++void run() ++{ ++ ioperm(0xB2, 3, 1); ++ outb(0x28, 0xB2); ++ ioperm(0xB2, 3, 0); ++} ++ ++/** ++* @brief This function is used to read/write and erase BIOS. ++* trigger SMI and send information to SMM(like requirement, address,and data) ++* @param[in] bios_offset - offset of bios region [0~size of bios region] ++* @param[in] buf - pointer to write data if cmd is "SMI_READ_SPI" ++* @param[in] cmd - enum SPI_SMI_CMD ++* @param[out] buf - pointer to read data if cmd is "SMI_WRITE_SPI" ++* @returns ret. This ret is returned from SMM. ++*/ ++int32_t dnv_smi_doit(uint32_t bios_offset, uint8_t *buf, SPI_SMI_CMD cmd) ++{ ++ ++ if (cmd == SMI_READ_SPI) { ++ mailbox->cmd = 0x1; ++ mailbox->offset = bios_offset; ++ mailbox->dlen = DELL_DENVERTON_BLOCK_SIZE; ++ run(); ++ memcpy (buf, mailbox->data, DELL_DENVERTON_BLOCK_SIZE); ++ return mailbox->ret; ++ } else if (cmd == SMI_ERASE_SPI) { ++ mailbox->cmd = 0x2; ++ mailbox->offset = bios_offset; ++ mailbox->dlen = DELL_DENVERTON_BLOCK_SIZE; ++ run(); ++ return mailbox->ret; ++ } else if (cmd == SMI_WRITE_SPI) { ++ memcpy (mailbox->data, buf, DELL_DENVERTON_BLOCK_SIZE); ++ mailbox->cmd = 0x3; ++ mailbox->offset = bios_offset; ++ mailbox->dlen = DELL_DENVERTON_BLOCK_SIZE; ++ run(); ++ return mailbox->ret; ++ } ++ ++ switch (cmd) ++ { ++ case SMI_ENABLE_SPI: ++ dnv_trigger_smi_spi_unlock(); ++ break; ++ case SMI_DISABLE_SPI: ++ dnv_trigger_smi_spi_lock(); ++ break; ++ default: ++ return -1; ++ } ++ ++ return 0; ++} ++ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ +diff --git a/drkaiser.c b/drkaiser.c +index b94d6dd..0cf1fdb 100644 +--- a/drkaiser.c ++++ b/drkaiser.c +@@ -56,12 +56,6 @@ static const struct par_programmer par_programmer_drkaiser = { + .chip_writen = fallback_chip_writen, + }; + +-static int drkaiser_shutdown(void *data) +-{ +- physunmap(drkaiser_bar, DRKAISER_MEMMAP_SIZE); +- return 0; +-} +- + int drkaiser_init(void) + { + struct pci_dev *dev = NULL; +@@ -75,15 +69,15 @@ int drkaiser_init(void) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); ++ if (!addr) ++ return 1; + + /* Write magic register to enable flash write. */ + rpci_write_word(dev, PCI_MAGIC_DRKAISER_ADDR, PCI_MAGIC_DRKAISER_VALUE); + + /* Map 128kB flash memory window. */ +- drkaiser_bar = physmap("Dr. Kaiser PC-Waechter flash memory", +- addr, DRKAISER_MEMMAP_SIZE); +- +- if (register_shutdown(drkaiser_shutdown, NULL)) ++ drkaiser_bar = rphysmap("Dr. Kaiser PC-Waechter flash memory", addr, DRKAISER_MEMMAP_SIZE); ++ if (drkaiser_bar == ERROR_PTR) + return 1; + + max_rom_decode.parallel = 128 * 1024; +diff --git a/flash.h b/flash.h +index 63701ed..79fe8f4 100644 +--- a/flash.h ++++ b/flash.h +@@ -45,6 +45,14 @@ + typedef uintptr_t chipaddr; + #define PRIxPTR_WIDTH ((int)(sizeof(uintptr_t)*2)) + ++/* Types and macros regarding the maximum flash space size supported by generic code. */ ++typedef uint32_t chipoff_t; /* Able to store any addressable offset within a supported flash memory. */ ++typedef uint32_t chipsize_t; /* Able to store the number of bytes of any supported flash memory. */ ++#define FL_MAX_CHIPADDR_BITS (24) ++#define FL_MAX_CHIPADDR ((chipoff_t)(1ULL< 0) ++ programmer_table[programmer].delay(usecs); + } + + void map_flash_registers(struct flashctx *flash) +@@ -619,12 +629,29 @@ static unsigned int count_usable_erasers(const struct flashctx *flash) + return usable_erasefunctions; + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++int8_t is_erase = 0; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + int compare_range(uint8_t *wantbuf, uint8_t *havebuf, unsigned int start, unsigned int len) + { + int ret = 0, failcount = 0; + unsigned int i; + for (i = 0; i < len; i++) { + if (wantbuf[i] != havebuf[i]) { ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv && is_erase) { ++ // _FVH ++ // At offset 0x28~0x2b of NVRAM, Main Bios and Boot Bios ++ // We can't read correct data after "erasing". ++ // But, We verified bios through SF100. The erase feature is work. ++ if (i == _FVH_OFFSET && ++ memcmp(&havebuf[i], _FVH_SIGNATURE, sizeof(_FVH_SIGNATURE) - 1) == 0) { ++ i += sizeof(_FVH_SIGNATURE) - 1; ++ continue; ++ } ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + /* Only print the first failure. */ + if (!failcount++) + msg_cerr("FAILED at 0x%08x! Expected=0x%02x, Found=0x%02x,", +@@ -651,7 +678,15 @@ int check_erased_range(struct flashctx *flash, unsigned int start, + exit(1); + } + memset(cmpbuf, 0xff, len); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) ++ is_erase = 1; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + ret = verify_range(flash, cmpbuf, start, len); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) ++ is_erase = 0; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + free(cmpbuf); + return ret; + } +@@ -695,6 +730,22 @@ int verify_range(struct flashctx *flash, uint8_t *cmpbuf, unsigned int start, un + return ret; + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++ // NVRAM will be recovery even if use afulnx. ++ // skip NVRAM region. ++ if (is_dnv) { ++ // Do not hard-code the NVRAM region start address. It is located at different addresses for 16MB and 32MB BIOS image. ++ // For Denverton platform, NVRAM region start address is always located at dnv_bios_region_start. ++ // NVRAM backup region is located at (dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH). ++ if ((start >= dnv_bios_region_start && ++ start < (dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH)) || ++ (start >= (dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH) && ++ start < ((dnv_bios_region_start + DELL_DENVERTON_MAIN_NVRAM_LENGTH) + DELL_DENVERTON_BACKUP_NVRAM_LENGTH))) { ++ return ret; ++ } ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + ret = compare_range(cmpbuf, readbuf, start, len); + out_free: + free(readbuf); +@@ -770,6 +821,11 @@ int need_erase(uint8_t *have, uint8_t *want, unsigned int len, enum write_granul + case write_gran_1056bytes: + result = need_erase_gran_bytes(have, want, len, 1056); + break; ++#if DELL_DENVERTON_SUPPORT == 1 ++ case write_gran_4096bytes: ++ result = need_erase_gran_bytes(have, want, len, 4096); ++ break; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + default: + msg_cerr("%s: Unsupported granularity! Please report a bug at " + "flashrom@flashrom.org\n", __func__); +@@ -831,6 +887,11 @@ static unsigned int get_next_write(uint8_t *have, uint8_t *want, unsigned int le + case write_gran_1056bytes: + stride = 1056; + break; ++#if DELL_DENVERTON_SUPPORT == 1 ++ case write_gran_4096bytes: ++ stride = 4096; ++ break; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + default: + msg_cerr("%s: Unsupported granularity! Please report a bug at " + "flashrom@flashrom.org\n", __func__); +@@ -1140,6 +1201,12 @@ notfound: + if (!flash->chip) + return -1; + ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ flash->chip->gran = write_gran_4096bytes; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + #if CONFIG_INTERNAL == 1 + if (programmer_table[programmer].map_flash_region == physmap) + snprintf(location, sizeof(location), "at physical address 0x%lx", base); +@@ -1148,8 +1215,13 @@ notfound: + snprintf(location, sizeof(location), "on %s", programmer_table[programmer].name); + + tmp = flashbuses_to_text(flash->chip->bustype); ++#ifdef FORCE10_SPI_CHANGE ++ msg_cdbg("%s %s flash chip \"%s\" (%d kB, %s) %s.\n", force ? "Assuming" : "Found", ++ flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp, location); ++#else + msg_cinfo("%s %s flash chip \"%s\" (%d kB, %s) %s.\n", force ? "Assuming" : "Found", + flash->chip->vendor, flash->chip->name, flash->chip->total_size, tmp, location); ++#endif + free(tmp); + + /* Flash registers will not be mapped if the chip was forced. Lock info +@@ -1166,6 +1238,10 @@ notfound: + int read_buf_from_file(unsigned char *buf, unsigned long size, + const char *filename) + { ++#ifdef __LIBPAYLOAD__ ++ msg_gerr("Error: No file I/O support in libpayload\n"); ++ return 1; ++#else + unsigned long numbytes; + FILE *image; + struct stat image_stat; +@@ -1196,11 +1272,16 @@ int read_buf_from_file(unsigned char *buf, unsigned long size, + return 1; + } + return 0; ++#endif + } + + int write_buf_to_file(unsigned char *buf, unsigned long size, + const char *filename) + { ++#ifdef __LIBPAYLOAD__ ++ msg_gerr("Error: No file I/O support in libpayload\n"); ++ return 1; ++#else + unsigned long numbytes; + FILE *image; + +@@ -1221,6 +1302,7 @@ int write_buf_to_file(unsigned char *buf, unsigned long size, + return 1; + } + return 0; ++#endif + } + + int read_flash_to_file(struct flashctx *flash, const char *filename) +@@ -1229,6 +1311,16 @@ int read_flash_to_file(struct flashctx *flash, const char *filename) + unsigned char *buf = calloc(size, sizeof(char)); + int ret = 0; + ++#if DELL_DENVERTON_SUPPORT == 1 ++ uint64_t bios_start = 0; ++ uint64_t bios_size = size; ++ ++ if (is_dnv) { ++ bios_size = dnv_bios_region_size; ++ bios_start = dnv_bios_region_start; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + msg_cinfo("Reading flash... "); + if (!buf) { + msg_gerr("Memory allocation failed!\n"); +@@ -1240,7 +1332,11 @@ int read_flash_to_file(struct flashctx *flash, const char *filename) + ret = 1; + goto out_free; + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (flash->chip->read(flash, (buf + bios_start), bios_start, bios_size)) { ++#else + if (flash->chip->read(flash, buf, 0, size)) { ++#endif /* #if DELL_DENVERTON__SUPPORT == 1 */ + msg_cerr("Read operation failed!\n"); + ret = 1; + goto out_free; +@@ -1388,6 +1484,11 @@ static int walk_eraseregions(struct flashctx *flash, int erasefunction, + { + int i, j; + unsigned int start = 0; ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ start = dnv_bios_region_start; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + unsigned int len; + struct block_eraser eraser = flash->chip->block_erasers[erasefunction]; + +@@ -1897,6 +1998,10 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + uint8_t *newcontents; + int ret = 0; + unsigned long size = flash->chip->total_size * 1024; ++#if DELL_DENVERTON_SUPPORT == 1 ++ uint32_t bios_size = size; ++ uint32_t bios_start = 0; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + + if (chip_safety_check(flash, force, read_it, write_it, erase_it, verify_it)) { + msg_cerr("Aborting.\n"); +@@ -1904,6 +2009,12 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + goto out_nofree; + } + ++ if (normalize_romentries(flash)) { ++ msg_cerr("Requested regions can not be handled. Aborting.\n"); ++ ret = 1; ++ goto out_nofree; ++ } ++ + /* Given the existence of read locks, we want to unlock for read, + * erase and write. + */ +@@ -1936,6 +2047,13 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + */ + + if (erase_it) { ++ ++#if 0 // Since we dont have a layout, why set newcontents to 0?? ++#ifdef FORCE10_SPI_CHANGE ++ /* Build a new image taking the given layout into account. */ ++ build_new_image(flash, oldcontents, newcontents); ++#endif ++#endif + /* FIXME: Do we really want the scary warning if erase failed? + * After all, after erase the chip is either blank or partially + * blank or it has the old contents. A blank chip won't boot, +@@ -1975,25 +2093,47 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + * preserved, but in that case we might perform unneeded erase which + * takes time as well. + */ ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ bios_size = dnv_bios_region_size; ++ bios_start = dnv_bios_region_start; ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++#ifdef FORCE10_SPI_CHANGE ++ msg_cdbg("Reading old flash chip contents... "); ++#else + msg_cinfo("Reading old flash chip contents... "); ++#endif ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (flash->chip->read(flash, oldcontents + bios_start, bios_start, bios_size)) { ++#else + if (flash->chip->read(flash, oldcontents, 0, size)) { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + ret = 1; + msg_cinfo("FAILED.\n"); + goto out; + } ++#ifdef FORCE10_SPI_CHANGE ++ msg_cdbg("done.\n"); ++#else + msg_cinfo("done.\n"); ++#endif + +- // This should be moved into each flash part's code to do it +- // cleanly. This does the job. +- handle_romentries(flash, oldcontents, newcontents); +- ++#if 0 ++ /* Build a new image taking the given layout into account. */ ++ build_new_image(flash, oldcontents, newcontents); ++#endif + // //////////////////////////////////////////////////////////// + + if (write_it) { + if (erase_and_write_flash(flash, oldcontents, newcontents)) { + msg_cerr("Uh oh. Erase/write failed. Checking if " + "anything changed.\n"); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (!flash->chip->read(flash, newcontents, bios_start, bios_size)) { ++#else + if (!flash->chip->read(flash, newcontents, 0, size)) { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + if (!memcmp(oldcontents, newcontents, size)) { + msg_cinfo("Good. It seems nothing was changed.\n"); + nonfatal_help_message(); +@@ -2014,14 +2154,22 @@ int doit(struct flashctx *flash, int force, const char *filename, int read_it, + if (write_it) { + /* Work around chips which need some time to calm down. */ + programmer_delay(1000*1000); ++#if DELL_DENVERTON_SUPPORT == 1 ++ ret = verify_range(flash, newcontents + bios_start, bios_start, bios_size); ++#else + ret = verify_range(flash, newcontents, 0, size); ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + /* If we tried to write, and verification now fails, we + * might have an emergency situation. + */ + if (ret) + emergency_help_message(); + } else { ++#if DELL_DENVERTON_SUPPORT == 1 ++ ret = compare_range(newcontents + bios_start, oldcontents + bios_start, bios_start, bios_size); ++#else + ret = compare_range(newcontents, oldcontents, 0, size); ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + } + if (!ret) + msg_cinfo("VERIFIED.\n"); +diff --git a/ft2232_spi.c b/ft2232_spi.c +index 81be051..44354fd 100644 +--- a/ft2232_spi.c ++++ b/ft2232_spi.c +@@ -43,6 +43,7 @@ + #define FTDI_FT4232H_PID 0x6011 + #define FTDI_FT232H_PID 0x6014 + #define TIAO_TUMPA_PID 0x8a98 ++#define TIAO_TUMPA_LITE_PID 0x8a99 + #define AMONTEC_JTAGKEY_PID 0xCFF8 + + #define GOEPEL_VID 0x096C +@@ -62,6 +63,7 @@ const struct dev_entry devs_ft2232spi[] = { + {FTDI_VID, FTDI_FT4232H_PID, OK, "FTDI", "FT4232H"}, + {FTDI_VID, FTDI_FT232H_PID, OK, "FTDI", "FT232H"}, + {FTDI_VID, TIAO_TUMPA_PID, OK, "TIAO", "USB Multi-Protocol Adapter"}, ++ {FTDI_VID, TIAO_TUMPA_LITE_PID, OK, "TIAO", "USB Multi-Protocol Adapter Lite"}, + {FTDI_VID, AMONTEC_JTAGKEY_PID, OK, "Amontec", "JTAGkey"}, + {GOEPEL_VID, GOEPEL_PICOTAP_PID, OK, "GOEPEL", "PicoTAP"}, + {FIC_VID, OPENMOKO_DBGBOARD_PID, OK, "FIC", "OpenMoko Neo1973 Debug board (V2+)"}, +@@ -208,6 +210,10 @@ int ft2232_spi_init(void) + /* Interface A is SPI1, B is SPI2. */ + ft2232_type = TIAO_TUMPA_PID; + channel_count = 2; ++ } else if (!strcasecmp(arg, "tumpalite")) { ++ /* Only one channel is used on lite edition */ ++ ft2232_type = TIAO_TUMPA_LITE_PID; ++ channel_count = 1; + } else if (!strcasecmp(arg, "busblaster")) { + /* In its default configuration it is a jtagkey clone */ + ft2232_type = FTDI_FT2232H_PID; +diff --git a/gfxnvidia.c b/gfxnvidia.c +index d0a9feb..d3ee14e 100644 +--- a/gfxnvidia.c ++++ b/gfxnvidia.c +@@ -77,12 +77,6 @@ static const struct par_programmer par_programmer_gfxnvidia = { + .chip_writen = fallback_chip_writen, + }; + +-static int gfxnvidia_shutdown(void *data) +-{ +- physunmap(nvidia_bar, GFXNVIDIA_MEMMAP_SIZE); +- return 0; +-} +- + int gfxnvidia_init(void) + { + struct pci_dev *dev = NULL; +@@ -96,12 +90,14 @@ int gfxnvidia_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; ++ + io_base_addr += 0x300000; + msg_pinfo("Detected NVIDIA I/O base address: 0x%x.\n", io_base_addr); + +- nvidia_bar = physmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE); +- +- if (register_shutdown(gfxnvidia_shutdown, NULL)) ++ nvidia_bar = rphysmap("NVIDIA", io_base_addr, GFXNVIDIA_MEMMAP_SIZE); ++ if (nvidia_bar == ERROR_PTR) + return 1; + + /* Allow access to flash interface (will disable screen). */ +diff --git a/hwaccess.h b/hwaccess.h +index fd6eb12..83f349e 100644 +--- a/hwaccess.h ++++ b/hwaccess.h +@@ -37,7 +37,13 @@ + * or as builtin. + */ + #define index shadow_workaround_index ++ ++#if !defined (__NetBSD__) && !defined (__DragonFly__) + #include ++#else ++#include ++#endif ++ + #undef index + #endif + +diff --git a/ich_descriptors.c b/ich_descriptors.c +index 528717b..c007867 100644 +--- a/ich_descriptors.c ++++ b/ich_descriptors.c +@@ -45,6 +45,11 @@ + #define min(a, b) (a < b) ? a : b + #endif + ++#if DELL_DENVERTON_SUPPORT == 1 ++#define DELL_DENVERTON_MAX_DENSITY 7 ++extern int8_t is_dnv; // if 1 chipset is denverton serial, 0 otherwise ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity) + { + print(verbosity, "BES=0x%x, ", (reg_val & VSCC_BES) >> VSCC_BES_OFF); +@@ -100,6 +105,36 @@ void prettyprint_ich_descriptor_content(const struct ich_desc_content *cont) + + void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc) + { ++#if DELL_DENVERTON_SUPPORT == 1 ++ static const char * const dnv_freq_str[8] = { ++ "reserved", /* 000 */ ++ "reserved", /* 001 */ ++ "48 MHz", /* 010 */ ++ "reserved", /* 011 */ ++ "30MHz", /* 100 */ ++ "reserved", /* 101 */ ++ "17 MHz", /* 110 */ ++ "reserved", /* 111 */ ++ }; ++ static const char * const dnv_size_str[16] = { ++ "512 kB", /* 0000 */ ++ " 1 MB", /* 0001 */ ++ " 2 MB", /* 0010 */ ++ " 4 MB", /* 0011 */ ++ " 8 MB", /* 0100 */ ++ " 16 MB", /* 0101 */ ++ " 32 MB", /* 0110 */ ++ " 64 MB", /* 0111 */ ++ "reserved", /* 1000 */ ++ "reserved", /* 1001 */ ++ "reserved", /* 1010 */ ++ "reserved", /* 1011 */ ++ "reserved", /* 1100 */ ++ "reserved", /* 1101 */ ++ "reserved", /* 1110 */ ++ "reserved", /* 1111 */ ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + static const char * const freq_str[8] = { + "20 MHz", /* 000 */ + "33 MHz", /* 001 */ +@@ -121,6 +156,47 @@ void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc) + "reserved", /* 111 */ + }; + ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ msg_pdbg2("=== Component Section ===\n"); ++ msg_pdbg2("FLCOMP 0x%08x\n", desc->component.FLCOMP); ++ msg_pdbg2("FLILL 0x%08x\n", desc->component.FLILL ); ++ msg_pdbg2("\n"); ++ ++ msg_pdbg2("--- Details ---\n"); ++ msg_pdbg2("Component 1 density: %s\n", ++ dnv_size_str[desc->component.dnv_comp1_density]); ++ if (desc->content.NC) ++ msg_pdbg2("Component 2 density: %s\n", ++ dnv_size_str[desc->component.dnv_comp2_density]); ++ else ++ msg_pdbg2("Component 2 is not used.\n"); ++ msg_pdbg2("Read Clock Frequency: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_read]); ++ msg_pdbg2("Read ID and Status Clock Freq.: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_read_id]); ++ msg_pdbg2("Write and Erase Clock Freq.: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_write]); ++ msg_pdbg2("Fast Read is %ssupported.\n", ++ desc->component.dnv_fastread ? "" : "not "); ++ if (desc->component.dnv_fastread) ++ msg_pdbg2("Fast Read Clock Frequency: %s\n", ++ dnv_freq_str[desc->component.dnv_freq_fastread]); ++ if (desc->component.FLILL == 0) ++ msg_pdbg2("No forbidden opcodes.\n"); ++ else { ++ msg_pdbg2("Invalid instruction 0: 0x%02x\n", ++ desc->component.invalid_instr0); ++ msg_pdbg2("Invalid instruction 1: 0x%02x\n", ++ desc->component.invalid_instr1); ++ msg_pdbg2("Invalid instruction 2: 0x%02x\n", ++ desc->component.invalid_instr2); ++ msg_pdbg2("Invalid instruction 3: 0x%02x\n", ++ desc->component.invalid_instr3); ++ } ++ } else { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + msg_pdbg2("=== Component Section ===\n"); + msg_pdbg2("FLCOMP 0x%08x\n", desc->component.FLCOMP); + msg_pdbg2("FLILL 0x%08x\n", desc->component.FLILL ); +@@ -157,6 +233,9 @@ void prettyprint_ich_descriptor_component(const struct ich_descriptors *desc) + msg_pdbg2("Invalid instruction 3: 0x%02x\n", + desc->component.invalid_instr3); + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + msg_pdbg2("\n"); + } + +@@ -171,6 +250,12 @@ static void pprint_freg(const struct ich_desc_region *reg, uint32_t i) + } + uint32_t base = ICH_FREG_BASE(reg->FLREGs[i]); + uint32_t limit = ICH_FREG_LIMIT(reg->FLREGs[i]); ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ base = DELL_DENVERTON_FREG_BASE(reg->FLREGs[i]); ++ limit = DELL_DENVERTON_FREG_LIMIT(reg->FLREGs[i]); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + msg_pdbg2("Region %d (%-6s) ", i, region_names[i]); + if (base > limit) + msg_pdbg2("is unused.\n"); +@@ -741,17 +826,36 @@ int getFCBA_component_density(const struct ich_descriptors *desc, uint8_t idx) + msg_perr("Only ICH SPI component index 0 or 1 are supported yet.\n"); + return 0; + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ if (size_enc > DELL_DENVERTON_MAX_DENSITY) { ++ msg_perr("Density of ICH SPI component with index %d is invalid. Encoded density is 0x%x.\n", idx, size_enc); ++ return 0; ++ } ++ } else { ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + if (size_enc > 5) { + msg_perr("Density of ICH SPI component with index %d is invalid. Encoded density is 0x%x.\n", + idx, size_enc); + return 0; + } ++#if DELL_DENVERTON_SUPPORT == 1 ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + return (1 << (19 + size_enc)); + } + + static uint32_t read_descriptor_reg(uint8_t section, uint16_t offset, void *spibar) + { + uint32_t control = 0; ++#if DELL_DENVERTON_SUPPORT == 1 ++ if (is_dnv) { ++ control |= (section << DENVERTON_FDOC_FDSS_OFF) & DENVERTON_FDOC_FDSS; ++ control |= (offset << DENVERTON_FDOC_FDSI_OFF) & DENVERTON_FDOC_FDSI; ++ mmio_le_writel(control, spibar + DENVERTON_REG_FDOC); ++ return mmio_le_readl(spibar + DENVERTON_REG_FDOD); ++ } ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + control |= (section << FDOC_FDSS_OFF) & FDOC_FDSS; + control |= (offset << FDOC_FDSI_OFF) & FDOC_FDSI; + mmio_le_writel(control, spibar + ICH9_REG_FDOC); +diff --git a/ich_descriptors.h b/ich_descriptors.h +index 3a44740..914a3cd 100644 +--- a/ich_descriptors.h ++++ b/ich_descriptors.h +@@ -64,6 +64,19 @@ + #define ICH_FREG_BASE(flreg) (((flreg) << 12) & 0x01fff000) + #define ICH_FREG_LIMIT(flreg) (((flreg) >> 4) & 0x01fff000) + ++#if DELL_DENVERTON_SUPPORT == 1 ++#define DENVERTON_REG_FDOC 0xB4 ++#define DENVERTON_FDOC_FDSI_OFF 2 ++#define DENVERTON_FDOC_FDSI (0x3ff << DENVERTON_FDOC_FDSI_OFF) ++#define DENVERTON_FDOC_FDSS_OFF 12 ++#define DENVERTON_FDOC_FDSS (0x3 << DENVERTON_FDOC_FDSS_OFF) ++ ++#define DENVERTON_REG_FDOD 0xB8 ++ ++#define DELL_DENVERTON_FREG_BASE(flreg) (((flreg) << 12) & 0x03fff000) ++#define DELL_DENVERTON_FREG_LIMIT(flreg) (((flreg) >> 4) & 0x03fff000) ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + void prettyprint_ich_reg_vscc(uint32_t reg_val, int verbosity); + + struct ich_desc_content { +@@ -78,6 +91,15 @@ struct ich_desc_content { + NR :3, /* Number Of Regions */ + :5; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ struct { ++ int32_t dnv_FCBA :8, /* Flash Component Base Address */ ++ dnv_NC :2, /* Number Of Components */ ++ :6, ++ dnv_FRBA :8, /* Flash Region Base Address */ ++ :8; ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + union { /* 0x08 */ + uint32_t FLMAP1; +@@ -113,6 +135,20 @@ struct ich_desc_component { + freq_read_id :3, + :2; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ struct { ++ uint32_t dnv_comp1_density :4, ++ dnv_comp2_density :4, ++ :9, ++ dnv_freq_read :3, ++ dnv_fastread :1, ++ dnv_freq_fastread :3, ++ dnv_freq_write :3, ++ dnv_freq_read_id :3, ++ dnv_dualfastread :1, ++ :1; ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + union { /* 0x04 */ + uint32_t FLILL; /* Flash Invalid Instructions Register */ +@@ -129,6 +165,15 @@ struct ich_desc_component { + uint32_t FPBA :13, /* Flash Partition Boundary Addr */ + :19; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ uint32_t FLILL1; /* Flash Partition Boundary Register for dnv */ ++ struct { ++ uint32_t invalid_instr4 :8, ++ invalid_instr5 :8, ++ invalid_instr6 :8, ++ invalid_instr7 :8; ++ }; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + }; + +@@ -167,6 +212,65 @@ struct ich_desc_region { + :3; + }; + }; ++#if DELL_DENVERTON_SUPPORT == 1 ++ struct { /* FLREG0 Flash Descriptor */ ++ uint32_t dnv_reg0_base :15, ++ :1, ++ dnv_reg0_limit :15, ++ :1; ++ }; ++ struct { /* FLREG1 BIOS */ ++ uint32_t dnv_reg1_base :15, ++ :1, ++ dnv_reg1_limit :15, ++ :1; ++ }; ++ struct { /* FLREG2 ME */ ++ uint32_t dnv_reg2_base :15, ++ :1, ++ dnv_reg2_limit :15, ++ :1; ++ }; ++ ++ /* FLREG3 - Reserved */ ++ ++ struct { /* FLREG4 Platform */ ++ uint32_t dnv_reg4_base :15, ++ :1, ++ dnv_reg4_limit :15, ++ :1; ++ }; ++ ++ /* FLREG5 - Reserved */ ++ /* FLREG6 - Reserved */ ++ /* FLREG7 - Reserved */ ++ /* FLREG8 - Reserved */ ++ /* FLREG9 - Reserved */ ++ ++ struct { /* FLREG10 IE */ ++ uint32_t dnv_reg10_base :15, ++ :1, ++ dnv_reg10_limit :15, ++ :1; ++ }; ++ struct { /* FLREG11 LAN CTRL0 */ ++ uint32_t dnv_reg11_base :15, ++ :1, ++ dnv_reg11_limit :15, ++ :1; ++ }; ++ struct { /* FLREG12 LAN CTRL1 */ ++ uint32_t dnv_reg12_base :15, ++ :1, ++ dnv_reg12_limit :15, ++ :1; ++ }; ++ ++ /* FLREG13 - Reserved */ ++ /* FLREG14 - Reserved */ ++ /* FLREG15 - Reserved */ ++ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + }; + +diff --git a/ichspi.c b/ichspi.c +index 6d1bd1a..742d424 100644 +--- a/ichspi.c ++++ b/ichspi.c +@@ -170,6 +170,52 @@ + #define ICH7_REG_OPTYPE 0x56 /* 16 Bits */ + #define ICH7_REG_OPMENU 0x58 /* 64 Bits */ + ++/* denverton controller register definition */ ++#if DELL_DENVERTON_SUPPORT == 1 ++#define DENVERTON_REG_BFPREG 0x00 /* 32 Bits SPI BIOS MMIO PRI */ ++#define DENVERTON_BFPREG_PRB_OFF 0 /* 0-14: BIOS Flash Promary Region Base */ ++#define DENVERTON_BFPREG_PRB (0x7FFF << DENVERTON_BFPREG_PRB_OFF) ++#define DENVERTON_BFPREG_PRL_OFF 16 /* 16-30: BIOS Flash Primary Region Limit */ ++#define DENVERTON_BFPREG_PRL (0xFFFF << DENVERTON_BFPREG_PRL_OFF) ++#define DENVERTON_REG_HSFS 0x04 /* 16 Bits Hardware Sequencing Flash Status */ ++#define DENVERTON_HSFS_FDONE_OFF 0 /* 0: Flash Cycle Done */ ++#define DENVERTON_HSFS_FDONE (0x1 << DENVERTON_HSFS_FDONE_OFF) ++#define DENVERTON_HSFS_FCERR_OFF 1 /* 1: Flash Cycle Error */ ++#define DENVERTON_HSFS_FCERR (0x1 << DENVERTON_HSFS_FCERR_OFF) ++#define DENVERTON_HSFS_FDOPSS_OFF 13 /* 13: Flash Descriptor Override Pin-Strap Status */ ++#define DENVERTON_HSFS_FDOPSS (0x1 << DENVERTON_HSFS_FDOPSS_OFF) ++#define DENVERTON_HSFS_FDV_OFF 14 /* 14: Flash Descriptor Valid */ ++#define DENVERTON_HSFS_FDV (0x1 << DENVERTON_HSFS_FDV_OFF) ++#define DENVERTON_HSFS_FLOCKDN_OFF 15 /* 15: Flash Configuration Lock-Down */ ++#define DENVERTON_HSFS_FLOCKDN (0x1 << DENVERTON_HSFS_FLOCKDN_OFF) ++#define DENVERTON_REG_HSFC 0x06 /* 16 Bits Hardware Sequencing Flash Control */ ++#define DENVERTON_HSFC_FGO_OFF 0 /* 0: Flash Cycle Go */ ++#define DENVERTON_HSFC_FGO (0x1 << DENVERTON_HSFC_FGO_OFF) ++#define DENVERTON_HSFC_FCYCLE_OFF 1 /* 1- 4: FLASH Cycle */ ++#define DENVERTON_HSFC_FCYCLE (0xF << DENVERTON_HSFC_FCYCLE_OFF) ++#define DENVERTON_HSFC_FDBC_OFF 8 /* 8-13: Flash Data Byte Count */ ++#define DENVERTON_HSFC_FDBC (0x3F << DENVERTON_HSFC_FDBC_OFF) ++#define DENVERTON_REG_FADDR 0x08 /* 32 Bits */ ++#define DENVERTON_REG_FDATA0 0x10 /* 32 Bits */ ++#define DENVERTON_REG_FRAP 0x50 /* 32 Bytes Flash Region Access Permissions */ ++#define DENVERTON_REG_FREG0 0x54 /* 32 Bytes Flash Region 0 */ ++#define DENVERTON_REG_PR0 0x84 /* 32 Bytes Protected Range 0 */ ++#define DENVERTON_PR_WP_OFF 31 /* 31: write protection enable */ ++#define DENVERTON_PR_RP_OFF 15 /* 15: read protection enable */ ++#define DENVERTON_REG_VSCC0 0xC4 /* 32 Bits Host Vendor Specific Component Capabilities for Component 0 */ ++#define DENVERTON_REG_VSCC1 0xC8 /* 32 Bits Host Vendor Specific Component Capabilities for Component 1 */ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ ++#ifdef DELL_AVOTON_SUPPORT ++extern int8_t is_avoton; ++#endif /* DELL_AVOTON_SUPPORT */ ++ ++#if DELL_DENVERTON_SUPPORT == 1 ++extern uint32_t dnv_bios_region_start; ++extern uint32_t dnv_bios_region_size; ++extern uint32_t dnv_bios_region_limit; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + /* ICH SPI configuration lock-down. May be set during chipset enabling. */ + static int ichspi_lock = 0; + +@@ -466,6 +512,8 @@ static int generate_opcodes(OPCODES * op) + + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + preop = REGREAD16(ICH7_REG_PREOP); + optype = REGREAD16(ICH7_REG_OPTYPE); + opmenu[0] = REGREAD32(ICH7_REG_OPMENU); +@@ -529,7 +577,7 @@ static int program_opcodes(OPCODES *op, int enable_undo) + opmenu[0] |= ((uint32_t) op->opcode[a].opcode) << (a * 8); + } + +- /*Program Allowable Opcodes 4 - 7 */ ++ /* Program Allowable Opcodes 4 - 7 */ + opmenu[1] = 0; + for (a = 4; a < 8; a++) { + opmenu[1] |= ((uint32_t) op->opcode[a].opcode) << ((a - 4) * 8); +@@ -538,6 +586,8 @@ static int program_opcodes(OPCODES *op, int enable_undo) + msg_pdbg2("\n%s: preop=%04x optype=%04x opmenu=%08x%08x\n", __func__, preop, optype, opmenu[0], opmenu[1]); + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + /* Register undo only for enable_undo=1, i.e. first call. */ + if (enable_undo) { + rmmio_valw(ich_spibar + ICH7_REG_PREOP); +@@ -603,10 +653,19 @@ static void ich_set_bbar(uint32_t min_addr) + int bbar_off; + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + bbar_off = 0x50; + break; + case CHIPSET_ICH8: ++#ifdef DELL_AVOTON_SUPPORT ++ case CHIPSET_AVOTON: ++#endif ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("BBAR offset is unknown on ICH8!\n"); ++#else + msg_perr("BBAR offset is unknown on ICH8!\n"); ++#endif + return; + case CHIPSET_ICH9: + default: /* Future version might behave the same */ +@@ -817,11 +876,17 @@ static int ich7_run_opcode(OPCODE op, uint32_t offset, + /* FIXME: make sure we do not needlessly cause transaction errors. */ + temp16 = REGREAD16(ICH7_REG_SPIS); + if (temp16 & SPIS_FCERR) { ++#ifndef FORCE10_SPI_CHANGE + msg_perr("Transaction error!\n"); ++#endif + /* keep reserved bits */ + temp16 &= SPIS_RESERVED_MASK; + REGWRITE16(ICH7_REG_SPIS, temp16 | SPIS_FCERR); ++#ifndef FORCE10_SPI_CHANGE + return 1; ++#else ++ return 0; ++#endif + } + + if ((!write_cmd) && (datalength != 0)) +@@ -838,6 +903,22 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset, + uint32_t temp32; + uint64_t opmenu; + int opcode_index; ++/* skip unused region for Rangeley */ ++ if (offset >= 0x10000 && offset <= 0x9fffff) { ++ uint32_t i = 0; ++ for (i = 0; i < datalength; i++) ++ *(data + i) = 0xff; ++ return 0; ++ } ++#ifdef DELL_AVOTON_SUPPORT ++ /* skip unused region for Rangeley */ ++ if (is_avoton && offset >= 0x10000 && offset <= 0x9fffff) { ++ uint32_t i = 0; ++ for (i = 0; i < datalength; i++) ++ *(data + i) = 0xff; ++ return 0; ++ } ++#endif /* AVOTON */ + + /* Is it a write command? */ + if ((op.spi_type == SPI_OPCODE_TYPE_WRITE_NO_ADDRESS) +@@ -939,14 +1020,20 @@ static int ich9_run_opcode(OPCODE op, uint32_t offset, + /* FIXME make sure we do not needlessly cause transaction errors. */ + temp32 = REGREAD32(ICH9_REG_SSFS); + if (temp32 & SSFS_FCERR) { ++#ifndef FORCE10_SPI_CHANGE + msg_perr("Transaction error!\n"); ++#endif + prettyprint_ich9_reg_ssfs(temp32); + prettyprint_ich9_reg_ssfc(temp32); + /* keep reserved bits */ + temp32 &= SSFS_RESERVED_MASK | SSFC_RESERVED_MASK; + /* Clear the transaction error. */ + REGWRITE32(ICH9_REG_SSFS, temp32 | SSFS_FCERR); ++#ifndef FORCE10_SPI_CHANGE + return 1; ++#else ++ return 0; ++#endif + } + + if ((!write_cmd) && (datalength != 0)) +@@ -975,6 +1062,8 @@ static int run_opcode(const struct flashctx *flash, OPCODE op, uint32_t offset, + + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + return ich7_run_opcode(op, offset, datalength, data, maxlength); + case CHIPSET_ICH8: + default: /* Future version might behave the same */ +@@ -1418,6 +1507,191 @@ static int ich_spi_send_multicommand(struct flashctx *flash, + return ret; + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++/* Sets FLA in FADDR to (addr & 0x01FFFFFF) without touching other bits. */ ++static void dnv_hwseq_set_addr(uint32_t addr) ++{ ++ uint32_t addr_old = REGREAD32(DENVERTON_REG_FADDR) & ~0x01FFFFFF; ++ REGWRITE32(DENVERTON_REG_FADDR, (addr & 0x01FFFFFF) | addr_old); ++} ++ ++/* Polls for Cycle Done Status, Flash Cycle Error or timeout in 8 us intervals. ++ Resets all error flags in HSFS. ++ Returns 0 if the cycle completes successfully without errors within ++ timeout us, 1 on errors. */ ++static int dnv_hwseq_wait_for_cycle_complete(uint32_t timeout, ++ uint32_t len) ++{ ++ uint16_t hsfs; ++ uint32_t addr; ++ ++ timeout /= 8; /* scale timeout duration to counter */ ++ while ((((hsfs = REGREAD16(DENVERTON_REG_HSFS)) & ++ (DENVERTON_HSFS_FDONE | DENVERTON_HSFS_FCERR)) == 0) && ++ --timeout) { ++ programmer_delay(8); ++ } ++ REGWRITE16(DENVERTON_REG_HSFS, REGREAD16(DENVERTON_REG_HSFS)); ++ if (!timeout) { ++ addr = REGREAD32(DENVERTON_REG_FADDR) & 0x01FFFFFF; ++ msg_perr("Timeout error between offset 0x%08x and " ++ "0x%08x (= 0x%08x + %d)!\n", ++ addr, addr + len - 1, addr, len - 1); ++ return 1; ++ } ++ ++ if (hsfs & DENVERTON_HSFS_FCERR) { ++ addr = REGREAD32(DENVERTON_REG_FADDR) & 0x01FFFFFF; ++ msg_perr("Transaction error between offset 0x%08x and " ++ "0x%08x (= 0x%08x + %d)!\n", ++ addr, addr + len - 1, addr, len - 1); ++ return 1; ++ } ++ return 0; ++} ++ ++int dnv_read_JEDEC_ID(uint8_t *buf) ++{ ++ uint16_t hsfc; ++ uint16_t timeout = 100 * 60; ++ uint8_t len = 3; ++ ++ /* clear FDONE, FCERR, AEL by writing 1 to them (if they are set) */ ++ REGWRITE16(DENVERTON_REG_HSFS, REGREAD16(DENVERTON_REG_HSFS)); ++ ++ dnv_hwseq_set_addr(0); ++ hsfc = REGREAD16(DENVERTON_REG_HSFC); ++ hsfc &= ~DENVERTON_HSFC_FCYCLE; /* clear operation */ ++ hsfc |= (0x6 << DENVERTON_HSFC_FCYCLE_OFF); /* set read JEDEC ID operation */ ++ hsfc &= ~DENVERTON_HSFC_FDBC; /* clear byte count */ ++ /* set byte count */ ++ hsfc |= (((len - 1) << DENVERTON_HSFC_FDBC_OFF) & DENVERTON_HSFC_FDBC); ++ hsfc |= DENVERTON_HSFC_FGO; /* start */ ++ REGWRITE16(DENVERTON_REG_HSFC, hsfc); ++ ++ if (dnv_hwseq_wait_for_cycle_complete(timeout, len)) ++ return 1; ++ ich_read_data(buf, len, DENVERTON_REG_FDATA0); ++ return 0; ++} ++ ++static int dnv_hwseq_probe(struct flashctx *flash) ++{ ++ uint8_t jedec_id[3]; ++ uint32_t tmp, manufacture_id, model_id; ++ struct block_eraser *eraser; ++ const struct flashchip *chip; ++ ++ msg_gdbg("Using HW Sequency to read JEDEC ID and find SPI flash.\n"); ++ if (dnv_read_JEDEC_ID(jedec_id)) { ++ msg_cerr("Can't get JEDEC ID through HW Sequency\n"); ++ return -1; ++ } ++ ++ manufacture_id = (uint32_t)jedec_id[0]; ++ model_id = (uint32_t)(jedec_id[1] << 8 | jedec_id[2]); ++ ++ for (chip = flashchips; chip && chip->name; chip++) { ++ if (chip->manufacture_id == manufacture_id && chip->model_id == model_id) { ++ break; ++ } ++ } ++ ++ flash->bios_size = (hwseq_data.size_comp0 + hwseq_data.size_comp1) / 1024; ++ ++ /* We only replace base information. The functions still use hw sequency, like read and write */ ++ flash->chip->vendor = chip->vendor; ++ flash->chip->name = chip->name; ++ flash->chip->manufacture_id = chip->manufacture_id; ++ flash->chip->model_id = chip->model_id; ++ flash->chip->total_size = chip->total_size; ++ flash->chip->page_size = chip->page_size; ++ ++ msg_cdbg("Hardware sequencing reports %d attached SPI flash chip", ++ (hwseq_data.size_comp1 != 0) ? 2 : 1); ++ if (hwseq_data.size_comp1 != 0) ++ msg_cdbg("s with a combined"); ++ else ++ msg_cdbg(" with a"); ++ msg_cdbg(" density of %d kB.\n", flash->chip->total_size); ++ ++ eraser = &(flash->chip->block_erasers[0]); ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_BFPREG); ++ dnv_bios_region_start = ((tmp & DENVERTON_BFPREG_PRB) >> DENVERTON_BFPREG_PRB_OFF) << 12; ++ dnv_bios_region_limit = ((tmp & DENVERTON_BFPREG_PRL) >> ++ DENVERTON_BFPREG_PRL_OFF) << 12 | ((1 << 12) -1); ++ dnv_bios_region_size = dnv_bios_region_limit - dnv_bios_region_start + 1; ++ eraser->eraseblocks[0].size = 4 * 1024; // 4K ++ eraser->eraseblocks[0].count = dnv_bios_region_size / ++ eraser->eraseblocks[0].size; ++ ++ flash->chip->tested = TEST_OK_PREW; ++ return 1; ++} ++ ++static int dnv_block_check(struct flashctx *flash, uint32_t addr, uint32_t len, SPI_SMI_CMD cmd) ++{ ++ char msg[3][4][32] = { ++ {"Read", "read", "", "Reading"}, ++ {"Erase", "erase", "Not erasing anthing.", "Erasing"}, ++ {"Write", "write", "", "Writing"}}; ++ ++ /* Although the hardware supports this (it would erase the whole block ++ * containing the address) we play safe here. */ ++ if (addr % DELL_DENVERTON_BLOCK_SIZE != 0) { ++ msg_cerr("%s address 0x%06x is not aligned to the %s " ++ "block boundary (any multiple of %d). %s\n", ++ msg[cmd][0], addr, msg[cmd][1], DELL_DENVERTON_BLOCK_SIZE, msg[cmd][2]); ++ return -1; ++ } ++ ++ if (addr + len > flash->chip->total_size * 1024) { ++ msg_perr("Request to %s some inaccessible memory address(es)" ++ " (addr=0x%x, len=%d). %s\n", msg[cmd][1], ++ addr, len, msg[cmd][2]); ++ return -1; ++ } ++ ++ msg_pdbg("%s %d bytes starting at 0x%06x.\n", msg[cmd][3], len, addr); ++ return 0; ++} ++ ++static int dnv_smi_spi(struct flashctx *flash, uint8_t *buf, uint32_t addr, ++ uint32_t len, SPI_SMI_CMD cmd) ++{ ++ int32_t ret = 0; ++ uint32_t block_index = 0; ++ ++ ret = dnv_block_check(flash, addr, len, cmd); ++ if (ret == 0) { ++ for (block_index = 0; block_index * DELL_DENVERTON_BLOCK_SIZE < len; block_index++ ) { ++ if ((ret = dnv_smi_doit(addr - dnv_bios_region_start, buf, cmd)) != 0) { ++ break; ++ } ++ buf += DELL_DENVERTON_BLOCK_SIZE; ++ addr += DELL_DENVERTON_BLOCK_SIZE; ++ } ++ } ++ return ret; ++} ++ ++static int dnv_smi_erase_spi(struct flashctx *flash, uint32_t addr, uint32_t len) ++{ ++ return dnv_smi_spi(flash, NULL, addr, len, SMI_ERASE_SPI); ++} ++ ++static int dnv_smi_read_spi(struct flashctx *flash, uint8_t *buf, uint32_t addr, uint32_t len) ++{ ++ return dnv_smi_spi(flash, buf, addr, len, SMI_READ_SPI); ++} ++ ++static int dnv_smi_write_spi(struct flashctx *flash, uint8_t *buf, uint32_t addr, uint32_t len) ++{ ++ return dnv_smi_spi(flash, buf, addr, len, SMI_WRITE_SPI); ++} ++ ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + #define ICH_BMWAG(x) ((x >> 24) & 0xff) + #define ICH_BMRAG(x) ((x >> 16) & 0xff) + #define ICH_BRWA(x) ((x >> 8) & 0xff) +@@ -1452,6 +1726,9 @@ static int ich9_handle_frap(uint32_t frap, int i) + msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i, + region_names[i], base, (limit | 0x0fff), + access_names[rwperms]); ++#ifdef FORCE10_SPI_CHANGE ++ add_romentry(base, (limit | 0x0fff), region_names[i]); ++#endif + return 0; + } + +@@ -1514,6 +1791,90 @@ static void ich9_set_pr(int i, int read_prot, int write_prot) + msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr)); + } + ++#if DELL_DENVERTON_SUPPORT == 1 ++/* returns 0 if region is unused or r/w */ ++static int dnv_handle_frap(uint32_t frap, int32_t i) ++{ ++ static const char *const access_names[4] = { ++ "locked", "read-only", "write-only", "read-write" ++ }; ++ static const char *const region_names[5] = { ++ "Flash Descriptor", "BIOS", "Management Engine", ++ "Gigabit Ethernet", "Platform Data" ++ }; ++ uint32_t base, limit; ++ int32_t rwperms = (((ICH_BRWA(frap) >> i) & 1) << 1) | ++ (((ICH_BRRA(frap) >> i) & 1) << 0); ++ int32_t offset = DENVERTON_REG_FREG0 + i * 4; ++ uint32_t freg = mmio_readl(ich_spibar + offset); ++ ++ base = ICH_FREG_BASE(freg); ++ limit = ICH_FREG_LIMIT(freg); ++ if (base > limit || (freg == 0 && i > 0)) { ++ /* this FREG is disabled */ ++ msg_pdbg2("0x%02X: 0x%08x FREG%i: %s region is unused.\n", ++ offset, freg, i, region_names[i]); ++ return 0; ++ } ++ msg_pdbg("0x%02X: 0x%08x ", offset, freg); ++ if (rwperms == 0x3) { ++ msg_pdbg("FREG%i: %s region (0x%08x-0x%08x) is %s.\n", i, ++ region_names[i], base, (limit | 0x0fff), ++ access_names[rwperms]); ++ return 0; ++ } ++ ++ msg_pwarn("FREG%i: Warning: %s region (0x%08x-0x%08x) is %s.\n", i, ++ region_names[i], base, (limit | 0x0fff), ++ access_names[rwperms]); ++ return 1; ++} ++ ++/* returns 0 if range is unused (i.e. r/w) */ ++static int dnv_handle_pr(int32_t i) ++{ ++ static const char *const access_names[3] = { ++ "locked", "read-only", "write-only" ++ }; ++ uint8_t off = DENVERTON_REG_PR0 + (i * 4); ++ uint32_t pr = mmio_readl(ich_spibar + off); ++ uint32_t rwperms = ICH_PR_PERMS(pr); ++ ++ if (rwperms == 0x3) { ++ msg_pdbg2("0x%02X: 0x%08x (PR%u is unused)\n", off, pr, i); ++ return 0; ++ } ++ ++ msg_pdbg("0x%02X: 0x%08x ", off, pr); ++ msg_pwarn("PR%u: Warning: 0x%08x-0x%08x is %s.\n", i, ICH_FREG_BASE(pr), ++ ICH_FREG_LIMIT(pr) | 0x0fff, access_names[rwperms]); ++ return 1; ++} ++ ++/* Set/Clear the read and write protection enable bits of PR register @i ++ * according to @read_prot and @write_prot. */ ++static void dnv_set_pr(int32_t i, int32_t read_prot, int32_t write_prot) ++{ ++ void *addr = ich_spibar + DENVERTON_REG_PR0 + (i * 4); ++ uint32_t old = mmio_readl(addr); ++ uint32_t new; ++ ++ msg_gspew("PR%u is 0x%08x", i, old); ++ new = old & ~((1 << DENVERTON_PR_RP_OFF) | (1 << DENVERTON_PR_WP_OFF)); ++ if (read_prot) ++ new |= (1 << DENVERTON_PR_RP_OFF); ++ if (write_prot) ++ new |= (1 << DENVERTON_PR_WP_OFF); ++ if (old == new) { ++ msg_gspew(" already.\n"); ++ return; ++ } ++ msg_gspew(", trying to set it to 0x%08x ", new); ++ rmmio_writel(new, addr); ++ msg_gspew("resulted in 0x%08x.\n", mmio_readl(addr)); ++} ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ + static const struct spi_programmer spi_programmer_ich7 = { + .type = SPI_CONTROLLER_ICH7, + .max_data_read = 64, +@@ -1545,12 +1906,21 @@ static const struct opaque_programmer opaque_programmer_ich_hwseq = { + .erase = ich_hwseq_block_erase, + }; + +-int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, +- enum ich_chipset ich_gen) ++#if DELL_DENVERTON_SUPPORT == 1 ++static const struct opaque_programmer opaque_master_dnv_hwseq = { ++ .max_data_read = 64, ++ .max_data_write = 64, ++ .probe = dnv_hwseq_probe, ++ .read = dnv_smi_read_spi, ++ .write = dnv_smi_write_spi, ++ .erase = dnv_smi_erase_spi, ++}; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ ++ ++int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_gen) + { + int i; +- uint8_t old, new; +- uint16_t spibar_offset, tmp2; ++ uint16_t tmp2; + uint32_t tmp; + char *arg; + int ich_spi_force = 0; +@@ -1564,42 +1934,18 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + } ich_spi_mode = ich_auto; + + ich_generation = ich_gen; +- +- switch (ich_generation) { +- case CHIPSET_ICH_UNKNOWN: +- return ERROR_FATAL; +- case CHIPSET_ICH7: +- case CHIPSET_ICH8: +- spibar_offset = 0x3020; +- break; +- case CHIPSET_ICH9: +- default: /* Future version might behave the same */ +- spibar_offset = 0x3800; +- break; +- } +- +- /* SPIBAR is at RCRB+0x3020 for ICH[78] and RCRB+0x3800 for ICH9. */ +- msg_pdbg("SPIBAR = 0x%x + 0x%04x\n", base, spibar_offset); +- +- /* Assign Virtual Address */ +- ich_spibar = rcrb + spibar_offset; ++ ich_spibar = spibar; + + switch (ich_generation) { + case CHIPSET_ICH7: ++ case CHIPSET_TUNNEL_CREEK: ++ case CHIPSET_CENTERTON: + msg_pdbg("0x00: 0x%04x (SPIS)\n", + mmio_readw(ich_spibar + 0)); + msg_pdbg("0x02: 0x%04x (SPIC)\n", + mmio_readw(ich_spibar + 2)); + msg_pdbg("0x04: 0x%08x (SPIA)\n", + mmio_readl(ich_spibar + 4)); +- for (i = 0; i < 8; i++) { +- int offs; +- offs = 8 + (i * 8); +- msg_pdbg("0x%02x: 0x%08x (SPID%d)\n", offs, +- mmio_readl(ich_spibar + offs), i); +- msg_pdbg("0x%02x: 0x%08x (SPID%d+4)\n", offs + 4, +- mmio_readl(ich_spibar + offs + 4), i); +- } + ichspi_bbar = mmio_readl(ich_spibar + 0x50); + msg_pdbg("0x50: 0x%08x (BBAR)\n", + ichspi_bbar); +@@ -1625,7 +1971,123 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + ich_set_bbar(0); + register_spi_programmer(&spi_programmer_ich7); + break; ++#if DELL_DENVERTON_SUPPORT == 1 ++ case CHIPSET_DENVERTON: ++ ++ tmp2 = mmio_readw(ich_spibar + DENVERTON_REG_HSFS); ++ msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2); ++ if (tmp2 & DENVERTON_HSFS_FLOCKDN) { ++ msg_pwarn("Warning: SPI Configuration Lockdown activated.\n"); ++ ichspi_lock = 1; ++ } ++ if (tmp2 & DENVERTON_HSFS_FDV) ++ desc_valid = 1; ++ if (!(tmp2 & DENVERTON_HSFS_FDOPSS) && desc_valid) ++ msg_pinfo("The Flash Descriptor Override Strap-Pin is set. " ++ "Restrictions implied by\n" ++ "the Master Section of the flash descriptor are " ++ "NOT in effect. Please note\n" ++ "that Protected Range (PR) restrictions still apply.\n"); ++ if (desc_valid) { ++ tmp2 = mmio_readw(ich_spibar + DENVERTON_REG_HSFC); ++ msg_pdbg("0x06: 0x%04x (HSFC)\n", tmp2); ++ } ++ ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_FADDR); ++ msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp); ++ ++ if (desc_valid) { ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_FRAP); ++ msg_pdbg("0x50: 0x%08x (FRAP)", tmp); ++ ++ /* Handle FREGx and FRAP registers */ ++ for (i=0; i < 5; i++) ++ ich_spi_rw_restricted |= dnv_handle_frap(tmp, i); ++ if (ich_spi_rw_restricted) ++ msg_pwarn("Not all flash regions are freely accessible " ++ "by flashrom. This is most likely\n" ++ "due to an active ME. " ++ "Please see http://flashrom.org/ME for details.\n"); ++ } ++ ++ /* Handle PR registers */ ++ for (i = 0; i < 5; i++) { ++ if (!ichspi_lock) ++ dnv_set_pr(i, 0, 0); ++ ich_spi_rw_restricted |= dnv_handle_pr(i); ++ } ++ ++ if (ich_spi_force) ++ msg_pinfo("Continuing with write support because " ++ "the user forced us to!\n"); ++ ++ if (desc_valid) { ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_VSCC0); ++ msg_pdbg("0xC4: 0x%08x (VSCC0)\n", tmp); ++ ++ tmp = mmio_readl(ich_spibar + DENVERTON_REG_VSCC1); ++ msg_pdbg("0xC8: 0x%08x (VSCC1)\n", tmp); ++ ++ if (read_ich_descriptors_via_fdo(ich_spibar, &desc) == ICH_RET_OK) ++ prettyprint_ich_descriptors(ich_gen, &desc); ++ ++ /* If the descriptor is valid and indicates multiple ++ * flash devices we need to use hwseq to be able to ++ * access the second flash device. ++ */ ++ if (ich_spi_mode == ich_auto && desc.content.NC != 0) { ++ msg_pinfo("Enabling hardware sequencing due to " ++ "multiple flash chips detected.\n"); ++ ich_spi_mode = ich_hwseq; ++ } ++ } ++ ++ if (ich_spi_mode == ich_auto && ichspi_lock) { ++ msg_pinfo("Enabling hardware sequencing because " ++ "some important opcode is locked.\n"); ++ ich_spi_mode = ich_hwseq; ++ } ++ ++ if (ich_spi_mode == ich_auto && ichspi_lock) { ++ msg_pinfo("Enabling hardware sequencing because " ++ "some important opcode is locked.\n"); ++ ich_spi_mode = ich_hwseq; ++ } ++ ++ if (ich_spi_mode == ich_hwseq) { ++ if (!desc_valid) { ++ msg_perr("Hardware sequencing was requested " ++ "but the flash descriptor is not valid. Aborting.\n"); ++ return ERROR_FATAL; ++ } ++ ++ uint32_t tmpi = getFCBA_component_density(&desc, 0); ++ if (tmpi < 0) { ++ msg_perr("Could not determine density of " ++ "flash component %d.\n", 0); ++ return ERROR_FATAL; ++ } ++ hwseq_data.size_comp0 = tmpi; ++ ++ tmpi = getFCBA_component_density(&desc, 1); ++ if (tmpi < 0) { ++ msg_perr("Could not determine density of flash component %d.\n", 1); ++ return ERROR_FATAL; ++ } ++ hwseq_data.size_comp1 = tmpi; ++ ++ register_opaque_programmer(&opaque_master_dnv_hwseq); ++ } else { ++ msg_perr("[%s:%d] Error!!!\n", __func__, __LINE__); ++ return -1; ++ } ++ ++ break; ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + case CHIPSET_ICH8: ++#ifdef DELL_AVOTON_SUPPORT ++ case CHIPSET_AVOTON: ++#endif + default: /* Future version might behave the same */ + arg = extract_programmer_param("ich_spi_mode"); + if (arg && !strcmp(arg, "hwseq")) { +@@ -1669,7 +2131,11 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + msg_pdbg("0x04: 0x%04x (HSFS)\n", tmp2); + prettyprint_ich9_reg_hsfs(tmp2); + if (tmp2 & HSFS_FLOCKDN) { ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Warning: SPI Configuration Lockdown activated.\n"); ++#else + msg_pwarn("Warning: SPI Configuration Lockdown activated.\n"); ++#endif + ichspi_lock = 1; + } + if (tmp2 & HSFS_FDV) +@@ -1690,6 +2156,7 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + msg_pdbg2("0x08: 0x%08x (FADDR)\n", tmp); + + if (desc_valid) { ++ + tmp = mmio_readl(ich_spibar + ICH9_REG_FRAP); + msg_pdbg("0x50: 0x%08x (FRAP)\n", tmp); + msg_pdbg("BMWAG 0x%02x, ", ICH_BMWAG(tmp)); +@@ -1750,10 +2217,15 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + msg_pdbg("VSCC: "); + prettyprint_ich_reg_vscc(tmp, MSG_DEBUG); + } else { ++#ifdef DELL_AVOTON_SUPPORT ++ if (ich_generation != CHIPSET_AVOTON) { ++#endif + ichspi_bbar = mmio_readl(ich_spibar + ICH9_REG_BBAR); + msg_pdbg("0xA0: 0x%08x (BBAR)\n", + ichspi_bbar); +- ++#ifdef DELL_AVOTON_SUPPORT ++ } ++#endif + if (desc_valid) { + tmp = mmio_readl(ich_spibar + ICH9_REG_LVSCC); + msg_pdbg("0xC4: 0x%08x (LVSCC)\n", tmp); +@@ -1811,21 +2283,6 @@ int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, + break; + } + +- old = pci_read_byte(dev, 0xdc); +- msg_pdbg("SPI Read Configuration: "); +- new = (old >> 2) & 0x3; +- switch (new) { +- case 0: +- case 1: +- case 2: +- msg_pdbg("prefetching %sabled, caching %sabled, ", +- (new & 0x2) ? "en" : "dis", +- (new & 0x1) ? "dis" : "en"); +- break; +- default: +- msg_pdbg("invalid prefetching/caching settings, "); +- break; +- } + return 0; + } + +@@ -1844,7 +2301,9 @@ int via_init_spi(struct pci_dev *dev, uint32_t mmio_base) + { + int i; + +- ich_spibar = physmap("VIA SPI MMIO registers", mmio_base, 0x70); ++ ich_spibar = rphysmap("VIA SPI MMIO registers", mmio_base, 0x70); ++ if (ich_spibar == ERROR_PTR) ++ return ERROR_FATAL; + /* Do we really need no write enable? Like the LPC one at D17F0 0x40 */ + + /* Not sure if it speaks all these bus protocols. */ +diff --git a/internal.c b/internal.c +index ab3c81f..30b184f 100644 +--- a/internal.c ++++ b/internal.c +@@ -331,9 +331,8 @@ int internal_init(void) + return ret; + + #if defined(__i386__) || defined(__x86_64__) +- /* Probe unconditionally for IT87* LPC->SPI translation and for +- * IT87* Parallel write enable. +- */ ++ /* Probe unconditionally for ITE Super I/O chips. This enables LPC->SPI translation on IT87* and ++ * parallel writes on IT8705F. Also, this handles the manual chip select for Gigabyte's DualBIOS. */ + init_superio_ite(); + #endif + +diff --git a/it85spi.c b/it85spi.c +index 0b074eb..7efc680 100644 +--- a/it85spi.c ++++ b/it85spi.c +@@ -262,6 +262,9 @@ static int it85xx_spi_common_init(struct superio s) + * Major TODO here, and it will be a lot of work. + */ + base = (chipaddr)physmap("it85 communication", 0xFFFFF000, 0x1000); ++ if (base == (chipaddr)ERROR_PTR) ++ return 1; ++ + msg_pdbg("%s():%d base=0x%08x\n", __func__, __LINE__, + (unsigned int)base); + ce_high = (unsigned char *)(base + 0xE00); /* 0xFFFFFE00 */ +diff --git a/it87spi.c b/it87spi.c +index 8e4e0ad..be7f234 100644 +--- a/it87spi.c ++++ b/it87spi.c +@@ -27,6 +27,7 @@ + + #include + #include ++#include + #include "flash.h" + #include "chipdrivers.h" + #include "programmer.h" +@@ -36,7 +37,7 @@ + #define ITE_SUPERIO_PORT1 0x2e + #define ITE_SUPERIO_PORT2 0x4e + +-uint16_t it8716f_flashport = 0; ++static uint16_t it8716f_flashport = 0; + /* use fast 33MHz SPI (<>0) or slow 16MHz (0) */ + static int fast_spi = 1; + +@@ -124,10 +125,40 @@ static const struct spi_programmer spi_programmer_it87xx = { + static uint16_t it87spi_probe(uint16_t port) + { + uint8_t tmp = 0; +- char *portpos = NULL; + uint16_t flashport = 0; + + enter_conf_mode_ite(port); ++ ++ char *param = extract_programmer_param("dualbiosindex"); ++ if (param != NULL) { ++ sio_write(port, 0x07, 0x07); /* Select GPIO LDN */ ++ tmp = sio_read(port, 0xEF); ++ if (*param == '\0') { /* Print current setting only. */ ++ free(param); ++ } else { ++ char *dualbiosindex_suffix; ++ errno = 0; ++ long chip_index = strtol(param, &dualbiosindex_suffix, 0); ++ free(param); ++ if (errno != 0 || *dualbiosindex_suffix != '\0' || chip_index < 0 || chip_index > 1) { ++ msg_perr("DualBIOS: Invalid chip index requested - choose 0 or 1.\n"); ++ exit_conf_mode_ite(port); ++ return 1; ++ } ++ if (chip_index != (tmp & 1)) { ++ msg_pdbg("DualBIOS: Previous chip index: %d\n", tmp & 1); ++ sio_write(port, 0xEF, (tmp & 0xFE) | chip_index); ++ tmp = sio_read(port, 0xEF); ++ if ((tmp & 1) != chip_index) { ++ msg_perr("DualBIOS: Chip selection failed.\n"); ++ exit_conf_mode_ite(port); ++ return 1; ++ } ++ } ++ } ++ msg_pinfo("DualBIOS: Selected chip: %d\n", tmp & 1); ++ } ++ + /* NOLDN, reg 0x24, mask out lowest bit (suspend) */ + tmp = sio_read(port, 0x24) & 0xFE; + /* Check if LPC->SPI translation is active. */ +@@ -163,11 +194,11 @@ static uint16_t it87spi_probe(uint16_t port) + flashport |= sio_read(port, 0x65); + msg_pdbg("Serial flash port 0x%04x\n", flashport); + /* Non-default port requested? */ +- portpos = extract_programmer_param("it87spiport"); +- if (portpos) { ++ param = extract_programmer_param("it87spiport"); ++ if (param) { + char *endptr = NULL; + unsigned long forced_flashport; +- forced_flashport = strtoul(portpos, &endptr, 0); ++ forced_flashport = strtoul(param, &endptr, 0); + /* Port 0, port >0x1000, unaligned ports and garbage strings + * are rejected. + */ +@@ -180,7 +211,8 @@ static uint16_t it87spi_probe(uint16_t port) + msg_perr("Error: it87spiport specified, but no valid " + "port specified.\nPort must be a multiple of " + "0x8 and lie between 0x100 and 0xff8.\n"); +- free(portpos); ++ exit_conf_mode_ite(port); ++ free(param); + return 1; + } else { + flashport = (uint16_t)forced_flashport; +@@ -190,7 +222,7 @@ static uint16_t it87spi_probe(uint16_t port) + sio_write(port, 0x65, (flashport & 0xff)); + } + } +- free(portpos); ++ free(param); + exit_conf_mode_ite(port); + it8716f_flashport = flashport; + if (internal_buses_supported & BUS_SPI) +@@ -228,6 +260,7 @@ int init_superio_ite(void) + case 0x8716: + case 0x8718: + case 0x8720: ++ case 0x8728: + ret |= it87spi_probe(superios[i].port); + break; + default: +diff --git a/layout.c b/layout.c +index 1bd3152..d00c16c 100644 +--- a/layout.c ++++ b/layout.c +@@ -3,6 +3,7 @@ + * + * Copyright (C) 2005-2008 coresystems GmbH + * (Written by Stefan Reinauer for coresystems GmbH) ++ * Copyright (C) 2011-2013 Stefan Tauner + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by +@@ -25,24 +26,23 @@ + #include "flash.h" + #include "programmer.h" + +-static int romimages = 0; +- + #define MAX_ROMLAYOUT 32 + + typedef struct { +- unsigned int start; +- unsigned int end; ++ chipoff_t start; ++ chipoff_t end; + unsigned int included; + char name[256]; +-} romlayout_t; ++} romentry_t; + +-/* include_args lists arguments specified at the command line with -i. They +- * must be processed at some point so that desired regions are marked as +- * "included" in the rom_entries list. +- */ ++/* rom_entries store the entries specified in a layout file and associated run-time data */ ++static romentry_t rom_entries[MAX_ROMLAYOUT]; ++static int num_rom_entries = 0; /* the number of successfully parsed rom_entries */ ++ ++/* include_args holds the arguments specified at the command line with -i. They must be processed at some point ++ * so that desired regions are marked as "included" in the rom_entries list. */ + static char *include_args[MAX_ROMLAYOUT]; +-static int num_include_args = 0; /* the number of valid entries. */ +-static romlayout_t rom_entries[MAX_ROMLAYOUT]; ++static int num_include_args = 0; /* the number of valid include_args. */ + + #ifndef __LIBPAYLOAD__ + int read_romlayout(char *name) +@@ -62,12 +62,13 @@ int read_romlayout(char *name) + while (!feof(romlayout)) { + char *tstr1, *tstr2; + +- if (romimages >= MAX_ROMLAYOUT) { ++ if (num_rom_entries >= MAX_ROMLAYOUT) { + msg_gerr("Maximum number of ROM images (%i) in layout " + "file reached.\n", MAX_ROMLAYOUT); ++ fclose(romlayout); + return 1; + } +- if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[romimages].name)) ++ if (2 != fscanf(romlayout, "%s %s\n", tempstr, rom_entries[num_rom_entries].name)) + continue; + #if 0 + // fscanf does not like arbitrary comments like that :( later +@@ -82,13 +83,13 @@ int read_romlayout(char *name) + fclose(romlayout); + return 1; + } +- rom_entries[romimages].start = strtol(tstr1, (char **)NULL, 16); +- rom_entries[romimages].end = strtol(tstr2, (char **)NULL, 16); +- rom_entries[romimages].included = 0; +- romimages++; ++ rom_entries[num_rom_entries].start = strtol(tstr1, (char **)NULL, 16); ++ rom_entries[num_rom_entries].end = strtol(tstr2, (char **)NULL, 16); ++ rom_entries[num_rom_entries].included = 0; ++ num_rom_entries++; + } + +- for (i = 0; i < romimages; i++) { ++ for (i = 0; i < num_rom_entries; i++) { + msg_gdbg("romlayout %08x - %08x named %s\n", + rom_entries[i].start, + rom_entries[i].end, rom_entries[i].name); +@@ -100,6 +101,33 @@ int read_romlayout(char *name) + } + #endif + ++ ++#ifdef FORCE10_SPI_CHANGE ++int add_romentry(chipoff_t start, chipoff_t end, const char *name) ++{ ++ int len = 0; ++ ++ if (num_rom_entries >= MAX_ROMLAYOUT) { ++ msg_gerr("Maximum number of ROM images (%i) in layout " ++ "file reached.\n", MAX_ROMLAYOUT); ++ return 1; ++ } ++ rom_entries[num_rom_entries].start = start; ++ rom_entries[num_rom_entries].end = end; ++ rom_entries[num_rom_entries].included = 1; ++ len = strlen(name); ++ if (len > 256) { ++ msg_gdbg("terminating rom entry name to 256 as it exceeds max length\n"); ++ len = 255; ++ } ++ strncpy(rom_entries[num_rom_entries].name, name, len); ++ msg_gdbg("Adding rom entry: %08x - %08x named %s\n", rom_entries[num_rom_entries].start, ++ rom_entries[num_rom_entries].end, rom_entries[num_rom_entries].name); ++ num_rom_entries++; ++ return 0; ++} ++#endif ++ + /* returns the index of the entry (or a negative value if it is not found) */ + int find_include_arg(const char *const name) + { +@@ -139,11 +167,11 @@ static int find_romentry(char *name) + { + int i; + +- if (!romimages) ++ if (num_rom_entries == 0) + return -1; + + msg_gspew("Looking for region \"%s\"... ", name); +- for (i = 0; i < romimages; i++) { ++ for (i = 0; i < num_rom_entries; i++) { + if (!strcmp(rom_entries[i].name, name)) { + rom_entries[i].included = 1; + msg_gspew("found.\n"); +@@ -166,7 +194,7 @@ int process_include_args(void) + return 0; + + /* User has specified an area, but no layout file is loaded. */ +- if (!romimages) { ++ if (num_rom_entries == 0) { + msg_gerr("Region requested (with -i \"%s\"), " + "but no layout data is available.\n", + include_args[0]); +@@ -190,15 +218,30 @@ int process_include_args(void) + return 0; + } + +-romlayout_t *get_next_included_romentry(unsigned int start) ++void layout_cleanup(void) ++{ ++ int i; ++ for (i = 0; i < num_include_args; i++) { ++ free(include_args[i]); ++ include_args[i] = NULL; ++ } ++ num_include_args = 0; ++ ++ for (i = 0; i < num_rom_entries; i++) { ++ rom_entries[i].included = 0; ++ } ++ num_rom_entries = 0; ++} ++ ++romentry_t *get_next_included_romentry(unsigned int start) + { + int i; + unsigned int best_start = UINT_MAX; +- romlayout_t *best_entry = NULL; +- romlayout_t *cur; ++ romentry_t *best_entry = NULL; ++ romentry_t *cur; + + /* First come, first serve for overlapping regions. */ +- for (i = 0; i < romimages; i++) { ++ for (i = 0; i < num_rom_entries; i++) { + cur = &rom_entries[i]; + if (!cur->included) + continue; +@@ -217,18 +260,43 @@ romlayout_t *get_next_included_romentry(unsigned int start) + return best_entry; + } + +-int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents) ++/* Validate and - if needed - normalize layout entries. */ ++int normalize_romentries(const struct flashctx *flash) ++{ ++ chipsize_t total_size = flash->chip->total_size * 1024; ++ int ret = 0; ++ ++ int i; ++ for (i = 0; i < num_rom_entries; i++) { ++ if (rom_entries[i].start >= total_size || rom_entries[i].end >= total_size) { ++ msg_gwarn("Warning: Address range of region \"%s\" exceeds the current chip's " ++ "address space.\n", rom_entries[i].name); ++ if (rom_entries[i].included) ++ ret = 1; ++ } ++ if (rom_entries[i].start > rom_entries[i].end) { ++ msg_gerr("Error: Size of the address range of region \"%s\" is not positive.\n", ++ rom_entries[i].name); ++ ret = 1; ++ } ++ } ++ ++ return ret; ++} ++ ++int build_new_image(const struct flashctx *flash, uint8_t *oldcontents, uint8_t *newcontents) + { + unsigned int start = 0; +- romlayout_t *entry; ++ romentry_t *entry; + unsigned int size = flash->chip->total_size * 1024; + + /* If no regions were specified for inclusion, assume + * that the user wants to write the complete new image. + */ ++#ifndef FORCE10_SPI_CHANGE + if (num_include_args == 0) + return 0; +- ++#endif + /* Non-included romentries are ignored. + * The union of all included romentries is used from the new image. + */ +@@ -239,7 +307,7 @@ int handle_romentries(const struct flashctx *flash, uint8_t *oldcontents, uint8_ + memcpy(newcontents + start, oldcontents + start, + size - start); + break; +- } ++ } + /* For non-included region, copy from old content. */ + if (entry->start > start) + memcpy(newcontents + start, oldcontents + start, +diff --git a/linux_spi.c b/linux_spi.c +index d12fceb..f0c6404 100644 +--- a/linux_spi.c ++++ b/linux_spi.c +@@ -60,7 +60,7 @@ static const struct spi_programmer spi_programmer_linux = { + int linux_spi_init(void) + { + char *p, *endp, *dev; +- uint32_t speed = 0; ++ uint32_t speed_hz = 0; + /* FIXME: make the following configurable by CLI options. */ + /* SPI mode 0 (beware this also includes: MSB first, CS active low and others */ + const uint8_t mode = SPI_MODE_0; +@@ -68,7 +68,7 @@ int linux_spi_init(void) + + p = extract_programmer_param("spispeed"); + if (p && strlen(p)) { +- speed = (uint32_t)strtoul(p, &endp, 10) * 1024; ++ speed_hz = (uint32_t)strtoul(p, &endp, 10) * 1000; + if (p == endp) { + msg_perr("%s: invalid clock: %s kHz\n", __func__, p); + free(p); +@@ -98,14 +98,14 @@ int linux_spi_init(void) + return 1; + /* We rely on the shutdown function for cleanup from here on. */ + +- if (speed > 0) { +- if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1) { ++ if (speed_hz > 0) { ++ if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed_hz) == -1) { + msg_perr("%s: failed to set speed to %d Hz: %s\n", +- __func__, speed, strerror(errno)); ++ __func__, speed_hz, strerror(errno)); + return 1; + } + +- msg_pdbg("Using %d kHz clock\n", speed); ++ msg_pdbg("Using %d kHz clock\n", speed_hz/1000); + } + + if (ioctl(fd, SPI_IOC_WR_MODE, &mode) == -1) { +diff --git a/mcp6x_spi.c b/mcp6x_spi.c +index ac40557..20e9bd8 100644 +--- a/mcp6x_spi.c ++++ b/mcp6x_spi.c +@@ -135,25 +135,20 @@ int mcp6x_spi_init(int want_spi) + + /* Accessing a NULL pointer BAR is evil. Don't do it. */ + if (!mcp6x_spibaraddr && want_spi) { +- msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR " +- "is invalid.\n"); ++ msg_perr("Error: Chipset is strapped for SPI, but MCP SPI BAR is invalid.\n"); + return 1; + } else if (!mcp6x_spibaraddr && !want_spi) { + msg_pdbg("MCP SPI is not used.\n"); + return 0; + } else if (mcp6x_spibaraddr && !want_spi) { +- msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently" +- " doesn't have SPI enabled.\n"); ++ msg_pdbg("Strange. MCP SPI BAR is valid, but chipset apparently doesn't have SPI enabled.\n"); + /* FIXME: Should we enable SPI anyway? */ + return 0; + } + /* Map the BAR. Bytewise/wordwise access at 0x530 and 0x540. */ +- mcp6x_spibar = physmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544); +- +-#if 0 +- /* FIXME: Run the physunmap in a shutdown function. */ +- physunmap(mcp6x_spibar, 0x544); +-#endif ++ mcp6x_spibar = rphysmap("NVIDIA MCP6x SPI", mcp6x_spibaraddr, 0x544); ++ if (mcp6x_spibar == ERROR_PTR) ++ return 1; + + status = mmio_readw(mcp6x_spibar + 0x530); + msg_pdbg("SPI control is 0x%04x, req=%i, gnt=%i\n", +diff --git a/nic3com.c b/nic3com.c +index 8d67b54..27e28c7 100644 +--- a/nic3com.c ++++ b/nic3com.c +@@ -96,6 +96,8 @@ int nic3com_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; + + id = dev->device_id; + +diff --git a/nicintel.c b/nicintel.c +index 56678e7..98ba29f 100644 +--- a/nicintel.c ++++ b/nicintel.c +@@ -59,13 +59,6 @@ static const struct par_programmer par_programmer_nicintel = { + .chip_writen = fallback_chip_writen, + }; + +-static int nicintel_shutdown(void *data) +-{ +- physunmap(nicintel_control_bar, NICINTEL_CONTROL_MEMMAP_SIZE); +- physunmap(nicintel_bar, NICINTEL_MEMMAP_SIZE); +- return 0; +-} +- + int nicintel_init(void) + { + struct pci_dev *dev = NULL; +@@ -83,18 +76,19 @@ int nicintel_init(void) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); +- nicintel_bar = physmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE); ++ if (!addr) ++ return 1; ++ ++ nicintel_bar = rphysmap("Intel NIC flash", addr, NICINTEL_MEMMAP_SIZE); + if (nicintel_bar == ERROR_PTR) +- goto error_out_unmap; ++ return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- /* FIXME: This is not an aligned mapping. Use 4k? */ +- nicintel_control_bar = physmap("Intel NIC control/status reg", +- addr, NICINTEL_CONTROL_MEMMAP_SIZE); +- if (nicintel_control_bar == ERROR_PTR) +- goto error_out; ++ if (!addr) ++ return 1; + +- if (register_shutdown(nicintel_shutdown, NULL)) ++ nicintel_control_bar = rphysmap("Intel NIC control/status reg", addr, NICINTEL_CONTROL_MEMMAP_SIZE); ++ if (nicintel_control_bar == ERROR_PTR) + return 1; + + /* FIXME: This register is pretty undocumented in all publicly available +@@ -112,11 +106,6 @@ int nicintel_init(void) + register_par_programmer(&par_programmer_nicintel, BUS_PARALLEL); + + return 0; +- +-error_out_unmap: +- physunmap(nicintel_bar, NICINTEL_MEMMAP_SIZE); +-error_out: +- return 1; + } + + static void nicintel_chip_writeb(const struct flashctx *flash, uint8_t val, +diff --git a/nicintel_spi.c b/nicintel_spi.c +index 0045c09..1522c9b 100644 +--- a/nicintel_spi.c ++++ b/nicintel_spi.c +@@ -19,10 +19,16 @@ + */ + + /* +- * Datasheet: ++ * Datasheets: + * PCI/PCI-X Family of Gigabit Ethernet Controllers Software Developer's Manual + * 82540EP/EM, 82541xx, 82544GC/EI, 82545GM/EM, 82546GB/EB, and 82547xx +- * http://download.intel.com/design/network/manuals/8254x_GBe_SDM.pdf ++ * http://www.intel.com/content/www/us/en/ethernet-controllers/pci-pci-x-family-gbe-controllers-software-dev-manual.html ++ * ++ * PCIe GbE Controllers Open Source Software Developer's Manual ++ * http://www.intel.com/content/www/us/en/ethernet-controllers/pcie-gbe-controllers-open-source-manual.html ++ * ++ * Intel 82574 Gigabit Ethernet Controller Family Datasheet ++ * http://www.intel.com/content/www/us/en/ethernet-controllers/82574l-gbe-controller-datasheet.html + */ + + #include +@@ -72,6 +78,7 @@ const struct dev_entry nics_intel_spi[] = { + {PCI_VENDOR_ID_INTEL, 0x1076, OK, "Intel", "82541GI Gigabit Ethernet Controller"}, + {PCI_VENDOR_ID_INTEL, 0x107c, OK, "Intel", "82541PI Gigabit Ethernet Controller"}, + {PCI_VENDOR_ID_INTEL, 0x10b9, OK, "Intel", "82572EI Gigabit Ethernet Controller"}, ++ {PCI_VENDOR_ID_INTEL, 0x10d3, OK, "Intel", "82574L Gigabit Ethernet Controller"}, + + {0}, + }; +@@ -151,16 +158,12 @@ static int nicintel_spi_shutdown(void *data) + { + uint32_t tmp; + +- /* Disable writes manually. See the comment about EECD in +- * nicintel_spi_init() for details. +- */ ++ /* Disable writes manually. See the comment about EECD in nicintel_spi_init() for details. */ + tmp = pci_mmio_readl(nicintel_spibar + EECD); + tmp &= ~FLASH_WRITES_ENABLED; + tmp |= FLASH_WRITES_DISABLED; + pci_mmio_writel(tmp, nicintel_spibar + EECD); + +- physunmap(nicintel_spibar, MEMMAP_SIZE); +- + return 0; + } + +@@ -177,8 +180,13 @@ int nicintel_spi_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- nicintel_spibar = physmap("Intel Gigabit NIC w/ SPI flash", +- io_base_addr, MEMMAP_SIZE); ++ if (!io_base_addr) ++ return 1; ++ ++ nicintel_spibar = rphysmap("Intel Gigabit NIC w/ SPI flash", io_base_addr, MEMMAP_SIZE); ++ if (nicintel_spibar == ERROR_PTR) ++ return 1; ++ + /* Automatic restore of EECD on shutdown is not possible because EECD + * does not only contain FLASH_WRITES_DISABLED|FLASH_WRITES_ENABLED, + * but other bits with side effects as well. Those other bits must be +diff --git a/nicnatsemi.c b/nicnatsemi.c +index d62a73f..cb8da6d 100644 +--- a/nicnatsemi.c ++++ b/nicnatsemi.c +@@ -64,6 +64,8 @@ int nicnatsemi_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; + + /* The datasheet shows address lines MA0-MA16 in one place and MA0-MA15 + * in another. My NIC has MA16 connected to A16 on the boot ROM socket +diff --git a/nicrealtek.c b/nicrealtek.c +index fb8e9e1..02fbd39 100644 +--- a/nicrealtek.c ++++ b/nicrealtek.c +@@ -69,6 +69,8 @@ int nicrealtek_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!io_base_addr) ++ return 1; + + /* Beware, this ignores the vendor ID! */ + switch (dev->device_id) { +diff --git a/ogp_spi.c b/ogp_spi.c +index 0c09d6a..23431d1 100644 +--- a/ogp_spi.c ++++ b/ogp_spi.c +@@ -97,12 +97,6 @@ static const struct bitbang_spi_master bitbang_spi_master_ogp = { + .half_period = 0, + }; + +-static int ogp_spi_shutdown(void *data) +-{ +- physunmap(ogp_spibar, 4096); +- return 0; +-} +- + int ogp_spi_init(void) + { + struct pci_dev *dev = NULL; +@@ -126,8 +120,10 @@ int ogp_spi_init(void) + ogp_reg_sck = OGA1_XP10_CPROM_SCK; + } else { + msg_perr("Invalid or missing rom= parameter.\n"); ++ free(type); + return 1; + } ++ free(type); + + if (rget_io_perms()) + return 1; +@@ -137,9 +133,11 @@ int ogp_spi_init(void) + return 1; + + io_base_addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- ogp_spibar = physmap("OGP registers", io_base_addr, 4096); ++ if (!io_base_addr) ++ return 1; + +- if (register_shutdown(ogp_spi_shutdown, NULL)) ++ ogp_spibar = rphysmap("OGP registers", io_base_addr, 4096); ++ if (ogp_spibar == ERROR_PTR) + return 1; + + if (bitbang_spi_init(&bitbang_spi_master_ogp)) +diff --git a/pcidev.c b/pcidev.c +index c7e9d78..3a3f77c 100644 +--- a/pcidev.c ++++ b/pcidev.c +@@ -94,7 +94,7 @@ uintptr_t pcidev_readbar(struct pci_dev *dev, int bar) + + supported_cycles = pci_read_word(dev, PCI_COMMAND); + +- msg_pdbg("Requested BAR is "); ++ msg_pdbg("Requested BAR is of type "); + switch (bartype) { + case TYPE_MEMBAR: + msg_pdbg("MEM"); +diff --git a/physmap.c b/physmap.c +index 932fe75..150c44a 100644 +--- a/physmap.c ++++ b/physmap.c +@@ -21,11 +21,13 @@ + */ + + #include ++#include + #include + #include + #include + #include + #include "flash.h" ++#include "programmer.h" + #include "hwaccess.h" + + #if !defined(__DJGPP__) && !defined(__LIBPAYLOAD__) +@@ -88,7 +90,7 @@ static void *sys_physmap(uintptr_t phys_addr, size_t len) + #define sys_physmap_rw_uncached sys_physmap + #define sys_physmap_ro_cached sys_physmap + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { + __dpmi_meminfo mi; + +@@ -117,7 +119,7 @@ void *sys_physmap(uintptr_t phys_addr, size_t len) + #define sys_physmap_rw_uncached sys_physmap + #define sys_physmap_ro_cached sys_physmap + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { + } + #elif defined(__MACH__) && defined(__APPLE__) +@@ -138,7 +140,7 @@ static void *sys_physmap(uintptr_t phys_addr, size_t len) + #define sys_physmap_rw_uncached sys_physmap + #define sys_physmap_ro_cached sys_physmap + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { + unmap_physical(virt_addr, len); + } +@@ -164,12 +166,11 @@ static void *sys_physmap_rw_uncached(uintptr_t phys_addr, size_t len) + /* Open the memory device UNCACHED. Important for MMIO. */ + if (-1 == (fd_mem = open(MEM_DEV, O_RDWR | O_SYNC))) { + msg_perr("Critical error: open(" MEM_DEV "): %s\n", strerror(errno)); +- exit(2); ++ return ERROR_PTR; + } + } + +- virt_addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, +- fd_mem, (off_t)phys_addr); ++ virt_addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd_mem, (off_t)phys_addr); + return MAP_FAILED == virt_addr ? ERROR_PTR : virt_addr; + } + +@@ -184,50 +185,77 @@ static void *sys_physmap_ro_cached(uintptr_t phys_addr, size_t len) + /* Open the memory device CACHED. */ + if (-1 == (fd_mem_cached = open(MEM_DEV, O_RDWR))) { + msg_perr("Critical error: open(" MEM_DEV "): %s\n", strerror(errno)); +- exit(2); ++ return ERROR_PTR; + } + } + +- virt_addr = mmap(NULL, len, PROT_READ, MAP_SHARED, +- fd_mem_cached, (off_t)phys_addr); ++ virt_addr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd_mem_cached, (off_t)phys_addr); + return MAP_FAILED == virt_addr ? ERROR_PTR : virt_addr; + } + +-void physunmap(void *virt_addr, size_t len) ++void sys_physunmap_unaligned(void *virt_addr, size_t len) + { +- if (len == 0) { +- msg_pspew("Not unmapping zero size at %p\n", virt_addr); +- return; +- } +- + munmap(virt_addr, len); + } + #endif + +-#define PHYSMAP_NOFAIL 0 +-#define PHYSMAP_MAYFAIL 1 +-#define PHYSMAP_RW 0 +-#define PHYSMAP_RO 1 ++#define PHYSM_RW 0 ++#define PHYSM_RO 1 ++#define PHYSM_NOCLEANUP 0 ++#define PHYSM_CLEANUP 1 ++#define PHYSM_EXACT 0 ++#define PHYSM_ROUND 1 ++ ++/* Round start to nearest page boundary below and set len so that the resulting address range ends at the lowest ++ * possible page boundary where the original address range is still entirely contained. It returns the ++ * difference between the rounded start address and the original start address. */ ++static uintptr_t round_to_page_boundaries(uintptr_t *start, size_t *len) ++{ ++ uintptr_t page_size = getpagesize(); ++ uintptr_t page_mask = ~(page_size-1); ++ uintptr_t end = *start + *len; ++ uintptr_t old_start = *start; ++ msg_gspew("page_size=%" PRIxPTR "\n", page_size); ++ msg_gspew("pre-rounding: start=0x%0*" PRIxPTR ", len=0x%zx, end=0x%0*" PRIxPTR "\n", ++ PRIxPTR_WIDTH, *start, *len, PRIxPTR_WIDTH, end); ++ *start = *start & page_mask; ++ end = (end + page_size - 1) & page_mask; ++ *len = end - *start; ++ msg_gspew("post-rounding: start=0x%0*" PRIxPTR ", len=0x%zx, end=0x%0*" PRIxPTR "\n", ++ PRIxPTR_WIDTH, *start, *len, PRIxPTR_WIDTH, *start + *len); ++ return old_start - *start; ++} ++ ++struct undo_physmap_data { ++ void *virt_addr; ++ size_t len; ++}; ++ ++static int undo_physmap(void *data) ++{ ++ if (data == NULL) { ++ msg_perr("%s: tried to physunmap without valid data!\n", __func__); ++ return 1; ++ } ++ struct undo_physmap_data *d = data; ++ physunmap_unaligned(d->virt_addr, d->len); ++ free(data); ++ return 0; ++} + +-static void *physmap_common(const char *descr, uintptr_t phys_addr, +- size_t len, int mayfail, int readonly) ++static void *physmap_common(const char *descr, uintptr_t phys_addr, size_t len, bool readonly, bool autocleanup, ++ bool round) + { + void *virt_addr; ++ uintptr_t offset = 0; + + if (len == 0) { + msg_pspew("Not mapping %s, zero size at 0x%0*" PRIxPTR ".\n", descr, PRIxPTR_WIDTH, phys_addr); + return ERROR_PTR; + } + +- if ((getpagesize() - 1) & len) { +- msg_perr("Mapping %s at 0x%0*" PRIxPTR ", unaligned size 0x%zx.\n", +- descr, PRIxPTR_WIDTH, phys_addr, len); +- } +- +- if ((getpagesize() - 1) & phys_addr) { +- msg_perr("Mapping %s, 0x%zx bytes at unaligned 0x%0*" PRIxPTR ".\n", +- descr, len, PRIxPTR_WIDTH, phys_addr); +- } ++ if (round) ++ offset = round_to_page_boundaries(&phys_addr, &len); + + if (readonly) + virt_addr = sys_physmap_ro_cached(phys_addr, len); +@@ -253,23 +281,89 @@ static void *physmap_common(const char *descr, uintptr_t phys_addr, + "and reboot, or reboot into\n" + "single user mode.\n"); + #endif +- if (!mayfail) +- exit(3); ++ return ERROR_PTR; + } + +- return virt_addr; ++ if (autocleanup) { ++ struct undo_physmap_data *d = malloc(sizeof(struct undo_physmap_data)); ++ if (d == NULL) { ++ msg_perr("%s: Out of memory!\n", __func__); ++ physunmap_unaligned(virt_addr, len); ++ return ERROR_PTR; ++ } ++ ++ d->virt_addr = virt_addr; ++ d->len = len; ++ if (register_shutdown(undo_physmap, d) != 0) { ++ msg_perr("%s: Could not register shutdown function!\n", __func__); ++ physunmap_unaligned(virt_addr, len); ++ return ERROR_PTR; ++ } ++ } ++ ++ return virt_addr + offset; ++} ++ ++void physunmap_unaligned(void *virt_addr, size_t len) ++{ ++ /* No need to check for zero size, such mappings would have yielded ERROR_PTR. */ ++ if (virt_addr == ERROR_PTR) { ++#ifndef FORCE10_SPI_CHANGE ++ msg_perr("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#else ++ msg_pdbg("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#endif ++ return; ++ } ++ ++ sys_physunmap_unaligned(virt_addr, len); ++} ++ ++void physunmap(void *virt_addr, size_t len) ++{ ++ uintptr_t tmp; ++ ++ /* No need to check for zero size, such mappings would have yielded ERROR_PTR. */ ++ if (virt_addr == ERROR_PTR) { ++#ifndef FORCE10_SPI_CHANGE ++ msg_perr("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#else ++ msg_pdbg("Trying to unmap a nonexisting mapping!\n" ++ "Please report a bug at flashrom@flashrom.org\n"); ++#endif ++ return; ++ } ++ tmp = (uintptr_t)virt_addr; ++ /* We assume that the virtual address of a page-aligned physical address is page-aligned as well. By ++ * extension, rounding a virtual unaligned address as returned by physmap should yield the same offset ++ * between rounded and original virtual address as between rounded and original physical address. ++ */ ++ round_to_page_boundaries(&tmp, &len); ++ virt_addr = (void *)tmp; ++ physunmap_unaligned(virt_addr, len); + } + + void *physmap(const char *descr, uintptr_t phys_addr, size_t len) + { +- return physmap_common(descr, phys_addr, len, PHYSMAP_NOFAIL, +- PHYSMAP_RW); ++ return physmap_common(descr, phys_addr, len, PHYSM_RW, PHYSM_NOCLEANUP, PHYSM_ROUND); ++} ++ ++void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len) ++{ ++ return physmap_common(descr, phys_addr, len, PHYSM_RW, PHYSM_CLEANUP, PHYSM_ROUND); ++} ++ ++void *physmap_ro(const char *descr, uintptr_t phys_addr, size_t len) ++{ ++ return physmap_common(descr, phys_addr, len, PHYSM_RO, PHYSM_NOCLEANUP, PHYSM_ROUND); + } + +-void *physmap_try_ro(const char *descr, uintptr_t phys_addr, size_t len) ++void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len) + { +- return physmap_common(descr, phys_addr, len, PHYSMAP_MAYFAIL, +- PHYSMAP_RO); ++ return physmap_common(descr, phys_addr, len, PHYSM_RO, PHYSM_NOCLEANUP, PHYSM_EXACT); + } + + /* MSR abstraction implementations for Linux, OpenBSD, FreeBSD/Dragonfly, OSX, libpayload +diff --git a/pony_spi.c b/pony_spi.c +index 101751f..2a3666f 100644 +--- a/pony_spi.c ++++ b/pony_spi.c +@@ -140,6 +140,7 @@ int pony_spi_init(void) + } else if (arg && !strlen(arg)) { + msg_perr("Error: Missing argument for programmer type.\n"); + free(arg); ++ return 1; + } else if (arg){ + msg_perr("Error: Invalid programmer type specified.\n"); + free(arg); +diff --git a/print.c b/print.c +index 6766eeb..6d2921b 100644 +--- a/print.c ++++ b/print.c +@@ -436,12 +436,13 @@ static void print_supported_boards_helper(const struct board_info *boards, + msg_ginfo("%s", b->name); + for (i = 0; i < maxboardlen - strlen(b->name); i++) + msg_ginfo(" "); +- if (b->working == OK) +- msg_ginfo("OK "); +- else if (b->working == NT) +- msg_ginfo("NT "); +- else +- msg_ginfo("BAD "); ++ ++ if (b->working == OK) ++ msg_ginfo("OK "); ++ else if (b->working == NT) ++ msg_ginfo("NT "); ++ else ++ msg_ginfo("BAD "); + + for (e = board_matches; e->vendor_name != NULL; e++) { + if (strcmp(e->vendor_name, b->vendor) +@@ -530,6 +531,7 @@ const struct board_info boards_known[] = { + B("abit", "AN-M2", OK, NULL, NULL), + B("abit", "AV8", OK, NULL, NULL), + B("abit", "AX8", OK, NULL, NULL), ++ B("abit", "BF6", OK, NULL, NULL), + B("abit", "BM6", OK, NULL, NULL), + B("abit", "Fatal1ty F-I90HD", OK, NULL, NULL), + B("abit", "IC7", OK, NULL, NULL), +@@ -695,6 +697,7 @@ const struct board_info boards_known[] = { + B("ASUS", "P5L-VM 1394", OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LVM_1394/", NULL), + B("ASUS", "P5LD2", NT, NULL, "Untested board enable."), + B("ASUS", "P5LD2-VM", NT, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM/", "Untested board enable."), ++ B("ASUS", "P5LD2-VM DH", OK, "http://www.asus.com/Motherboards/Intel_Socket_775/P5LD2VM_DH/", NULL), + B("ASUS", "P5LP-LE (Lithium-UL8E)", OK, "http://h10025.www1.hp.com/ewfrf/wc/document?docname=c00379616&tmp_task=prodinfoCategory&cc=us&dlc=en&lc=en&product=1159887", "This is an OEM board from HP."), + B("ASUS", "P5LP-LE (Epson OEM)", OK, NULL, "This is an OEM board from Epson (e.g. Endeavor MT7700)."), + B("ASUS", "P5LP-LE", NT, NULL, "This designation is used for OEM boards from HP, Epson and maybe others. The HP names vary and not all of them have been tested yet. Please report any success or failure, thanks."), +diff --git a/programmer.h b/programmer.h +index 4db8d58..d3cc557 100644 +--- a/programmer.h ++++ b/programmer.h +@@ -276,8 +276,11 @@ int processor_flash_enable(void); + + /* physmap.c */ + void *physmap(const char *descr, uintptr_t phys_addr, size_t len); +-void *physmap_try_ro(const char *descr, uintptr_t phys_addr, size_t len); ++void *rphysmap(const char *descr, uintptr_t phys_addr, size_t len); ++void *physmap_ro(const char *descr, uintptr_t phys_addr, size_t len); ++void *physmap_ro_unaligned(const char *descr, uintptr_t phys_addr, size_t len); + void physunmap(void *virt_addr, size_t len); ++void physunmap_unaligned(void *virt_addr, size_t len); + #if CONFIG_INTERNAL == 1 + int setup_cpu_msr(int cpu); + void cleanup_cpu_msr(void); +@@ -287,9 +290,11 @@ int cb_parse_table(const char **vendor, const char **model); + int cb_check_image(uint8_t *bios, int size); + + /* dmi.c */ ++#if defined(__i386__) || defined(__x86_64__) + extern int has_dmi_support; + void dmi_init(void); + int dmi_match(const char *pattern); ++#endif // defined(__i386__) || defined(__x86_64__) + + /* internal.c */ + struct superio { +@@ -550,10 +555,19 @@ int default_spi_write_256(struct flashctx *flash, uint8_t *buf, unsigned int sta + int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int start, unsigned int len); + int register_spi_programmer(const struct spi_programmer *programmer); + +-/* The following enum is needed by ich_descriptor_tool and ich* code. */ ++/* The following enum is needed by ich_descriptor_tool and ich* code as well as in chipset_enable.c. */ + enum ich_chipset { + CHIPSET_ICH_UNKNOWN, +- CHIPSET_ICH7 = 7, ++#ifdef DELL_AVOTON_SUPPORT ++ CHIPSET_AVOTON, ++#endif ++ CHIPSET_ICH, ++ CHIPSET_ICH2345, ++ CHIPSET_ICH6, ++ CHIPSET_POULSBO, /* SCH U* */ ++ CHIPSET_TUNNEL_CREEK, /* Atom E6xx */ ++ CHIPSET_CENTERTON, /* Atom S1220 S1240 S1260 */ ++ CHIPSET_ICH7, + CHIPSET_ICH8, + CHIPSET_ICH9, + CHIPSET_ICH10, +@@ -563,13 +577,15 @@ enum ich_chipset { + CHIPSET_8_SERIES_LYNX_POINT, + CHIPSET_8_SERIES_LYNX_POINT_LP, + CHIPSET_8_SERIES_WELLSBURG, ++#if DELL_DENVERTON_SUPPORT == 1 ++ CHIPSET_DENVERTON, ++#endif /* #if DELL_DENVERTON_SUPPORT == 1 */ + }; + + /* ichspi.c */ + #if CONFIG_INTERNAL == 1 + extern uint32_t ichspi_bbar; +-int ich_init_spi(struct pci_dev *dev, uint32_t base, void *rcrb, +- enum ich_chipset ich_generation); ++int ich_init_spi(struct pci_dev *dev, void *spibar, enum ich_chipset ich_generation); + int via_init_spi(struct pci_dev *dev, uint32_t mmio_base); + + /* amd_imc.c */ +@@ -659,7 +675,7 @@ typedef int fdtype; + + void sp_flush_incoming(void); + fdtype sp_openserport(char *dev, unsigned int baud); +-void __attribute__((noreturn)) sp_die(char *msg); ++int serialport_config(fdtype fd, unsigned int baud); + extern fdtype sp_fd; + /* expose serialport_shutdown as it's currently used by buspirate */ + int serialport_shutdown(void *data); +diff --git a/rayer_spi.c b/rayer_spi.c +index b312610..189341a 100644 +--- a/rayer_spi.c ++++ b/rayer_spi.c +@@ -17,11 +17,9 @@ + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +-/* Driver for the SPIPGM hardware by "RayeR" Martin Rehak. +- * See http://rayer.ic.cz/elektro/spipgm.htm for schematics and instructions. +- */ +- +-/* This driver uses non-portable direct I/O port accesses which won't work on ++/* Driver for various LPT adapters. ++ * ++ * This driver uses non-portable direct I/O port accesses which won't work on + * any non-x86 platform, and even on x86 there is a high chance there will be + * collisions with any loaded parallel port drivers. + * The big advantage of direct port I/O is OS independence and speed because +@@ -37,21 +35,87 @@ + #include "programmer.h" + #include "hwaccess.h" + +-enum rayer_type { +- TYPE_RAYER, +- TYPE_XILINX_DLC5, +-}; +- + /* We have two sets of pins, out and in. The numbers for both sets are + * independent and are bitshift values, not real pin numbers. + * Default settings are for the RayeR hardware. + */ +-/* Pins for master->slave direction */ +-static int rayer_cs_bit = 5; +-static int rayer_sck_bit = 6; +-static int rayer_mosi_bit = 7; +-/* Pins for slave->master direction */ +-static int rayer_miso_bit = 6; ++ ++struct rayer_programmer { ++ const char *type; ++ const enum test_state status; ++ const char *description; ++ const void *dev_data; ++}; ++ ++struct rayer_pinout { ++ uint8_t cs_bit; ++ uint8_t sck_bit; ++ uint8_t mosi_bit; ++ uint8_t miso_bit; ++ void (*preinit)(const void *); ++ int (*shutdown)(void *); ++}; ++ ++static const struct rayer_pinout rayer_spipgm = { ++ .cs_bit = 5, ++ .sck_bit = 6, ++ .mosi_bit = 7, ++ .miso_bit = 6, ++}; ++ ++static void dlc5_preinit(const void *); ++static int dlc5_shutdown(void *); ++ ++static const struct rayer_pinout xilinx_dlc5 = { ++ .cs_bit = 2, ++ .sck_bit = 1, ++ .mosi_bit = 0, ++ .miso_bit = 4, ++ .preinit = dlc5_preinit, ++ .shutdown = dlc5_shutdown, ++}; ++ ++static void byteblaster_preinit(const void *); ++static int byteblaster_shutdown(void *); ++ ++static const struct rayer_pinout altera_byteblastermv = { ++ .cs_bit = 1, ++ .sck_bit = 0, ++ .mosi_bit = 6, ++ .miso_bit = 7, ++ .preinit = byteblaster_preinit, ++ .shutdown = byteblaster_shutdown, ++}; ++ ++static void stk200_preinit(const void *); ++static int stk200_shutdown(void *); ++ ++static const struct rayer_pinout atmel_stk200 = { ++ .cs_bit = 7, ++ .sck_bit = 4, ++ .mosi_bit = 5, ++ .miso_bit = 6, ++ .preinit = stk200_preinit, ++ .shutdown = stk200_shutdown, ++}; ++ ++static const struct rayer_pinout wiggler_lpt = { ++ .cs_bit = 1, ++ .sck_bit = 2, ++ .mosi_bit = 3, ++ .miso_bit = 7, ++}; ++ ++static const struct rayer_programmer rayer_spi_types[] = { ++ {"rayer", NT, "RayeR SPIPGM", &rayer_spipgm}, ++ {"xilinx", NT, "Xilinx Parallel Cable III (DLC 5)", &xilinx_dlc5}, ++ {"byteblastermv", OK, "Altera ByteBlasterMV", &altera_byteblastermv}, ++ {"stk200", NT, "Atmel STK200/300 adapter", &atmel_stk200}, ++ {"wiggler", OK, "Wiggler LPT", &wiggler_lpt}, ++ {0}, ++}; ++ ++static const struct rayer_pinout *pinout = NULL; + + static uint16_t lpt_iobase; + +@@ -60,22 +124,22 @@ static uint8_t lpt_outbyte; + + static void rayer_bitbang_set_cs(int val) + { +- lpt_outbyte &= ~(1 << rayer_cs_bit); +- lpt_outbyte |= (val << rayer_cs_bit); ++ lpt_outbyte &= ~(1 << pinout->cs_bit); ++ lpt_outbyte |= (val << pinout->cs_bit); + OUTB(lpt_outbyte, lpt_iobase); + } + + static void rayer_bitbang_set_sck(int val) + { +- lpt_outbyte &= ~(1 << rayer_sck_bit); +- lpt_outbyte |= (val << rayer_sck_bit); ++ lpt_outbyte &= ~(1 << pinout->sck_bit); ++ lpt_outbyte |= (val << pinout->sck_bit); + OUTB(lpt_outbyte, lpt_iobase); + } + + static void rayer_bitbang_set_mosi(int val) + { +- lpt_outbyte &= ~(1 << rayer_mosi_bit); +- lpt_outbyte |= (val << rayer_mosi_bit); ++ lpt_outbyte &= ~(1 << pinout->mosi_bit); ++ lpt_outbyte |= (val << pinout->mosi_bit); + OUTB(lpt_outbyte, lpt_iobase); + } + +@@ -83,8 +147,8 @@ static int rayer_bitbang_get_miso(void) + { + uint8_t tmp; + +- tmp = INB(lpt_iobase + 1); +- tmp = (tmp >> rayer_miso_bit) & 0x1; ++ tmp = INB(lpt_iobase + 1) ^ 0x80; // bit.7 inverted ++ tmp = (tmp >> pinout->miso_bit) & 0x1; + return tmp; + } + +@@ -99,8 +163,8 @@ static const struct bitbang_spi_master bitbang_spi_master_rayer = { + + int rayer_spi_init(void) + { ++ const struct rayer_programmer *prog = rayer_spi_types; + char *arg = NULL; +- enum rayer_type rayer_type = TYPE_RAYER; + + /* Non-default port requested? */ + arg = extract_programmer_param("iobase"); +@@ -138,36 +202,20 @@ int rayer_spi_init(void) + + arg = extract_programmer_param("type"); + if (arg) { +- if (!strcasecmp(arg, "rayer")) { +- rayer_type = TYPE_RAYER; +- } else if (!strcasecmp(arg, "xilinx")) { +- rayer_type = TYPE_XILINX_DLC5; +- } else { ++ for (; prog->type != NULL; prog++) { ++ if (strcasecmp(arg, prog->type) == 0) { ++ break; ++ } ++ } ++ if (prog->type == NULL) { + msg_perr("Error: Invalid device type specified.\n"); + free(arg); + return 1; + } ++ free(arg); + } +- free(arg); +- switch (rayer_type) { +- case TYPE_RAYER: +- msg_pdbg("Using RayeR SPIPGM pinout.\n"); +- /* Bits for master->slave direction */ +- rayer_cs_bit = 5; +- rayer_sck_bit = 6; +- rayer_mosi_bit = 7; +- /* Bits for slave->master direction */ +- rayer_miso_bit = 6; +- break; +- case TYPE_XILINX_DLC5: +- msg_pdbg("Using Xilinx Parallel Cable III (DLC 5) pinout.\n"); +- /* Bits for master->slave direction */ +- rayer_cs_bit = 2; +- rayer_sck_bit = 1; +- rayer_mosi_bit = 0; +- /* Bits for slave->master direction */ +- rayer_miso_bit = 4; +- } ++ msg_pinfo("Using %s pinout.\n", prog->description); ++ pinout = (struct rayer_pinout *)prog->dev_data; + + if (rget_io_perms()) + return 1; +@@ -175,12 +223,60 @@ int rayer_spi_init(void) + /* Get the initial value before writing to any line. */ + lpt_outbyte = INB(lpt_iobase); + ++ if (pinout->shutdown) ++ register_shutdown(pinout->shutdown, (void*)pinout); ++ if (pinout->preinit) ++ pinout->preinit(pinout); ++ + if (bitbang_spi_init(&bitbang_spi_master_rayer)) + return 1; + + return 0; + } + ++static void byteblaster_preinit(const void *data){ ++ msg_pdbg("byteblaster_preinit\n"); ++ /* Assert #EN signal. */ ++ OUTB(2, lpt_iobase + 2 ); ++} ++ ++static int byteblaster_shutdown(void *data){ ++ msg_pdbg("byteblaster_shutdown\n"); ++ /* De-Assert #EN signal. */ ++ OUTB(0, lpt_iobase + 2 ); ++ return 0; ++} ++ ++static void stk200_preinit(const void *data) { ++ msg_pdbg("stk200_init\n"); ++ /* Assert #EN signals, set LED signal. */ ++ lpt_outbyte = (1 << 6) ; ++ OUTB(lpt_outbyte, lpt_iobase); ++} ++ ++static int stk200_shutdown(void *data) { ++ msg_pdbg("stk200_shutdown\n"); ++ /* Assert #EN signals, clear LED signal. */ ++ lpt_outbyte = (1 << 2) | (1 << 3); ++ OUTB(lpt_outbyte, lpt_iobase); ++ return 0; ++} ++ ++static void dlc5_preinit(const void *data) { ++ msg_pdbg("dlc5_preinit\n"); ++ /* Assert pin 6 to receive MISO. */ ++ lpt_outbyte |= (1<<4); ++ OUTB(lpt_outbyte, lpt_iobase); ++} ++ ++static int dlc5_shutdown(void *data) { ++ msg_pdbg("dlc5_shutdown\n"); ++ /* De-assert pin 6 to force MISO low. */ ++ lpt_outbyte &= ~(1<<4); ++ OUTB(lpt_outbyte, lpt_iobase); ++ return 0; ++} ++ + #else + #error PCI port I/O access is not supported on this architecture yet. + #endif +diff --git a/satamv.c b/satamv.c +index c3f27e7..e03508e 100644 +--- a/satamv.c ++++ b/satamv.c +@@ -57,12 +57,6 @@ static const struct par_programmer par_programmer_satamv = { + .chip_writen = fallback_chip_writen, + }; + +-static int satamv_shutdown(void *data) +-{ +- physunmap(mv_bar, 0x20000); +- return 0; +-} +- + /* + * Random notes: + * FCE# Flash Chip Enable +@@ -94,11 +88,11 @@ int satamv_init(void) + return 1; + + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); +- mv_bar = physmap("Marvell 88SX7042 registers", addr, 0x20000); +- if (mv_bar == ERROR_PTR) ++ if (!addr) + return 1; + +- if (register_shutdown(satamv_shutdown, NULL)) ++ mv_bar = rphysmap("Marvell 88SX7042 registers", addr, 0x20000); ++ if (mv_bar == ERROR_PTR) + return 1; + + tmp = pci_mmio_readl(mv_bar + FLASH_PARAM); +@@ -144,12 +138,15 @@ int satamv_init(void) + pci_rmmio_writel(tmp, mv_bar + GPIO_PORT_CONTROL); + + /* Get I/O BAR location. */ +- tmp = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); ++ addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_2); ++ if (!addr) ++ return 1; ++ + /* Truncate to reachable range. + * FIXME: Check if the I/O BAR is actually reachable. + * This is an arch specific check. + */ +- mv_iobar = tmp & 0xffff; ++ mv_iobar = addr & 0xffff; + msg_pspew("Activating I/O BAR at 0x%04x\n", mv_iobar); + + /* 512 kByte with two 8-bit latches, and +diff --git a/satasii.c b/satasii.c +index 72e35e5..83dc62c 100644 +--- a/satasii.c ++++ b/satasii.c +@@ -54,12 +54,6 @@ static const struct par_programmer par_programmer_satasii = { + .chip_writen = fallback_chip_writen, + }; + +-static int satasii_shutdown(void *data) +-{ +- physunmap(sii_bar, SATASII_MEMMAP_SIZE); +- return 0; +-} +- + static uint32_t satasii_wait_done(void) + { + uint32_t ctrl_reg; +@@ -91,21 +85,25 @@ int satasii_init(void) + + if ((id == 0x3132) || (id == 0x3124)) { + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_0); ++ if (!addr) ++ return 1; + reg_offset = 0x70; + } else { + addr = pcidev_readbar(dev, PCI_BASE_ADDRESS_5); ++ if (!addr) ++ return 1; + reg_offset = 0x50; + } + +- sii_bar = physmap("SATA SiI registers", addr, SATASII_MEMMAP_SIZE) + reg_offset; ++ sii_bar = rphysmap("SATA SiI registers", addr, SATASII_MEMMAP_SIZE); ++ if (sii_bar == ERROR_PTR) ++ return 1; ++ sii_bar += reg_offset; + + /* Check if ROM cycle are OK. */ + if ((id != 0x0680) && (!(pci_mmio_readl(sii_bar) & (1 << 26)))) + msg_pwarn("Warning: Flash seems unconnected.\n"); + +- if (register_shutdown(satasii_shutdown, NULL)) +- return 1; +- + register_par_programmer(&par_programmer_satasii, BUS_PARALLEL); + + return 0; +diff --git a/sb600spi.c b/sb600spi.c +index cb7c4ac..9523591 100644 +--- a/sb600spi.c ++++ b/sb600spi.c +@@ -57,7 +57,28 @@ static enum amd_chipset amd_gen = CHIPSET_AMD_UNKNOWN; + static void determine_generation(struct pci_dev *dev) + { + amd_gen = CHIPSET_AMD_UNKNOWN; +- if (dev->device_id == 0x780e) { ++ msg_pdbg2("Trying to determine the generation of the SPI interface... "); ++ if (dev->device_id == 0x438d) { ++ amd_gen = CHIPSET_SB6XX; ++ msg_pdbg("SB6xx detected.\n"); ++ } else if (dev->device_id == 0x439d) { ++ struct pci_dev *smbus_dev = pci_dev_find(0x1002, 0x4385); ++ if (smbus_dev == NULL) ++ return; ++ uint8_t rev = pci_read_byte(smbus_dev, PCI_REVISION_ID); ++ if (rev >= 0x39 && rev <= 0x3D) { ++ amd_gen = CHIPSET_SB7XX; ++ msg_pdbg("SB7xx/SP5100 detected.\n"); ++ } else if (rev >= 0x40 && rev <= 0x42) { ++ amd_gen = CHIPSET_SB89XX; ++ msg_pdbg("SB8xx/SB9xx/Hudson-1 detected.\n"); ++ } else { ++ msg_pwarn("SB device found but SMBus revision 0x%02x does not match known values.\n" ++ "Assuming SB8xx/SB9xx/Hudson-1. Please send a log to flashrom@flashrom.org\n", ++ rev); ++ amd_gen = CHIPSET_SB89XX; ++ } ++ } else if (dev->device_id == 0x780e) { + /* The PCI ID of the LPC bridge doesn't change between Hudson-2/3/4 and Yangtze (Kabini/Temash) + * although they use different SPI interfaces. */ + #ifdef USE_YANGTZE_HEURISTICS +@@ -94,7 +115,11 @@ static void determine_generation(struct pci_dev *dev) + "the output of lspci -nnvx, thanks!.\n", rev); + } + #endif +- } ++ } else ++ msg_pwarn("%s: Unknown LPC device %" PRIx16 ":%" PRIx16 ".\n" ++ "Please report this to flashrom@flashrom.org and include this log and\n" ++ "the output of lspci -nnvx, thanks!\n", ++ __func__, dev->vendor_id, dev->device_id); + } + + static void reset_internal_fifo_pointer(void) +@@ -247,10 +272,66 @@ static int sb600_spi_send_command(struct flashctx *flash, unsigned int writecnt, + return 0; + } + ++struct spispeed { ++ const char *const name; ++ const uint8_t speed; ++}; ++ ++static const struct spispeed spispeeds[] = { ++ { "66 MHz", 0x00 }, ++ { "33 MHz", 0x01 }, ++ { "22 MHz", 0x02 }, ++ { "16.5 MHz", 0x03 }, ++}; ++ ++static int set_speed(struct pci_dev *dev, const struct spispeed *spispeed) ++{ ++ bool success = false; ++ uint8_t speed = spispeed->speed; ++ ++ msg_pdbg("Setting SPI clock to %s (0x%x).\n", spispeed->name, speed); ++ if (amd_gen != CHIPSET_YANGTZE) { ++ rmmio_writeb((mmio_readb(sb600_spibar + 0xd) & ~(0x3 << 4)) | (speed << 4), sb600_spibar + 0xd); ++ success = (speed == ((mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3)); ++ } ++ ++ if (!success) { ++ msg_perr("Setting SPI clock failed.\n"); ++ return 1; ++ } ++ return 0; ++} ++ ++static int handle_speed(struct pci_dev *dev) ++{ ++ uint32_t tmp; ++ int8_t spispeed_idx = 3; /* Default to 16.5 MHz */ ++ ++ /* See the chipset support matrix for SPI Base_Addr below for an explanation of the symbols used. ++ * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson234 yangtze ++ * 18 rsvd <- fastReadEnable ? <- ? SpiReadMode[0] ++ * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1] ++ */ ++ if (amd_gen != CHIPSET_YANGTZE) { ++ if (amd_gen >= CHIPSET_SB89XX && amd_gen <= CHIPSET_HUDSON234) { ++ bool fast_read = (mmio_readl(sb600_spibar + 0x00) >> 18) & 0x1; ++ msg_pdbg("Fast Reads are %sabled\n", fast_read ? "en" : "dis"); ++ if (fast_read) { ++ msg_pdbg("Disabling them temporarily.\n"); ++ rmmio_writel(mmio_readl(sb600_spibar + 0x00) & ~(0x1 << 18), ++ sb600_spibar + 0x00); ++ } ++ } ++ tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3; ++ msg_pdbg("NormSpeed is %s\n", spispeeds[tmp].name); ++ } ++ return set_speed(dev, &spispeeds[spispeed_idx]); ++} ++ + static int sb600_handle_imc(struct pci_dev *dev, bool amd_imc_force) + { + /* Handle IMC everywhere but sb600 which does not have one. */ +- if (dev->device_id == 0x438d) ++ if (amd_gen == CHIPSET_SB6XX) + return 0; + + /* TODO: we should not only look at IntegratedImcPresent (LPC Dev 20, Func 3, 40h) but also at +@@ -297,9 +378,6 @@ int sb600_probe_spi(struct pci_dev *dev) + uint32_t tmp; + uint8_t reg; + bool amd_imc_force = false; +- static const char *const speed_names[4] = { +- "66/reserved", "33", "22", "16.5" +- }; + + char *arg = extract_programmer_param("amd_imc_force"); + if (arg && !strcmp(arg, "yes")) { +@@ -326,14 +404,20 @@ int sb600_probe_spi(struct pci_dev *dev) + return 0; + + /* Physical memory has to be mapped at page (4k) boundaries. */ +- sb600_spibar = physmap("SB600 SPI registers", tmp & 0xfffff000, +- 0x1000); ++ sb600_spibar = rphysmap("SB600 SPI registers", tmp & 0xfffff000, 0x1000); ++ if (sb600_spibar == ERROR_PTR) ++ return ERROR_FATAL; ++ + /* The low bits of the SPI base address are used as offset into + * the mapped page. + */ + sb600_spibar += tmp & 0xfff; + + determine_generation(dev); ++ if (amd_gen == CHIPSET_AMD_UNKNOWN) { ++ msg_perr("Could not determine chipset generation."); ++ return ERROR_NONFATAL; ++ } + + if (amd_gen == CHIPSET_YANGTZE) { + msg_perr("SPI on Kabini/Temash and newer chipsets are not yet supported.\n" +@@ -341,34 +425,87 @@ int sb600_probe_spi(struct pci_dev *dev) + return ERROR_NONFATAL; + } + +- tmp = pci_read_long(dev, 0xa0); +- msg_pdbg("AltSpiCSEnable=%i, SpiRomEnable=%i, " +- "AbortEnable=%i\n", tmp & 0x1, (tmp & 0x2) >> 1, +- (tmp & 0x4) >> 2); +- tmp = (pci_read_byte(dev, 0xba) & 0x4) >> 2; +- msg_pdbg("PrefetchEnSPIFromIMC=%i, ", tmp); +- +- tmp = pci_read_byte(dev, 0xbb); +- /* FIXME: Set bit 3,6,7 if not already set. +- * Set bit 5, otherwise SPI accesses are pointless in LPC mode. +- * See doc 42413 AMD SB700/710/750 RPR. ++ /* How to read the following table and similar ones in this file: ++ * "?" means we have no datasheet for this chipset generation or it doesn't have any relevant info. ++ * "<-" means the bit/register meaning is identical to the next non-"?" chipset to the left. "<-" thus ++ * never refers to another "?". ++ * If a "?" chipset is between two chipsets with identical meaning, we assume the meaning didn't change ++ * twice in between, i.e. the meaning is unchanged for the "?" chipset. Usually we assume that ++ * succeeding hardware supports the same functionality as its predecessor unless proven different by ++ * tests or documentation, hence "?" will often be implemented equally to "<-". ++ * ++ * Chipset support matrix for SPI Base_Addr (LPC PCI reg 0xa0) ++ * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze ++ * 3 rsvd <- <- ? <- ? RouteTpm2Spi ++ * 2 rsvd AbortEnable rsvd ? <- ? <- ++ * 1 rsvd SpiRomEnable <- ? <- ? <- ++ * 0 rsvd AltSpiCSEnable rsvd ? <- ? <- + */ +- msg_pdbg("PrefetchEnSPIFromHost=%i, SpiOpEnInLpcMode=%i\n", +- tmp & 0x1, (tmp & 0x20) >> 5); +- tmp = mmio_readl(sb600_spibar); +- /* FIXME: If SpiAccessMacRomEn or SpiHostAccessRomEn are zero on +- * SB700 or later, reads and writes will be corrupted. Abort in this +- * case. Make sure to avoid this check on SB600. ++ if (amd_gen >= CHIPSET_SB7XX) { ++ tmp = pci_read_long(dev, 0xa0); ++ msg_pdbg("SpiRomEnable=%i", (tmp >> 1) & 0x1); ++ if (amd_gen == CHIPSET_SB7XX) ++ msg_pdbg(", AltSpiCSEnable=%i, AbortEnable=%i", tmp & 0x1, (tmp >> 2) & 0x1); ++ ++ tmp = pci_read_byte(dev, 0xba); ++ msg_pdbg(", PrefetchEnSPIFromIMC=%i", (tmp & 0x4) >> 2); ++ ++ tmp = pci_read_byte(dev, 0xbb); ++ /* FIXME: Set bit 3,6,7 if not already set. ++ * Set bit 5, otherwise SPI accesses are pointless in LPC mode. ++ * See doc 42413 AMD SB700/710/750 RPR. ++ */ ++ if (amd_gen == CHIPSET_SB7XX) ++ msg_pdbg(", SpiOpEnInLpcMode=%i", (tmp >> 5) & 0x1); ++ msg_pdbg(", PrefetchEnSPIFromHost=%i\n", tmp & 0x1); ++ } ++ ++ /* Chipset support matrix for SPI_Cntrl0 (spibar + 0x0) ++ * See the chipset support matrix for SPI Base_Addr above for an explanation of the symbols used. ++ * bit 6xx 7xx/SP5100 8xx 9xx hudson1 hudson2+ yangtze ++ * 17 rsvd <- <- ? <- ? <- ++ * 18 rsvd <- fastReadEnable<1> ? <- ? SpiReadMode[0]<1> ++ * 19 SpiArbEnable <- <- ? <- ? <- ++ * 20 (FifoPtrClr) <- <- ? <- ? <- ++ * 21 (FifoPtrInc) <- <- ? <- ? IllegalAccess ++ * 22 SpiAccessMacRomEn <- <- ? <- ? <- ++ * 23 SpiHostAccessRomEn <- <- ? <- ? <- ++ * 24:26 ArbWaitCount <- <- ? <- ? <- ++ * 27 SpiBridgeDisable <- <- ? <- ? rsvd ++ * 28 rsvd DropOneClkOnRd = SPIClkGate ? <- ? <- ++ * 29:30 rsvd <- <- ? <- ? SpiReadMode[2:1]<1> ++ * 31 rsvd <- SpiBusy ? <- ? <- ++ * ++ * <1> see handle_speed + */ +- msg_pdbg("(0x%08" PRIx32 ") fastReadEnable=%u, SpiArbEnable=%i, SpiAccessMacRomEn=%i, " +- "SpiHostAccessRomEn=%i, ArbWaitCount=%i, " +- "SpiBridgeDisable=%i, DropOneClkOnRd=%i\n", +- tmp, (tmp >> 18) & 0x1, +- (tmp >> 19) & 0x1, (tmp >> 22) & 0x1, +- (tmp >> 23) & 0x1, (tmp >> 24) & 0x7, +- (tmp >> 27) & 0x1, (tmp >> 28) & 0x1); +- tmp = (mmio_readb(sb600_spibar + 0xd) >> 4) & 0x3; +- msg_pdbg("NormSpeed is %s MHz\n", speed_names[tmp]); ++ tmp = mmio_readl(sb600_spibar + 0x00); ++ msg_pdbg("(0x%08" PRIx32 ") SpiArbEnable=%i", tmp, (tmp >> 19) & 0x1); ++ ++ msg_pdbg(", SpiAccessMacRomEn=%i, SpiHostAccessRomEn=%i, ArbWaitCount=%i", ++ (tmp >> 22) & 0x1, (tmp >> 23) & 0x1, (tmp >> 24) & 0x7); ++ ++ if (amd_gen != CHIPSET_YANGTZE) ++ msg_pdbg(", SpiBridgeDisable=%i", (tmp >> 27) & 0x1); ++ ++ switch (amd_gen) { ++ case CHIPSET_SB7XX: ++ msg_pdbg(", DropOneClkOnRd/SpiClkGate=%i", (tmp >> 28) & 0x1); ++ case CHIPSET_SB89XX: ++ case CHIPSET_HUDSON234: ++ msg_pdbg(", SpiBusy=%i", (tmp >> 31) & 0x1); ++ default: break; ++ } ++ msg_pdbg("\n"); ++ ++ if (((tmp >> 22) & 0x1) == 0 || ((tmp >> 23) & 0x1) == 0) { ++ msg_perr("ERROR: State of SpiAccessMacRomEn or SpiHostAccessRomEn prohibits full access.\n"); ++ return ERROR_NONFATAL; ++ } ++ ++ if (amd_gen >= CHIPSET_SB89XX) { ++ tmp = mmio_readb(sb600_spibar + 0x1D); ++ msg_pdbg("Using SPI_CS%d\n", tmp & 0x3); ++ } + + /* Look for the SMBus device. */ + smbus_dev = pci_dev_find(0x1002, 0x4385); +@@ -409,6 +546,9 @@ int sb600_probe_spi(struct pci_dev *dev) + return 0; + } + ++ if (handle_speed(dev) != 0) ++ return ERROR_FATAL; ++ + if (sb600_handle_imc(dev, amd_imc_force) != 0) + return ERROR_FATAL; + +diff --git a/serial.c b/serial.c +index 1b394cd..126079a 100644 +--- a/serial.c ++++ b/serial.c +@@ -41,12 +41,6 @@ + + fdtype sp_fd = SER_INV_FD; + +-void __attribute__((noreturn)) sp_die(char *msg) +-{ +- perror(msg); +- exit(1); +-} +- + #ifdef _WIN32 + struct baudentry { + DWORD flag; +@@ -158,35 +152,18 @@ static void msg_perr_strerror(const char *msg) + #endif + } + +-fdtype sp_openserport(char *dev, unsigned int baud) ++int serialport_config(fdtype fd, unsigned int baud) + { +-#ifdef _WIN32 +- HANDLE fd; +- char *dev2 = dev; +- if ((strlen(dev) > 3) && +- (tolower((unsigned char)dev[0]) == 'c') && +- (tolower((unsigned char)dev[1]) == 'o') && +- (tolower((unsigned char)dev[2]) == 'm')) { +- dev2 = malloc(strlen(dev) + 5); +- if (!dev2) { +- msg_perr_strerror("Out of memory: "); +- return SER_INV_FD; +- } +- strcpy(dev2, "\\\\.\\"); +- strcpy(dev2 + 4, dev); +- } +- fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL, +- OPEN_EXISTING, 0, NULL); +- if (dev2 != dev) +- free(dev2); +- if (fd == INVALID_HANDLE_VALUE) { +- msg_perr_strerror("Cannot open serial port: "); +- return SER_INV_FD; ++ if (fd == SER_INV_FD) { ++ msg_perr("%s: File descriptor is invalid.\n", __func__); ++ return 1; + } ++ ++#ifdef _WIN32 + DCB dcb; + if (!GetCommState(fd, &dcb)) { + msg_perr_strerror("Could not fetch original serial port configuration: "); +- goto out_close; ++ return 1; + } + const struct baudentry *entry = round_baud(baud); + dcb.BaudRate = entry->flag; +@@ -195,35 +172,25 @@ fdtype sp_openserport(char *dev, unsigned int baud) + dcb.StopBits = ONESTOPBIT; + if (!SetCommState(fd, &dcb)) { + msg_perr_strerror("Could not change serial port configuration: "); +- goto out_close; ++ return 1; + } + if (!GetCommState(fd, &dcb)) { + msg_perr_strerror("Could not fetch new serial port configuration: "); +- goto out_close; ++ return 1; + } + msg_pdbg("Baud rate is %ld.\n", dcb.BaudRate); +- return fd; +-out_close: +- CloseHandle(sp_fd); +- return SER_INV_FD; + #else + struct termios wanted, observed; +- int fd; +- fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); +- if (fd < 0) { +- msg_perr_strerror("Cannot open serial port: "); +- return SER_INV_FD; +- } + fcntl(fd, F_SETFL, 0); + if (tcgetattr(fd, &observed) != 0) { + msg_perr_strerror("Could not fetch original serial port configuration: "); +- goto out_close; ++ return 1; + } + wanted = observed; + const struct baudentry *entry = round_baud(baud); + if (cfsetispeed(&wanted, entry->flag) != 0 || cfsetospeed(&wanted, entry->flag) != 0) { + msg_perr_strerror("Could not set serial baud rate: "); +- goto out_close; ++ return 1; + } + wanted.c_cflag &= ~(PARENB | CSTOPB | CSIZE | CRTSCTS); + wanted.c_cflag |= (CS8 | CLOCAL | CREAD); +@@ -232,11 +199,11 @@ out_close: + wanted.c_oflag &= ~OPOST; + if (tcsetattr(fd, TCSANOW, &wanted) != 0) { + msg_perr_strerror("Could not change serial port configuration: "); +- goto out_close; ++ return 1; + } + if (tcgetattr(fd, &observed) != 0) { + msg_perr_strerror("Could not fetch new serial port configuration: "); +- goto out_close; ++ return 1; + } + if (observed.c_cflag != wanted.c_cflag || + observed.c_lflag != wanted.c_lflag || +@@ -244,14 +211,54 @@ out_close: + observed.c_oflag != wanted.c_oflag || + cfgetispeed(&observed) != cfgetispeed(&wanted)) { + msg_perr("%s: Some requested options did not stick.\n", __func__); +- goto out_close; ++ return 1; + } +- msg_pdbg("Baud rate is %d.\n", entry->baud); +- return fd; ++ msg_pdbg("Baud rate is %d now.\n", entry->baud); ++#endif ++ return 0; ++} + +-out_close: +- close(sp_fd); +- return SER_INV_FD; ++fdtype sp_openserport(char *dev, unsigned int baud) ++{ ++ fdtype fd; ++#ifdef _WIN32 ++ char *dev2 = dev; ++ if ((strlen(dev) > 3) && ++ (tolower((unsigned char)dev[0]) == 'c') && ++ (tolower((unsigned char)dev[1]) == 'o') && ++ (tolower((unsigned char)dev[2]) == 'm')) { ++ dev2 = malloc(strlen(dev) + 5); ++ if (!dev2) { ++ msg_perr_strerror("Out of memory: "); ++ return SER_INV_FD; ++ } ++ strcpy(dev2, "\\\\.\\"); ++ strcpy(dev2 + 4, dev); ++ } ++ fd = CreateFile(dev2, GENERIC_READ | GENERIC_WRITE, 0, NULL, ++ OPEN_EXISTING, 0, NULL); ++ if (dev2 != dev) ++ free(dev2); ++ if (fd == INVALID_HANDLE_VALUE) { ++ msg_perr_strerror("Cannot open serial port: "); ++ return SER_INV_FD; ++ } ++ if (serialport_config(fd, baud) != 0) { ++ CloseHandle(fd); ++ return SER_INV_FD; ++ } ++ return fd; ++#else ++ fd = open(dev, O_RDWR | O_NOCTTY | O_NDELAY); ++ if (fd < 0) { ++ msg_perr_strerror("Cannot open serial port: "); ++ return SER_INV_FD; ++ } ++ if (serialport_config(fd, baud) != 0) { ++ close(fd); ++ return SER_INV_FD; ++ } ++ return fd; + #endif + } + +@@ -350,7 +357,7 @@ int serialport_write(unsigned char *buf, unsigned int writecnt) + if (!tmp) { + msg_pdbg2("Empty write\n"); + empty_writes--; +- programmer_delay(500); ++ internal_delay(500); + if (empty_writes == 0) { + msg_perr("Serial port is unresponsive!\n"); + return 1; +diff --git a/serprog.c b/serprog.c +index 3476315..35c4f32 100644 +--- a/serprog.c ++++ b/serprog.c +@@ -100,6 +100,7 @@ static int sp_opensocket(char *ip, unsigned int port) + if (NULL == hostPtr) { + hostPtr = gethostbyaddr(ip, strlen(ip), AF_INET); + if (NULL == hostPtr) { ++ close(sock); + msg_perr("Error: cannot resolve %s\n", ip); + return -1; + } +@@ -114,7 +115,11 @@ static int sp_opensocket(char *ip, unsigned int port) + } + /* We are latency limited, and sometimes do write-write-read * + * (write-n) - so enable TCP_NODELAY. */ +- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int)); ++ if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &flag, sizeof(int))) { ++ close(sock); ++ msg_perr("Error: serprog cannot set socket options: %s\n", strerror(errno)); ++ return -1; ++ } + return sock; + } + #endif +@@ -237,43 +242,58 @@ static int sp_docommand(uint8_t command, uint32_t parmlen, + return 0; + } + +-static void sp_flush_stream(void) ++static int sp_flush_stream(void) + { + if (sp_streamed_transmit_ops) + do { + unsigned char c; + if (serialport_read(&c, 1) != 0) { +- sp_die("Error: cannot read from device (flushing stream)"); ++ msg_perr("Error: cannot read from device (flushing stream)"); ++ return 1; + } + if (c == S_NAK) { + msg_perr("Error: NAK to a stream buffer operation\n"); +- exit(1); ++ return 1; + } + if (c != S_ACK) { + msg_perr("Error: Invalid reply 0x%02X from device\n", c); +- exit(1); ++ return 1; + } + } while (--sp_streamed_transmit_ops); + sp_streamed_transmit_ops = 0; + sp_streamed_transmit_bytes = 0; ++ return 0; + } + +-static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t * parms) ++static int sp_stream_buffer_op(uint8_t cmd, uint32_t parmlen, uint8_t *parms) + { + uint8_t *sp; + if (sp_automatic_cmdcheck(cmd)) + return 1; ++ + sp = malloc(1 + parmlen); +- if (!sp) sp_die("Error: cannot malloc command buffer"); ++ if (!sp) { ++ msg_perr("Error: cannot malloc command buffer\n"); ++ return 1; ++ } + sp[0] = cmd; + memcpy(&(sp[1]), parms, parmlen); +- if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) +- sp_flush_stream(); +- if (serialport_write(sp, 1 + parmlen) != 0) +- sp_die("Error: cannot write command"); +- free(sp); ++ ++ if (sp_streamed_transmit_bytes >= (1 + parmlen + sp_device_serbuf_size)) { ++ if (sp_flush_stream() != 0) { ++ free(sp); ++ return 1; ++ } ++ } ++ if (serialport_write(sp, 1 + parmlen) != 0) { ++ msg_perr("Error: cannot write command\n"); ++ free(sp); ++ return 1; ++ } + sp_streamed_transmit_ops += 1; + sp_streamed_transmit_bytes += 1 + parmlen; ++ ++ free(sp); + return 0; + } + +@@ -656,16 +676,16 @@ int serprog_init(void) + return 0; + } + +-/* Move an in flashrom buffer existing write-n operation to * +- * the on-device operation buffer. */ +-static void sp_pass_writen(void) ++/* Move an in flashrom buffer existing write-n operation to the on-device operation buffer. */ ++static int sp_pass_writen(void) + { + unsigned char header[7]; +- msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", +- sp_write_n_bytes, sp_write_n_addr); +- if (sp_streamed_transmit_bytes >= +- (7 + sp_write_n_bytes + sp_device_serbuf_size)) +- sp_flush_stream(); ++ msg_pspew(MSGHEADER "Passing write-n bytes=%d addr=0x%x\n", sp_write_n_bytes, sp_write_n_addr); ++ if (sp_streamed_transmit_bytes >= (7 + sp_write_n_bytes + sp_device_serbuf_size)) { ++ if (sp_flush_stream() != 0) { ++ return 1; ++ } ++ } + /* In case it's just a single byte send it as a single write. */ + if (sp_write_n_bytes == 1) { + sp_write_n_bytes = 0; +@@ -673,9 +693,10 @@ static void sp_pass_writen(void) + header[1] = (sp_write_n_addr >> 8) & 0xFF; + header[2] = (sp_write_n_addr >> 16) & 0xFF; + header[3] = sp_write_n_buf[0]; +- sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header); ++ if (sp_stream_buffer_op(S_CMD_O_WRITEB, 4, header) != 0) ++ return 1; + sp_opbuf_usage += 5; +- return; ++ return 0; + } + header[0] = S_CMD_O_WRITEN; + header[1] = (sp_write_n_bytes >> 0) & 0xFF; +@@ -684,39 +705,55 @@ static void sp_pass_writen(void) + header[4] = (sp_write_n_addr >> 0) & 0xFF; + header[5] = (sp_write_n_addr >> 8) & 0xFF; + header[6] = (sp_write_n_addr >> 16) & 0xFF; +- if (serialport_write(header, 7) != 0) +- sp_die("Error: cannot write write-n command\n"); +- if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) +- sp_die("Error: cannot write write-n data"); ++ if (serialport_write(header, 7) != 0) { ++ msg_perr(MSGHEADER "Error: cannot write write-n command\n"); ++ return 1; ++ } ++ if (serialport_write(sp_write_n_buf, sp_write_n_bytes) != 0) { ++ msg_perr(MSGHEADER "Error: cannot write write-n data"); ++ return 1; ++ } + sp_streamed_transmit_bytes += 7 + sp_write_n_bytes; + sp_streamed_transmit_ops += 1; + sp_opbuf_usage += 7 + sp_write_n_bytes; + sp_write_n_bytes = 0; + sp_prev_was_write = 0; ++ return 0; + } + +-static void sp_execute_opbuf_noflush(void) ++static int sp_execute_opbuf_noflush(void) + { +- if ((sp_max_write_n) && (sp_write_n_bytes)) +- sp_pass_writen(); +- sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL); +- msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", +- sp_opbuf_usage); ++ if ((sp_max_write_n) && (sp_write_n_bytes)) { ++ if (sp_pass_writen() != 0) { ++ msg_perr("Error: could not transfer write buffer\n"); ++ return 1; ++ } ++ } ++ if (sp_stream_buffer_op(S_CMD_O_EXEC, 0, NULL) != 0) { ++ msg_perr("Error: could not execute command buffer\n"); ++ return 1; ++ } ++ msg_pspew(MSGHEADER "Executed operation buffer of %d bytes\n", sp_opbuf_usage); + sp_opbuf_usage = 0; + sp_prev_was_write = 0; +- return; ++ return 0; + } + +-static void sp_execute_opbuf(void) ++static int sp_execute_opbuf(void) + { +- sp_execute_opbuf_noflush(); +- sp_flush_stream(); ++ if (sp_execute_opbuf_noflush() != 0) ++ return 1; ++ if (sp_flush_stream() != 0) ++ return 1; ++ ++ return 0; + } + + static int serprog_shutdown(void *data) + { + if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) +- sp_execute_opbuf(); ++ if (sp_execute_opbuf() != 0) ++ msg_pwarn("Could not flush command buffer.\n"); + if (sp_check_commandavail(S_CMD_S_PIN_STATE)) { + uint8_t dis = 0; + if (sp_docommand(S_CMD_S_PIN_STATE, 1, &dis, 0, NULL) == 0) +@@ -731,14 +768,15 @@ static int serprog_shutdown(void *data) + return 0; + } + +-static void sp_check_opbuf_usage(int bytes_to_be_added) ++static int sp_check_opbuf_usage(int bytes_to_be_added) + { + if (sp_device_opbuf_size <= (sp_opbuf_usage + bytes_to_be_added)) { +- sp_execute_opbuf(); +- /* If this happens in the mid of an page load the page load * +- * will probably fail. */ +- msg_pdbg(MSGHEADER "Warning: executed operation buffer due to size reasons\n"); ++ /* If this happens in the middle of a page load the page load will probably fail. */ ++ msg_pwarn(MSGHEADER "Warning: executed operation buffer due to size reasons\n"); ++ if (sp_execute_opbuf() != 0) ++ return 1; + } ++ return 0; + } + + static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val, +@@ -768,7 +806,7 @@ static void serprog_chip_writeb(const struct flashctx *flash, uint8_t val, + writeb_parm[1] = (addr >> 8) & 0xFF; + writeb_parm[2] = (addr >> 16) & 0xFF; + writeb_parm[3] = val; +- sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); ++ sp_stream_buffer_op(S_CMD_O_WRITEB, 4, writeb_parm); // FIXME: return error + sp_opbuf_usage += 5; + } + } +@@ -785,16 +823,16 @@ static uint8_t serprog_chip_readb(const struct flashctx *flash, + buf[0] = ((addr >> 0) & 0xFF); + buf[1] = ((addr >> 8) & 0xFF); + buf[2] = ((addr >> 16) & 0xFF); +- sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); +- sp_flush_stream(); ++ sp_stream_buffer_op(S_CMD_R_BYTE, 3, buf); // FIXME: return error ++ sp_flush_stream(); // FIXME: return error + if (serialport_read(&c, 1) != 0) +- sp_die("readb byteread"); ++ msg_perr(MSGHEADER "readb byteread"); // FIXME: return error + msg_pspew("%s addr=0x%" PRIxPTR " returning 0x%02X\n", __func__, addr, c); + return c; + } + + /* Local version that really does the job, doesn't care of max_read_n. */ +-static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) ++static int sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) + { + unsigned char sbuf[6]; + msg_pspew("%s: addr=0x%" PRIxPTR " len=%zu\n", __func__, addr, len); +@@ -808,10 +846,13 @@ static void sp_do_read_n(uint8_t * buf, const chipaddr addr, size_t len) + sbuf[4] = ((len >> 8) & 0xFF); + sbuf[5] = ((len >> 16) & 0xFF); + sp_stream_buffer_op(S_CMD_R_NBYTES, 6, sbuf); +- sp_flush_stream(); +- if (serialport_read(buf, len) != 0) +- sp_die("Error: cannot read read-n data"); +- return; ++ if (sp_flush_stream() != 0) ++ return 1; ++ if (serialport_read(buf, len) != 0) { ++ msg_perr(MSGHEADER "Error: cannot read read-n data"); ++ return 1; ++ } ++ return 0; + } + + /* The externally called version that makes sure that max_read_n is obeyed. */ +@@ -821,12 +862,12 @@ static void serprog_chip_readn(const struct flashctx *flash, uint8_t * buf, + size_t lenm = len; + chipaddr addrm = addr; + while ((sp_max_read_n != 0) && (lenm > sp_max_read_n)) { +- sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); ++ sp_do_read_n(&(buf[addrm-addr]), addrm, sp_max_read_n); // FIXME: return error + addrm += sp_max_read_n; + lenm -= sp_max_read_n; + } + if (lenm) +- sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); ++ sp_do_read_n(&(buf[addrm-addr]), addrm, lenm); // FIXME: return error + } + + void serprog_delay(int usecs) +@@ -858,11 +899,18 @@ static int serprog_spi_send_command(struct flashctx *flash, + unsigned char *parmbuf; + int ret; + msg_pspew("%s, writecnt=%i, readcnt=%i\n", __func__, writecnt, readcnt); +- if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) +- sp_execute_opbuf(); ++ if ((sp_opbuf_usage) || (sp_max_write_n && sp_write_n_bytes)) { ++ if (sp_execute_opbuf() != 0) { ++ msg_perr("Error: could not execute command buffer before sending SPI commands.\n"); ++ return 1; ++ } ++ } ++ + parmbuf = malloc(writecnt + 6); +- if (!parmbuf) +- sp_die("Error: cannot malloc SPI send param buffer"); ++ if (!parmbuf) { ++ msg_perr("Error: could not allocate SPI send param buffer.\n"); ++ return 1; ++ } + parmbuf[0] = (writecnt >> 0) & 0xFF; + parmbuf[1] = (writecnt >> 8) & 0xFF; + parmbuf[2] = (writecnt >> 16) & 0xFF; +@@ -879,8 +927,7 @@ static int serprog_spi_send_command(struct flashctx *flash, + /* FIXME: This function is optimized so that it does not split each transaction + * into chip page_size long blocks unnecessarily like spi_read_chunked. This has + * the advantage that it is much faster for most chips, but breaks those with +- * non-contiguous address space (like AT45DB161D). When spi_read_chunked is +- * fixed this method can be removed. */ ++ * non-continuous reads. When spi_read_chunked is fixed this method can be removed. */ + static int serprog_spi_read(struct flashctx *flash, uint8_t *buf, + unsigned int start, unsigned int len) + { +diff --git a/spi25.c b/spi25.c +index e001196..862a865 100644 +--- a/spi25.c ++++ b/spi25.c +@@ -679,7 +679,7 @@ int spi_block_erase_20(struct flashctx *flash, unsigned int addr, + + result = spi_send_multicommand(flash, cmds); + if (result) { +- msg_cerr("%s failed during command execution at address 0x%x\n", ++ msg_pdbg("%s failed during command execution at address 0x%x\n", + __func__, addr); + return result; + } +@@ -1128,13 +1128,9 @@ int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int sta + + + result = spi_send_multicommand(flash, cmds); +- if (result) { +- msg_cerr("%s failed during start command execution\n", +- __func__); +- /* FIXME: Should we send WRDI here as well to make sure the chip +- * is not in AAI mode? +- */ +- return result; ++ if (result != 0) { ++ msg_cerr("%s failed during start command execution: %d\n", __func__, result); ++ goto bailout; + } + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); +@@ -1146,16 +1142,21 @@ int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int sta + while (pos < start + len - 1) { + cmd[1] = buf[pos++ - start]; + cmd[2] = buf[pos++ - start]; +- spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, +- cmd, NULL); ++ result = spi_send_command(flash, JEDEC_AAI_WORD_PROGRAM_CONT_OUTSIZE, 0, cmd, NULL); ++ if (result != 0) { ++ msg_cerr("%s failed during followup AAI command execution: %d\n", __func__, result); ++ goto bailout; ++ } + while (spi_read_status_register(flash) & SPI_SR_WIP) + programmer_delay(10); + } + +- /* Use WRDI to exit AAI mode. This needs to be done before issuing any +- * other non-AAI command. +- */ +- spi_write_disable(flash); ++ /* Use WRDI to exit AAI mode. This needs to be done before issuing any other non-AAI command. */ ++ result = spi_write_disable(flash); ++ if (result != 0) { ++ msg_cerr("%s failed to disable AAI mode.\n", __func__); ++ return SPI_GENERIC_ERROR; ++ } + + /* Write remaining byte (if any). */ + if (pos < start + len) { +@@ -1165,4 +1166,10 @@ int default_spi_write_aai(struct flashctx *flash, uint8_t *buf, unsigned int sta + } + + return 0; ++ ++bailout: ++ result = spi_write_disable(flash); ++ if (result != 0) ++ msg_cerr("%s failed to disable AAI mode.\n", __func__); ++ return SPI_GENERIC_ERROR; + } +diff --git a/spi25_statusreg.c b/spi25_statusreg.c +index 8fb7f2d..48fceb0 100644 +--- a/spi25_statusreg.c ++++ b/spi25_statusreg.c +@@ -270,7 +270,7 @@ static void spi_prettyprint_status_register_bp(uint8_t status, int bp) + } + + /* Unnamed bits. */ +-static void spi_prettyprint_status_register_bit(uint8_t status, int bit) ++void spi_prettyprint_status_register_bit(uint8_t status, int bit) + { + msg_cdbg("Chip status register: Bit %i is %sset\n", bit, (status & (1 << bit)) ? "" : "not "); + } +diff --git a/stm50.c b/stm50.c +new file mode 100644 +index 0000000..edcfdd2 +--- /dev/null ++++ b/stm50.c +@@ -0,0 +1,115 @@ ++/* ++ * This file is part of the flashrom project. ++ * ++ * Copyright (C) 2008 Claus Gindhart ++ * Copyright (C) 2009 Sean Nelson ++ * Copyright (C) 2013 Stefan Tauner ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ */ ++ ++/* ++ * All ST M50 chips are locked on startup. Most of them have a uniform 64 kB block layout, but some have ++ * a non-uniform block/sector segmentation which has to be handled with more care. Some of the non-uniform ++ * chips support erasing of the 4 kB sectors with another command. ++ */ ++ ++#include "flash.h" ++#include "flashchips.h" ++#include "chipdrivers.h" ++ ++static int stm50_unlock_address(struct flashctx *flash, int offset) ++{ ++ chipaddr wrprotect = flash->virtual_registers + 2; ++ static const uint8_t unlock_sector = 0x00; ++ msg_cdbg("unlocking at 0x%x\n", offset); ++ chip_writeb(flash, unlock_sector, wrprotect + offset); ++ if (chip_readb(flash, wrprotect + offset) != unlock_sector) { ++ msg_cerr("Cannot unlock address 0x%x\n", offset); ++ return -1; ++ } ++ return 0; ++} ++ ++/* Chips known to use a non-uniform block and sector layout for locking (as well as for erasing): ++ * Name Size Address range of lock registers ++ * M50FLW080A 1MB FFB00002 - FFBFF002 ++ * M50FLW080B 1MB FFB00002 - FFBFF002 ++ * M50FW002 256k FFBC0002 - FFBFC002 ++ * M50LPW116 2MB FFA00002 - FFBFC002 ++ */ ++int unlock_stm50_nonuniform(struct flashctx *flash) ++{ ++ int i; ++ struct eraseblock *eraseblocks = flash->chip->block_erasers[0].eraseblocks; ++ unsigned int done = 0; ++ for (i = 0; i < NUM_ERASEREGIONS && eraseblocks[i].count != 0; i++) { ++ unsigned int block_size = eraseblocks[i].size; ++ unsigned int block_count = eraseblocks[i].count; ++ ++ int j; ++ for (j = 0; j < block_count; j++) { ++ if (stm50_unlock_address(flash, done)) { ++ msg_cerr("UNLOCK FAILED!\n"); ++ return -1; ++ } ++ done += block_count * block_size; ++ } ++ } ++ return 0; ++} ++ ++/* Unlocking for uniform 64 kB blocks starting at offset 2 of the feature registers. */ ++int unlock_stm50_uniform(struct flashctx *flash) ++{ ++ int i; ++ for (i = 0; i < flash->chip->total_size * 1024; i+= 64 * 1024) { ++ if (stm50_unlock_address(flash, i)) { ++ msg_cerr("UNLOCK FAILED!\n"); ++ return -1; ++ } ++ } ++ return 0; ++} ++ ++static int stm50_erase_sector(struct flashctx *flash, unsigned int addr) ++{ ++ chipaddr bios = flash->virtual_memory + addr; ++ ++ // clear status register ++ chip_writeb(flash, 0x50, bios); ++ // now start it ++ chip_writeb(flash, 0x32, bios); ++ chip_writeb(flash, 0xd0, bios); ++ programmer_delay(10); ++ ++ uint8_t status = wait_82802ab(flash); ++ print_status_82802ab(status); ++ ++ return status == 0x80; ++} ++ ++/* Some ST M50* chips do support erasing of sectors. This function will derive the erase function to use from ++ * the length of the of the block. For calls that apparently do not address a sector (but a block) we just call ++ * the block erase function instead. FIXME: This duplicates the behavior of the remaining erasers for blocks and ++ * might be fixed when flashrom supports multiple functions per eraser or erasers that do erase parts of the ++ * chip only. */ ++int erase_sector_stm50(struct flashctx *flash, unsigned int addr, unsigned int len) ++{ ++ if (len == 4096) ++ return stm50_erase_sector(flash, addr); ++ else ++ return erase_block_82802ab(flash, addr, len); ++} +diff --git a/udelay.c b/udelay.c +index e3cf3e3..9d3bfc2 100644 +--- a/udelay.c ++++ b/udelay.c +@@ -90,7 +90,11 @@ void myusec_calibrate_delay(void) + unsigned long timeusec, resolution; + int i, tries = 0; + ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("Calibrating delay loop... "); ++#else + msg_pinfo("Calibrating delay loop... "); ++#endif + resolution = measure_os_delay_resolution(); + if (resolution) { + msg_pdbg("OS timer resolution is %lu usecs, ", resolution); +@@ -151,7 +155,7 @@ recalibrate: + } + } + } else { +- msg_perr("delay loop is unreliable, trying to continue "); ++ msg_pdbg("delay loop is unreliable, trying to continue "); + } + + /* We're interested in the actual precision. */ +@@ -166,7 +170,11 @@ recalibrate: + timeusec = measure_delay(resolution * 4); + msg_pdbg("%ld myus = %ld us, ", resolution * 4, timeusec); + ++#ifdef FORCE10_SPI_CHANGE ++ msg_pdbg("OK.\n"); ++#else + msg_pinfo("OK.\n"); ++#endif + } + + /* Not very precise sleep. */ +diff --git a/util/getrevision.sh b/util/getrevision.sh +new file mode 100755 +index 0000000..709e45f +--- /dev/null ++++ b/util/getrevision.sh +@@ -0,0 +1,311 @@ ++#!/bin/sh ++# ++# This file is part of the flashrom project. ++# ++# Copyright (C) 2005 coresystems GmbH ++# Copyright (C) 2009,2010 Carl-Daniel Hailfinger ++# Copyright (C) 2010 Chromium OS Authors ++# Copyright (C) 2013 Stefan Tauner ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation; either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++# ++ ++EXIT_SUCCESS=0 ++EXIT_FAILURE=1 ++ ++# Make sure we don't get translated output ++export LC_ALL=C ++# nor local times or dates ++export TZ=UTC0 ++ ++# Helper functions ++# First argument is the path to inspect (usually optional; w/o it the whole repository will be considered) ++svn_has_local_changes() { ++ svn status "$1" | egrep '^ *[ADMR] *' >/dev/null ++} ++ ++git_has_local_changes() { ++ git update-index -q --refresh >/dev/null ++ ! git diff-index --quiet HEAD -- "$1" ++} ++ ++git_last_commit() { ++ git log --pretty=format:"%h" -1 -- "$1" ++} ++ ++svn_is_file_tracked() { ++ svn info "$1" >/dev/null 2>&1 ++} ++ ++git_is_file_tracked() { ++ git ls-files --error-unmatch -- "$1" >/dev/null 2>&1 ++} ++ ++is_file_tracked() { ++ svn_is_file_tracked "$1" || git_is_file_tracked "$1" ++} ++ ++# Tries to find a remote source for the changes committed locally. ++# This includes the URL of the remote repository including the last commit and a suitable branch name. ++# Takes one optional argument: the path to inspect ++git_url() { ++ last_commit=$(git_last_commit "$1") ++ # get all remote branches containing the last commit (excluding origin/HEAD and git-svn branches/tags) ++ branches=$(git branch -r --contains $last_commit | sed '/\//!d;/.*->.*/d;s/[\t ]*//') ++ if [ -z "$branches" ] ; then ++ echo "No remote branch contains a suitable commit">&2 ++ return ++ fi ++ ++ # find "nearest" branch ++ local mindiff=9000 ++ local target= ++ for branch in $branches ; do ++ curdiff=$(git rev-list --count $last_commit..$branch) ++ if [ $curdiff -ge $mindiff ] ; then ++ continue ++ fi ++ mindiff=$curdiff ++ target=$branch ++ done ++ ++ echo "$(git ls-remote --exit-code --get-url ${target%/*}) ${target#*/}" ++} ++ ++# Returns a string indicating where others can get the current source code (excluding uncommitted changes) ++# Takes one optional argument: the path to inspect ++scm_url() { ++ local url= ++ ++ # for a primitive VCS like subversion finding the URL is easy: there is only one upstream host ++ if svn_is_file_tracked "$1" ; then ++ url="$(svn info "$1" 2>/dev/null | ++ grep URL: | ++ sed 's/.*URL:[[:blank:]]*//;s/:\/\/.*@/:\/\//' | ++ grep ^.)" ++ elif git_is_file_tracked "$1" ; then ++ url="$(git_url "$1")" ++ else ++ return ${EXIT_FAILURE} ++ fi ++ ++ echo "${url}" ++} ++ ++# Retrieve timestamp since last modification. If the sources are pristine, ++# then the timestamp will match that of the SCM's most recent modification ++# date. ++timestamp() { ++ local t ++ ++ # date syntaxes are manifold: ++ # gnu date [-d input]... [+FORMAT] ++ # netbsd date [-ajnu] [-d date] [-r seconds] [+format] [[[[[[CC]yy]mm]dd]HH]MM[.SS]] ++ # freebsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...] ++ # dragonflybsd date [-jnu] [-d dst] [-r seconds] [-f fmt date | [[[[[cc]yy]mm]dd]HH]MM[.ss]] [+format] [...] ++ # openbsd date [-aju] [-d dst] [-r seconds] [+format] [[[[[[cc]yy]mm]dd]HH]MM[.SS]] [...] ++ if svn_is_file_tracked "$2" ; then ++ if svn_has_local_changes "$2"; then ++ t=$(date -u "$1") ++ else ++ # No local changes, get date of the last log record. Subversion provides that in ++ # ISO 8601 format when using the --xml switch. The sed call extracts that ignoring any ++ # fractional parts started by a comma or a dot. ++ local last_commit_date="$(svn info --xml "$2"| \ ++ sed -n -e 's/\([^,\.]*\)\([\.,].*\)*Z<\/date>/\1Z/p')" ++ ++ case $(uname) in ++ # Most BSD dates do not support parsing date values from user input with -d but all of ++ # them support parsing the syntax with [[[[[[cc]yy]mm]dd]HH]MM[.ss]]. We have to ++ # transform the ISO8601 date first though. ++ NetBSD|OpenBSD|DragonFly|FreeBSD) ++ last_commit_date="$(echo ${last_commit_date} | \ ++ sed -n -e 's/\(....\)-\(..\)-\(..\)T\(..\):\(..\):\(..\)Z/\1\2\3\4\5\.\6/p')" ++ t=$(date -u -j "${last_commit_date}" "$1" 2>/dev/null);; ++ *) ++ t=$(date -u -d "${last_commit_date}" "$1" 2>/dev/null);; ++ esac ++ fi ++ elif git_is_file_tracked "$2" ; then ++ # are there local changes? ++ if git_has_local_changes "$2" ; then ++ t=$(date -u "${1}") ++ else ++ # No local changes, get date of the last commit ++ case $(uname) in ++ # Most BSD dates do not support parsing date values from user input with -d but all of ++ # them support parsing epoch seconds with -r. Thanks to git we can easily use that: ++ NetBSD|OpenBSD|DragonFly|FreeBSD) ++ t=$(date -u -r "$(git log --pretty=format:%ct -1 -- $2)" "$1" 2>/dev/null);; ++ *) ++ t=$(date -d "$(git log --pretty=format:%cD -1 -- $2)" -u "$1" 2>/dev/null);; ++ esac ++ fi ++ else ++ t=$(date -u "$1") ++ fi ++ ++ if [ -z "$t" ]; then ++ echo "Warning: Could not determine timestamp." 2>/dev/null ++ fi ++ echo "${t}" ++} ++ ++# Retrieve local SCM revision info. This is useful if we're working in a different SCM than upstream and/or ++# have local changes. ++local_revision() { ++ local r= ++ ++ if svn_is_file_tracked "$1" ; then ++ r=$(svn_has_local_changes "$1" && echo "dirty") ++ elif git_is_file_tracked "$1" ; then ++ r=$(git_last_commit "$1") ++ ++ local svn_base=$(git log --grep git-svn-id -1 --format='%h') ++ if [ "$svn_base" != "" ] ; then ++ local diff_to_svn=$(git rev-list --count ${svn_base}..${r}) ++ if [ "$diff_to_svn" -gt 0 ] ; then ++ r="$r-$diff_to_svn" ++ fi ++ fi ++ ++ if git_has_local_changes "$1" ; then ++ r="$r-dirty" ++ fi ++ else ++ return ${EXIT_FAILURE} ++ fi ++ ++ echo "${r}" ++} ++ ++# Get the upstream flashrom revision stored in SVN metadata. ++upstream_revision() { ++ local r= ++ ++ if svn_is_file_tracked "$1" ; then ++ r=$(svn info "$1" 2>/dev/null | \ ++ grep "Last Changed Rev:" | \ ++ sed -e "s/^Last Changed Rev: *//" -e "s/\([0-9]*\).*/r\1/" | \ ++ grep "r[0-9]") ++ elif git_is_file_tracked "$1" ; then ++ # If this is a "native" git-svn clone we could use git svn log: ++ # git svn log --oneline -1 | sed 's/^r//;s/[[:blank:]].*//' or even git svn find-rev ++ # but it is easier to just grep for the git-svn-id unconditionally ++ r=$(git log --grep git-svn-id -1 -- "$1" | \ ++ grep git-svn-id | \ ++ sed 's/.*@/r/;s/[[:blank:]].*//') ++ fi ++ ++ if [ -z "$r" ]; then ++ r="unknown" # default to unknown ++ fi ++ echo "${r}" ++} ++ ++show_help() { ++ echo "Usage: ++ ${0} [path] ++ ++Commands ++ -h or --help ++ this message ++ -l or --local ++ local revision information including an indicator for uncommitted changes ++ -u or --upstream ++ upstream revision ++ -U or --url ++ URL associated with the latest commit ++ -d or --date ++ date of most recent modification ++ -t or --timestamp ++ timestamp of most recent modification ++" ++ return ++} ++ ++check_action() { ++ if [ -n "$action" ]; then ++ echo "Error: Multiple actions given.">&2 ++ exit ${EXIT_FAILURE} ++ fi ++} ++ ++main() { ++ local query_path= ++ local action= ++ ++ # The is the main loop ++ while [ $# -gt 0 ]; ++ do ++ case ${1} in ++ -h|--help) ++ action=show_help; ++ shift;; ++ -l|--local) ++ check_action $1 ++ action=local_revision ++ shift;; ++ -u|--upstream) ++ check_action $1 ++ action=upstream_revision ++ shift;; ++ -U|--url) ++ check_action $1 ++ action=scm_url ++ shift;; ++ -d|--date) ++ check_action $1 ++ action="timestamp +%Y-%m-%d" # refrain from suffixing 'Z' to indicate it's UTC ++ shift;; ++ -t|--timestamp) ++ check_action $1 ++ action="timestamp +%Y-%m-%dT%H:%M:%SZ" # There is only one valid time format! ISO 8601 ++ shift;; ++ -*) ++ show_help; ++ echo "Error: Invalid option: ${1}" ++ exit ${EXIT_FAILURE};; ++ *) ++ if [ -z "$query_path" ] ; then ++ if [ ! -e "$1" ] ; then ++ echo "Error: Path \"${1}\" does not exist.">&2 ++ exit ${EXIT_FAILURE} ++ fi ++ query_path=$1 ++ else ++ echo "Warning: Ignoring over-abundant paramter: \"${1}\"">&2 ++ fi ++ shift;; ++ esac; ++ done ++ ++ # default to current directory (usually equals the whole repository) ++ if [ -z "$query_path" ] ; then ++ query_path=. ++ fi ++ if ! is_file_tracked "$query_path" ; then ++ echo "Warning: Path \"${query_path}\" is not under version control.">&2 ++ fi ++ if [ -z "$action" ] ; then ++ show_help ++ echo "Error: No actions specified" ++ exit ${EXIT_FAILURE} ++ fi ++ ++ $action "$query_path" ++} ++ ++main $@ +diff --git a/util/ich_descriptors_tool/ich_descriptors_tool.c b/util/ich_descriptors_tool/ich_descriptors_tool.c +index c359913..dd35860 100644 +--- a/util/ich_descriptors_tool/ich_descriptors_tool.c ++++ b/util/ich_descriptors_tool/ich_descriptors_tool.c +@@ -77,12 +77,13 @@ static void dump_file(const char *prefix, const uint32_t *dump, unsigned int len + printf("Dumping %u bytes of the %s region from 0x%08x-0x%08x to %s... ", + file_len, region_names[i], base, limit, fn); + int fh = open(fn, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); +- free(fn); + if (fh < 0) { + fprintf(stderr, + "ERROR: couldn't open(%s): %s\n", fn, strerror(errno)); ++ free(fn); + exit(1); + } ++ free(fn); + + ret = write(fh, &dump[base >> 2], file_len); + if (ret != file_len) { +@@ -120,6 +121,7 @@ static void usage(char *argv[], char *error) + "\t- \"5\" or \"ibex\" for Intel's 5 series chipsets,\n" + "\t- \"6\" or \"cougar\" for Intel's 6 series chipsets,\n" + "\t- \"7\" or \"panther\" for Intel's 7 series chipsets.\n" ++"\t- \"avoton\",\n" + "If '-d' is specified some regions such as the BIOS image as seen by the CPU or\n" + "the GbE blob that is required to initialize the GbE are also dumped to files.\n", + argv[0], argv[0]); +@@ -197,6 +199,10 @@ int main(int argc, char *argv[]) + else if ((strcmp(csn, "7") == 0) || + (strcmp(csn, "panther") == 0)) + cs = CHIPSET_7_SERIES_PANTHER_POINT; ++#ifdef DELL_AVOTON_SUPPORT ++ else if (strcmp(csn, "avoton") == 0) ++ cs = CHIPSET_AVOTON; ++#endif + } + + ret = read_ich_descriptors_from_dump(buf, len, &desc); +diff --git a/util/z60_flashrom.rules b/util/z60_flashrom.rules +index 8456a04..948563c 100644 +--- a/util/z60_flashrom.rules ++++ b/util/z60_flashrom.rules +@@ -80,4 +80,8 @@ ATTRS{idVendor}=="15ba", ATTRS{idProduct}=="002a", MODE="664", GROUP="plugdev" + # http://www.diygadget.com/tiao-usb-multi-protocol-adapter-jtag-spi-i2c-serial.html + ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a98", MODE="664", GROUP="plugdev" + ++# TIAO/DIYGADGET USB Multi-Protocol Adapter (TUMPA) Lite ++# http://www.tiaowiki.com/w/TIAO_USB_Multi_Protocol_Adapter_Lite_User's_Manual ++ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a99", MODE="664", GROUP="plugdev" ++ + LABEL="flashrom_rules_end" +-- +2.7.4 + diff --git a/platform/broadcom/sonic-platform-modules-dell/tools/flashrom.sh b/platform/broadcom/sonic-platform-modules-dell/tools/flashrom.sh new file mode 100755 index 000000000000..c3af65fd6d84 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/tools/flashrom.sh @@ -0,0 +1,10 @@ +#!/bin/bash +export DELL_TOOLS_DIR="platform/broadcom/sonic-platform-modules-dell/tools" + +cd $DELL_TOOLS_DIR +rm -rf $DELL_TOOLS_DIR/flashrom +git clone https://github.com/flashrom/flashrom.git +cd flashrom +git checkout tags/0.9.7 +git apply ../0002-Flashrom-support-for-Intel-Rangeley-and-Denverton-CP.patch +make diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py deleted file mode 120000 index 84af7963bb3d..000000000000 --- a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py +++ /dev/null @@ -1 +0,0 @@ -../../s6100/sonic_platform/sfp.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py new file mode 100644 index 000000000000..f29b708b8ea5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/z9100/sonic_platform/sfp.py @@ -0,0 +1,879 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +PAGE_OFFSET = 0 +KEY_OFFSET = 1 +KEY_WIDTH = 2 +FUNC_NAME = 3 + +INFO_OFFSET = 128 +DOM_OFFSET = 0 +DOM_OFFSET1 = 384 + +cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)', + 'Length OM1(m)', 'Length Cable Assembly(m)') + +compliance_code_tup = ( + '10/40G Ethernet Compliance Code', + 'SONET Compliance codes', + 'SAS/SATA compliance codes', + 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', + 'Fibre Channel Speed') + +info_dict_keys = ['type', 'hardwarerev', 'serialnum', + 'manufacturename', 'modelname', 'Connector', + 'encoding', 'ext_identifier', 'ext_rateselect_compliance', + 'cable_type', 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'vendor_date', 'vendor_oui'] + +dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', + 'power_lpmode', 'tx_disable', 'tx_disable_channel', + 'temperature', 'voltage', 'rx1power', + 'rx2power', 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', 'tx3bias', + 'tx4bias', 'tx1power', 'tx2power', + 'tx3power', 'tx4power'] + +threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +sff8436_parser = { + 'reset_status': [DOM_OFFSET, 2, 1, 'parse_dom_status_indicator'], + 'rx_los': [DOM_OFFSET, 3, 1, 'parse_dom_tx_rx_los'], + 'tx_fault': [DOM_OFFSET, 4, 1, 'parse_dom_tx_fault'], + 'tx_disable': [DOM_OFFSET, 86, 1, 'parse_dom_tx_disable'], + 'power_lpmode': [DOM_OFFSET, 93, 1, 'parse_dom_power_control'], + 'power_override': [DOM_OFFSET, 93, 1, 'parse_dom_power_control'], + 'Temperature': [DOM_OFFSET, 22, 2, 'parse_temperature'], + 'Voltage': [DOM_OFFSET, 26, 2, 'parse_voltage'], + 'ChannelMonitor': [DOM_OFFSET, 34, 16, 'parse_channel_monitor_params'], + + 'cable_type': [INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'cable_length': [INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'], + 'Connector': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'type': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'encoding': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'ext_identifier': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'ext_rateselect_compliance': + [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'nominal_bit_rate': [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'specification_compliance': + [INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'], + 'manufacturename': [INFO_OFFSET, 20, 16, 'parse_vendor_name'], + 'vendor_oui': [INFO_OFFSET, 37, 3, 'parse_vendor_oui'], + 'modelname': [INFO_OFFSET, 40, 16, 'parse_vendor_pn'], + 'hardwarerev': [INFO_OFFSET, 56, 2, 'parse_vendor_rev'], + 'serialnum': [INFO_OFFSET, 68, 16, 'parse_vendor_sn'], + 'vendor_date': [INFO_OFFSET, 84, 8, 'parse_vendor_date'], + 'ModuleThreshold': [DOM_OFFSET1, 128, 24, 'parse_module_threshold_values'], + 'ChannelThreshold': [DOM_OFFSET1, 176, 16, 'parse_channel_threshold_values'], +} + + +class Sfp(SfpBase): + """ + DELLEMC Platform-specific Sfp class + """ + + def __init__(self, index, sfp_type, eeprom_path, + sfp_control, sfp_ctrl_idx): + SfpBase.__init__(self) + self.sfp_type = sfp_type + self.index = index + self.eeprom_path = eeprom_path + self.sfp_control = sfp_control + self.sfp_ctrl_idx = sfp_ctrl_idx + self.sfpInfo = sff8436InterfaceId() + self.sfpDomInfo = sff8436Dom() + + def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes): + eeprom_raw = [] + try: + eeprom = 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: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _get_eeprom_data(self, eeprom_key): + eeprom_data = None + page_offset = None + + if (self.sfpInfo is None): + return None + + page_offset = sff8436_parser[eeprom_key][PAGE_OFFSET] + eeprom_data_raw = self._read_eeprom_bytes( + self.eeprom_path, + (sff8436_parser[eeprom_key][PAGE_OFFSET] + + sff8436_parser[eeprom_key][KEY_OFFSET]), + sff8436_parser[eeprom_key][KEY_WIDTH]) + if (eeprom_data_raw is not None): + # Offset 128 is used to retrieve sff8436InterfaceId Info + # Offset 0 is used to retrieve sff8436Dom Info + if (page_offset == 128): + eeprom_data = getattr( + self.sfpInfo, sff8436_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + else: + eeprom_data = getattr( + self.sfpDomInfo, sff8436_parser[eeprom_key][FUNC_NAME])( + eeprom_data_raw, 0) + + return eeprom_data + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + """ + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(info_dict_keys, 'N/A') + + # BaseInformation + iface_data = self._get_eeprom_data('type') + if (iface_data is not None): + connector = iface_data['data']['Connector']['value'] + encoding = iface_data['data']['EncodingCodes']['value'] + ext_id = iface_data['data']['Extended Identifier']['value'] + rate_identifier = iface_data['data']['RateIdentifier']['value'] + identifier = iface_data['data']['type']['value'] + bit_rate = str( + iface_data['data']['Nominal Bit Rate(100Mbs)']['value']) + + for key in compliance_code_tup: + if key in iface_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value'] + for key in cable_length_tup: + if key in iface_data['data']: + cable_type = key + cable_length = str(iface_data['data'][key]['value']) + else: + return None + + # Vendor Date + vendor_date_data = self._get_eeprom_data('vendor_date') + if (vendor_date_data is not None): + vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + else: + return None + + # Vendor Name + vendor_name_data = self._get_eeprom_data('manufacturename') + if (vendor_name_data is not None): + vendor_name = vendor_name_data['data']['Vendor Name']['value'] + else: + return None + + # Vendor OUI + vendor_oui_data = self._get_eeprom_data('vendor_oui') + if (vendor_oui_data is not None): + vendor_oui = vendor_oui_data['data']['Vendor OUI']['value'] + else: + return None + + # Vendor PN + vendor_pn_data = self._get_eeprom_data('modelname') + if (vendor_pn_data is not None): + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + else: + return None + + # Vendor Revision + vendor_rev_data = self._get_eeprom_data('hardwarerev') + if (vendor_rev_data is not None): + vendor_rev = vendor_rev_data['data']['Vendor Rev']['value'] + else: + return None + + # Vendor Serial Number + vendor_sn_data = self._get_eeprom_data('serialnum') + if (vendor_sn_data is not None): + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + else: + return None + + # Fill The Dictionary and return + transceiver_info_dict['type'] = identifier + transceiver_info_dict['hardwarerev'] = vendor_rev + transceiver_info_dict['serialnum'] = vendor_sn + transceiver_info_dict['manufacturename'] = vendor_name + transceiver_info_dict['modelname'] = vendor_pn + transceiver_info_dict['Connector'] = connector + transceiver_info_dict['encoding'] = encoding + transceiver_info_dict['ext_identifier'] = ext_id + transceiver_info_dict['ext_rateselect_compliance'] = rate_identifier + transceiver_info_dict['cable_type'] = cable_type + transceiver_info_dict['cable_length'] = cable_length + transceiver_info_dict['nominal_bit_rate'] = bit_rate + transceiver_info_dict['specification_compliance'] = str( + compliance_code_dict) + transceiver_info_dict['vendor_date'] = vendor_date + transceiver_info_dict['vendor_oui'] = vendor_oui + + return transceiver_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + """ + transceiver_dom_threshold_dict = {} + transceiver_dom_threshold_dict = dict.fromkeys( + threshold_dict_keys, 'N/A') + + # Module Threshold + module_threshold_data = self._get_eeprom_data('ModuleThreshold') + if (module_threshold_data is not None): + tempHighAlarm = module_threshold_data['data']['TempHighAlarm']['value'] + tempLowAlarm = module_threshold_data['data']['TempLowAlarm']['value'] + tempHighWarn = module_threshold_data['data']['TempHighWarning']['value'] + tempLowWarn = module_threshold_data['data']['TempLowWarning']['value'] + vccHighAlarm = module_threshold_data['data']['VccHighAlarm']['value'] + vccLowAlarm = module_threshold_data['data']['VccLowAlarm']['value'] + vccHighWarn = module_threshold_data['data']['VccHighWarning']['value'] + vccLowWarn = module_threshold_data['data']['VccLowWarning']['value'] + else: + return None + + # Channel Threshold + channel_threshold_data = self._get_eeprom_data('ChannelThreshold') + if (channel_threshold_data is not None): + rxPowerHighAlarm = channel_threshold_data['data']['RxPowerHighAlarm']['value'] + rxPowerLowAlarm = channel_threshold_data['data']['RxPowerLowAlarm']['value'] + rxPowerHighWarn = channel_threshold_data['data']['RxPowerHighWarning']['value'] + rxPowerLowWarn = channel_threshold_data['data']['RxPowerLowWarning']['value'] + txBiasHighAlarm = channel_threshold_data['data']['TxBiasHighAlarm']['value'] + txBiasLowAlarm = channel_threshold_data['data']['TxBiasLowAlarm']['value'] + txBiasHighWarn = channel_threshold_data['data']['TxBiasHighWarning']['value'] + txBiasLowWarn = channel_threshold_data['data']['TxBiasLowWarning']['value'] + else: + return None + + transceiver_dom_threshold_dict['temphighalarm'] = tempHighAlarm + transceiver_dom_threshold_dict['templowalarm'] = tempLowAlarm + transceiver_dom_threshold_dict['temphighwarning'] = tempHighWarn + transceiver_dom_threshold_dict['templowwarning'] = tempLowWarn + transceiver_dom_threshold_dict['vcchighalarm'] = vccHighAlarm + transceiver_dom_threshold_dict['vcclowalarm'] = vccLowAlarm + transceiver_dom_threshold_dict['vcchighwarning'] = vccHighWarn + transceiver_dom_threshold_dict['vcclowwarning'] = vccLowWarn + transceiver_dom_threshold_dict['rxpowerhighalarm'] = rxPowerHighAlarm + transceiver_dom_threshold_dict['rxpowerlowalarm'] = rxPowerLowAlarm + transceiver_dom_threshold_dict['rxpowerhighwarning'] = rxPowerHighWarn + transceiver_dom_threshold_dict['rxpowerlowwarning'] = rxPowerLowWarn + transceiver_dom_threshold_dict['txbiashighalarm'] = txBiasHighAlarm + transceiver_dom_threshold_dict['txbiaslowalarm'] = txBiasLowAlarm + transceiver_dom_threshold_dict['txbiashighwarning'] = txBiasHighWarn + transceiver_dom_threshold_dict['txbiaslowwarning'] = txBiasLowWarn + + return transceiver_dom_threshold_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + """ + tx_bias_list = [] + rx_power_list = [] + transceiver_dom_dict = {} + transceiver_dom_dict = dict.fromkeys(dom_dict_keys, 'N/A') + + # RxLos + rx_los = self.get_rx_los() + + # TxFault + tx_fault = self.get_tx_fault() + + # ResetStatus + reset_state = self.get_reset_status() + + # LowPower Mode + lp_mode = self.get_lpmode() + + # TxDisable + tx_disable = self.get_tx_disable() + + # TxDisable Channel + tx_disable_channel = self.get_tx_disable_channel() + + # Temperature + temperature = self.get_temperature() + + # Voltage + voltage = self.get_voltage() + + # Channel Monitor + channel_monitor_data = self._get_eeprom_data('ChannelMonitor') + if (channel_monitor_data is not None): + tx_bias = channel_monitor_data['data']['TX1Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = channel_monitor_data['data']['TX2Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = channel_monitor_data['data']['TX3Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = channel_monitor_data['data']['TX4Bias']['value'] + tx_bias_list.append(tx_bias) + rx_power = channel_monitor_data['data']['RX1Power']['value'] + rx_power_list.append(rx_power) + rx_power = channel_monitor_data['data']['RX2Power']['value'] + rx_power_list.append(rx_power) + rx_power = channel_monitor_data['data']['RX3Power']['value'] + rx_power_list.append(rx_power) + rx_power = channel_monitor_data['data']['RX4Power']['value'] + rx_power_list.append(rx_power) + else: + return None + + transceiver_dom_dict['rx_los'] = rx_los + transceiver_dom_dict['tx_fault'] = tx_fault + transceiver_dom_dict['reset_status'] = reset_state + transceiver_dom_dict['power_lpmode'] = lp_mode + transceiver_dom_dict['tx_disable'] = tx_disable + transceiver_dom_dict['tx_disable_channel'] = tx_disable_channel + transceiver_dom_dict['temperature'] = temperature + transceiver_dom_dict['voltage'] = voltage + transceiver_dom_dict['tx1bias'] = tx_bias_list[0] + transceiver_dom_dict['tx2bias'] = tx_bias_list[1] + transceiver_dom_dict['tx3bias'] = tx_bias_list[2] + transceiver_dom_dict['tx4bias'] = tx_bias_list[3] + transceiver_dom_dict['rx1power'] = rx_power_list[0] + transceiver_dom_dict['rx2power'] = rx_power_list[1] + transceiver_dom_dict['rx3power'] = rx_power_list[2] + transceiver_dom_dict['rx4power'] = rx_power_list[3] + + return transceiver_dom_dict + + def get_name(self): + """ + Retrieves the name of the sfp + Returns : QSFP or QSFP+ or QSFP28 + """ + iface_data = self._get_eeprom_data('type') + if (iface_data is not None): + identifier = iface_data['data']['type']['value'] + else: + return None + + return identifier + + def get_presence(self): + """ + Retrieves the presence of the sfp + """ + presence_ctrl = self.sfp_control + 'qsfp_modprs' + try: + reg_file = open(presence_ctrl) + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + # Mask off the bit corresponding to our port + mask = (1 << index) + + # ModPrsL is active low + if ((reg_value & mask) == 0): + return True + + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the sfp + """ + vendor_pn_data = self._get_eeprom_data('modelname') + if (vendor_pn_data is not None): + vendor_pn = vendor_pn_data['data']['Vendor PN']['value'] + else: + return None + + return vendor_pn + + def get_serial(self): + """ + Retrieves the serial number of the sfp + """ + vendor_sn_data = self._get_eeprom_data('serialnum') + if (vendor_sn_data is not None): + vendor_sn = vendor_sn_data['data']['Vendor SN']['value'] + else: + return None + + return vendor_sn + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + """ + reset_status = None + reset_ctrl = self.sfp_control + 'qsfp_reset' + try: + reg_file = open(reset_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + if ((reg_value & mask) == 0): + reset_status = True + else: + reset_status = False + + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + """ + rx_los = None + rx_los_list = [] + + rx_los_data = self._get_eeprom_data('rx_los') + if (rx_los_data is not None): + rx_los = rx_los_data['data']['Rx1LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx2LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx3LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + rx_los = rx_los_data['data']['Rx4LOS']['value'] + if (rx_los is 'On'): + rx_los_list.append(True) + else: + rx_los_list.append(False) + + if (rx_los_list[0] and rx_los_list[1] + and rx_los_list[2] and rx_los_list[3]): + rx_los = True + else: + rx_los = False + + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + """ + tx_fault = None + tx_fault_list = [] + + tx_fault_data = self._get_eeprom_data('tx_fault') + if (tx_fault_data is not None): + tx_fault = tx_fault_data['data']['Tx1Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx2Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx3Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + tx_fault = tx_fault_data['data']['Tx4Fault']['value'] + if (tx_fault is 'On'): + tx_fault_list.append(True) + else: + tx_fault_list.append(False) + + if (tx_fault_list[0] and tx_fault_list[1] + and tx_fault_list[2] and tx_fault_list[3]): + tx_fault = True + else: + tx_fault = False + + return tx_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + """ + tx_disable = None + tx_disable_list = [] + + tx_disable_data = self._get_eeprom_data('tx_disable') + if (tx_disable_data is not None): + tx_disable = tx_disable_data['data']['Tx1Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx2Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx3Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + tx_disable = tx_disable_data['data']['Tx4Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(True) + else: + tx_disable_list.append(False) + + if (tx_disable_list[0] and tx_disable_list[1] + and tx_disable_list[2] and tx_disable_list[3]): + tx_disable = True + else: + tx_disable = False + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + """ + tx_disable = None + tx_disable_list = [] + + tx_disable_data = self._get_eeprom_data('tx_disable') + if (tx_disable_data is not None): + tx_disable = tx_disable_data['data']['Tx1Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx2Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx3Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + tx_disable = tx_disable_data['data']['Tx4Disable']['value'] + if (tx_disable is 'On'): + tx_disable_list.append(1) + else: + tx_disable_list.append(0) + + bit4 = int(tx_disable_list[3]) * 8 + bit3 = int(tx_disable_list[2]) * 4 + bit2 = int(tx_disable_list[1]) * 2 + bit1 = int(tx_disable_list[0]) * 1 + + tx_disable_channel = hex(bit4 + bit3 + bit2 + bit1) + + return tx_disable_channel + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + """ + lpmode_ctrl = self.sfp_control + 'qsfp_lpmode' + try: + reg_file = open(lpmode_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + if ((reg_value & mask) == 0): + lpmode_state = False + else: + lpmode_state = True + + return lpmode_state + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + """ + power_override_state = None + + # Reset Status + power_override_data = self._get_eeprom_data('power_override') + if (power_override_data is not None): + power_override = power_override_data['data']['PowerOverRide']['value'] + if (power_override is 'On'): + power_override_state = True + else: + power_override_state = False + + return power_override_state + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + """ + temperature = None + + temperature_data = self._get_eeprom_data('Temperature') + if (temperature_data is not None): + temperature = temperature_data['data']['Temperature']['value'] + + return temperature + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + """ + voltage = None + + voltage_data = self._get_eeprom_data('Voltage') + if (voltage_data is not None): + voltage = voltage_data['data']['Vcc']['value'] + + return voltage + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + """ + tx_bias = None + tx_bias_list = [] + + tx_bias_data = self._get_eeprom_data('ChannelMonitor') + if (tx_bias_data is not None): + tx_bias = tx_bias_data['data']['TX1Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX2Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX3Bias']['value'] + tx_bias_list.append(tx_bias) + tx_bias = tx_bias_data['data']['TX4Bias']['value'] + tx_bias_list.append(tx_bias) + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + """ + rx_power = None + rx_power_list = [] + + rx_power_data = self._get_eeprom_data('ChannelMonitor') + if (rx_power_data is not None): + rx_power = rx_power_data['data']['RX1Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX2Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX3Power']['value'] + rx_power_list.append(rx_power) + rx_power = rx_power_data['data']['RX4Power']['value'] + rx_power_list.append(rx_power) + + return rx_power_list + + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + """ + tx_power = None + tx_power_list = [] + + tx_power_list.append('-infdBm') + tx_power_list.append('-infdBm') + tx_power_list.append('-infdBm') + tx_power_list.append('-infdBm') + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + """ + reset_ctrl = self.sfp_control + 'qsfp_reset' + try: + # Open reset_ctrl in both read & write mode + reg_file = open(reset_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + # Mask off the bit corresponding to our port + mask = (1 << index) + + # ResetL is active low + reg_value = (reg_value & ~mask) + + # Convert our register value back to a + # hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + # Flip the bit back high and write back to the + # register to take port out of reset + try: + reg_file = open(reset_ctrl, "w") + except IOError as e: + return False + + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + """ + lpmode_ctrl = self.sfp_control + 'qsfp_lpmode' + try: + reg_file = open(lpmode_ctrl, "r+") + except IOError as e: + return False + + reg_hex = reg_file.readline().rstrip() + + # content is a string containing the hex + # representation of the register + reg_value = int(reg_hex, 16) + + # Mask off the bit corresponding to our port + index = self.sfp_ctrl_idx + + mask = (1 << index) + + # 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 + content = hex(reg_value) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + """ + return False + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + """ + return False + + def get_status(self): + """ + Retrieves the operational status of the device + """ + reset = self.get_reset_status() + + if (reset == True): + status = False + else: + status = True + + return status diff --git a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh index 880ba98abb1f..9fd925f2b90d 100755 --- a/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh +++ b/platform/broadcom/sonic-platform-modules-dell/z9264f/scripts/z9264f_platform.sh @@ -85,6 +85,22 @@ switch_board_modsel() { python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1 done } + +# Copy led_proc_init.soc file according to the HWSKU +init_switch_port_led() { + device="/usr/share/sonic/device" + platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) + hwsku=$(cat /etc/sonic/config_db.json | grep "hwsku" | cut -d ":" -f2 | sed 's/"//g' | sed 's/,//g'| xargs ) + + led_proc_init="$device/$platform/$hwsku/led_proc_init.soc" + # Remove old HWSKU LED file.. + rm -rf $device/$platform/led_proc_init.soc + + if [ -e $led_proc_init ] && [ ! -e $device/$platform/led_proc_init.soc ]; then + cp $led_proc_init $device/$platform/ + fi +} + init_devnum if [ "$1" == "init" ]; then @@ -98,6 +114,7 @@ if [ "$1" == "init" ]; then switch_board_qsfp_mux "new_device" switch_board_qsfp "new_device" switch_board_modsel + init_switch_port_led python /usr/bin/qsfp_irq_enable.py elif [ "$1" == "deinit" ]; then diff --git a/platform/broadcom/sonic-platform-modules-juniper/.gitignore b/platform/broadcom/sonic-platform-modules-juniper/.gitignore new file mode 100644 index 000000000000..7f287d538227 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/.gitignore @@ -0,0 +1,50 @@ +# Object files +*.o +*.ko +*.obj +*.elf + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su + +# Kernel Module Compile Results +*.mod* +*.cmd +*.o.d +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# Debian packaging +*.debhelper.log +*.postinst.debhelper +*.postrm.debhelper +*.prerm.debhelper +*.substvars diff --git a/platform/broadcom/sonic-platform-modules-juniper/LICENSE b/platform/broadcom/sonic-platform-modules-juniper/LICENSE new file mode 100644 index 000000000000..c819eacfeb94 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/LICENSE @@ -0,0 +1,16 @@ +Copyright (C) 2016 Microsoft, Inc +Copyright (C) 2019 Juniper Networks + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/broadcom/sonic-platform-modules-juniper/README.md b/platform/broadcom/sonic-platform-modules-juniper/README.md new file mode 100644 index 000000000000..8d2820a74b2e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/README.md @@ -0,0 +1 @@ +platform drivers for Juniper QFX5210 for the SONiC project diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/juniper_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/juniper_i2c_cpld.c new file mode 100644 index 000000000000..25860a6ac1f9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/juniper_i2c_cpld.c @@ -0,0 +1,892 @@ +/* + * A hwmon driver for the juniper_i2c_cpld + * + * Tested and validated on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2013 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define MAX_PORT_NUM 64 +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +#define I2C_ADDR_CPLD1 0x60 +#define I2C_ADDR_CPLD2 0x62 +#define I2C_ADDR_CPLD3 0x64 +#define CPLD_ADDRS {I2C_ADDR_CPLD1, I2C_ADDR_CPLD2, I2C_ADDR_CPLD3} + + +/* + * Number of additional attribute pointers to allocate + * with each call to krealloc + */ +#define ATTR_ALLOC_SIZE 1 /*For last attribute which is NUll.*/ + +#define NAME_SIZE 24 +#define MAX_RESP_LENGTH 48 + +typedef ssize_t (*show_func)( struct device *dev, + struct device_attribute *attr, + char *buf); +typedef ssize_t (*store_func)(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count); + +enum models { + AS7712_32X, + AS7716_32X, + qfx5210_64X, + AS7312_54X, + PLAIN_CPLD, /*No attribute but add i2c addr to the list.*/ + NUM_MODEL +}; + +enum sfp_func { + HAS_SFP = 1<<0 , + HAS_QSFP = 1<<1 , +}; + +enum common_attrs { + CMN_VERSION, + CMN_ACCESS, + CMN_PRESENT_ALL, + NUM_COMMON_ATTR +}; + +enum sfp_attrs { + SFP_PRESENT, + SFP_RESET, + SFP_LP_MODE, + NUM_SFP_ATTR +}; + +struct cpld_sensor { + struct cpld_sensor *next; + char name[NAME_SIZE+1]; /* sysfs sensor name */ + struct device_attribute attribute; + bool update; /* runtime sensor update needed */ + int data; /* Sensor data. Negative if there was a read error */ + + u8 reg; /* register */ + u8 mask; /* bit mask */ + bool invert; /* inverted value*/ + +}; + +#define to_cpld_sensor(_attr) \ + container_of(_attr, struct cpld_sensor, attribute) + +struct cpld_data { + struct device *dev; + struct device *hwmon_dev; + + int num_attributes; + struct attribute_group group; + + enum models model; + struct cpld_sensor *sensors; + struct mutex update_lock; + bool valid; + unsigned long last_updated; /* in jiffies */ + + int attr_index; + u16 sfp_num; + u8 sfp_types; + struct model_attrs *cmn_attr; +}; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + + +struct base_attrs { + const char *name; + umode_t mode; + show_func get; + store_func set; +}; + +struct attrs { + int reg; + bool invert; + struct base_attrs *base; +}; + +struct model_attrs { + struct attrs **cmn; + struct attrs **portly; +}; + + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t show_presnet_all(struct device *dev, + struct device_attribute *devattr, char *buf); +static ssize_t set_1bit(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_byte(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg); +int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + + +struct base_attrs common_attrs[NUM_COMMON_ATTR] = +{ + [CMN_VERSION] = {"version", S_IRUGO, show_bit, NULL}, + [CMN_ACCESS] = {"access", S_IWUSR, NULL, set_byte}, + [CMN_PRESENT_ALL] = {"module_present_all", S_IRUGO, show_presnet_all, NULL}, +}; + +struct attrs as7712_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]}, +}; +struct attrs qfx5210_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {0x30, false, &common_attrs[CMN_PRESENT_ALL]}, +}; +struct attrs as7312_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, + [CMN_ACCESS] = {0x00, false, &common_attrs[CMN_ACCESS]}, + [CMN_PRESENT_ALL] = {-1, false, &common_attrs[CMN_PRESENT_ALL]}, +}; +struct attrs plain_common[] = { + [CMN_VERSION] = {0x01, false, &common_attrs[CMN_VERSION]}, +}; + +struct base_attrs portly_attrs[] = +{ + [SFP_PRESENT] = {"module_present", S_IRUGO, show_bit, NULL}, + // Only root user will have the privilege to write to sysfs + // [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUGO, show_bit, set_1bit}, + [SFP_RESET] = {"module_reset", S_IRUGO|S_IWUSR, show_bit, set_1bit}, +}; + +struct attrs as7712_port[] = { + {0x30, true, &portly_attrs[SFP_PRESENT]}, + {0x04, true, &portly_attrs[SFP_RESET]}, +}; + +struct attrs qfx5210_port[] = { + {0x70, true, &portly_attrs[SFP_PRESENT]}, + {0x40, true, &portly_attrs[SFP_RESET]}, +}; + +struct attrs *as7712_cmn_list[] = { + &as7712_common[CMN_VERSION], + &as7712_common[CMN_ACCESS], + &as7712_common[CMN_PRESENT_ALL], + NULL +}; + +struct attrs *qfx5210_cmn_list[] = { + &qfx5210_common[CMN_VERSION], + &qfx5210_common[CMN_ACCESS], + &qfx5210_common[CMN_PRESENT_ALL], + NULL +}; + +struct attrs *as7312_cmn_list[] = { + &as7312_common[CMN_VERSION], + &as7312_common[CMN_ACCESS], + &as7312_common[CMN_PRESENT_ALL], + NULL +}; + +struct attrs *plain_cmn_list[] = { + &plain_common[CMN_VERSION], + NULL +}; + +struct attrs *as7712_port_list[] = { + &as7712_port[SFP_PRESENT], + &as7712_port[SFP_RESET], + NULL +}; +struct attrs *qfx5210_port_list[] = { + &qfx5210_port[SFP_PRESENT], + &qfx5210_port[SFP_RESET], + NULL +}; + +struct model_attrs models_attr[NUM_MODEL] = { + {.cmn = as7712_cmn_list, .portly=as7712_port_list}, + {.cmn = as7712_cmn_list, .portly=as7712_port_list}, /*7716's as 7712*/ + {.cmn = qfx5210_cmn_list, .portly=qfx5210_port_list}, + {.cmn = as7312_cmn_list, .portly=qfx5210_port_list}, + {.cmn = plain_cmn_list, .portly=NULL}, +}; + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; +/* Addresses scanned for juniper_i2c_cpld + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static int get_sfp_spec(int model, u16 *num, u8 *types) +{ + switch (model) { + case AS7712_32X: + case AS7716_32X: + *num = 32; + *types = HAS_QSFP; + break; + case qfx5210_64X: + *num = 64; + *types = HAS_QSFP; + break; + case AS7312_54X: + *num = 54; + *types = HAS_QSFP|HAS_SFP; + default: + *types = 0; + *num = 0; + break; + } + + return 0; +} + +static int get_present_reg(int model, u8 port, u8 *cpld_addr, u8 *reg, u8 *num) +{ + u8 cpld_address[] = CPLD_ADDRS; + + switch (model) { + case AS7312_54X: + if (port < 48) { + *cpld_addr = cpld_address[1 + port/24]; + *reg = 0x09 + (port%24)/8; + *num = 8; + } + else + { + *reg = 0x18; + *num = 4; + *cpld_addr = ( port < 52)? cpld_address[1]: cpld_address[2]; + } + break; + default: + return -EINVAL; + } +} + + +/*Assume the bits for ports are listed in-a-row.*/ +static int get_reg_bit(u8 reg_start, int port, + u8 *reg ,u8 *mask) +{ + *reg = reg_start + ((port)/8); + *mask = 1 << ((port)%8); + + return 0; +} + +static int cpld_write_internal( + struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + + +/*Turn a numberic array into string with " " between each element. + * e.g., {0x11, 0x33, 0xff, 0xf1} => "11 33 ff f1" + */ +static ssize_t array_stringify(char *buf, u8 *input, size_t size) { + + int i; + char t[MAX_RESP_LENGTH+1]; + + buf[0] = '\0'; + for (i = 0; i < size; i++) { + snprintf(t, MAX_RESP_LENGTH, "%x ", input[i]); + strncat(buf, t, MAX_RESP_LENGTH); + } + + if (strlen(buf) > 0) + buf[strlen(buf)-1] = '\0'; /*Remove tailing blank*/ + + return snprintf(buf, MAX_RESP_LENGTH, "%s\n", buf); +} + +static ssize_t show_presnet_all_distinct(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + u8 i, value, reg; + u8 cpld_addr, num; + u8 _value[8]; + u64 *values = (u64 *)_value; + + values = 0; + mutex_lock(&data->update_lock); + while(i < data->sfp_num) + { + get_present_reg(data->model, i, &cpld_addr, ®, &num); + if(cpld_addr == client->addr) + value = cpld_read_internal(client, reg); + else + value = juniper_i2c_cpld_read(cpld_addr, reg); + + if (unlikely(value < 0)) { + goto exit; + } + + *values |= (value&((1<<(num))-1)) << i; + i += num; + } + mutex_unlock(&data->update_lock); + + *values = cpu_to_le64(*values); + return array_stringify(buf, _value, i); +exit: + mutex_unlock(&data->update_lock); + return value; +} + +static ssize_t show_presnet_all(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + u8 i, values[MAX_RESP_LENGTH/8]; + + if (sensor->reg < 0) { + return show_presnet_all_distinct(dev, devattr, buf); + } + + mutex_lock(&data->update_lock); + for (i = 0; i < ((data->sfp_num+7)/8); i++) { + values[i] = cpld_read_internal(client, sensor->reg + i); + if (unlikely(values[i] < 0)) { + goto exit; + } + } + mutex_unlock(&data->update_lock); + return array_stringify(buf, values, i); + +exit: + mutex_unlock(&data->update_lock); + return values[i]; +} + +static ssize_t show_bit(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int value; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, sensor->reg); + value = value & sensor->mask; + if (sensor->invert) + value = !value; + mutex_unlock(&data->update_lock); + + return snprintf(buf, PAGE_SIZE, "%x\n", value); +} + +static ssize_t set_1bit(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + long is_reset; + int value, status; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + struct cpld_sensor *sensor = to_cpld_sensor(devattr); + u8 cpld_bit, reg; + + status = kstrtol(buf, 10, &is_reset); + if (status) { + return status; + } + reg = sensor->reg; + cpld_bit = sensor->mask; + mutex_lock(&data->update_lock); + value = cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + if (sensor->invert) + is_reset = !is_reset; + + if (is_reset) { + value |= cpld_bit; + } + else { + value &= ~cpld_bit; + } + + status = cpld_write_internal(client, reg, value); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_byte(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + return access(dev, da, buf, count); +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void juniper_i2c_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = + kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", + client->addr); + return; + } + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void juniper_i2c_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static int cpld_add_attribute(struct cpld_data *data, struct attribute *attr) +{ + int new_max_attrs = ++data->num_attributes + ATTR_ALLOC_SIZE; + void *new_attrs = krealloc(data->group.attrs, + new_max_attrs * sizeof(void *), + GFP_KERNEL); + if (!new_attrs) + return -ENOMEM; + data->group.attrs = new_attrs; + + + data->group.attrs[data->num_attributes-1] = attr; + data->group.attrs[data->num_attributes] = NULL; + + return 0; +} + +static void cpld_dev_attr_init(struct device_attribute *dev_attr, + const char *name, umode_t mode, + show_func show, store_func store) +{ + sysfs_attr_init(&dev_attr->attr); + dev_attr->attr.name = name; + dev_attr->attr.mode = mode; + dev_attr->show = show; + dev_attr->store = store; +} + +static struct cpld_sensor * add_sensor(struct cpld_data *data, + const char *name, + u8 reg, u8 mask, bool invert, + bool update, umode_t mode, + show_func get, store_func set) +{ + struct cpld_sensor *sensor; + struct device_attribute *a; + + sensor = devm_kzalloc(data->dev, sizeof(*sensor), GFP_KERNEL); + if (!sensor) + return NULL; + a = &sensor->attribute; + + snprintf(sensor->name, sizeof(sensor->name), name); + sensor->reg = reg; + sensor->mask = mask; + sensor->update = update; + sensor->invert = invert; + cpld_dev_attr_init(a, sensor->name, + mode, + get, set); + + if (cpld_add_attribute(data, &a->attr)) + return NULL; + + sensor->next = data->sensors; + data->sensors = sensor; + + return sensor; +} + +static int add_attributes_cmn(struct cpld_data *data, struct attrs **cmn) +{ + u8 reg, i ; + bool invert; + struct attrs *a; + struct base_attrs *b; + + if (NULL == cmn) + return -1; + + for (i = 0; cmn[i]; i++) + { + a = cmn[i]; + + reg = a->reg; + invert = a->invert; + + b = a->base; + if (NULL == b) + break; + + if (add_sensor(data, b->name, + reg, 0xff, invert, + true, b->mode, + b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + return 0; +} + +static int add_attributes_portly(struct cpld_data *data, struct attrs **pa) +{ + char name[NAME_SIZE+1]; + int i, j; + u8 reg, mask, invert; + struct attrs *a; + struct base_attrs *b; + + if (NULL == pa) + return -1; + + + for (i = 0; pa[i]; i++) { + a = pa[i]; + + invert = a->invert; + b = a->base; + if (b == NULL) + break; + + for (j = 0; j < data->sfp_num; j++) + { + snprintf(name, NAME_SIZE, "%s_%d", b->name, j+1); + get_reg_bit(a->reg, j, ®, &mask); + + if (add_sensor(data, name, reg, mask, invert, + true, b->mode, b->get, b->set) == NULL) + { + return -ENOMEM; + } + } + } + return 0; +} + +static int add_attributes(struct i2c_client *client, + struct cpld_data *data) +{ + struct model_attrs *m = data->cmn_attr; + + if (m == NULL) + return -EINVAL; + + /* Common attributes.*/ + add_attributes_cmn(data, m->cmn); + + /* Port-wise attributes.*/ + add_attributes_portly(data, m->portly); + + return 0; +} + +static int juniper_i2c_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + struct cpld_data *data = NULL; + struct device *dev = &client->dev; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + dev_dbg(dev, "i2c_check_functionality failed (0x%x)\n", client->addr); + return -EIO; + } + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + + data->model = dev_id->driver_data; + data->cmn_attr = &models_attr[data->model]; + get_sfp_spec(data->model, &data->sfp_num, &data->sfp_types); + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->dev = dev; + dev_info(dev, "chip found\n"); + + status = add_attributes(client, data); + if (status) + goto out_kfree; + + /* + * If there are no attributes, something is wrong. + * Bail out instead of trying to register nothing. + */ + if (!data->num_attributes) { + dev_err(dev, "No attributes found\n"); + status = -ENODEV; + goto out_kfree; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &data->group); + if (status) { + goto out_kfree; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + juniper_i2c_cpld_add_client(client); + dev_info(dev, "%s: cpld '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; +exit_remove: + sysfs_remove_group(&client->dev.kobj, &data->group); +out_kfree: + kfree(data->group.attrs); + return status; + +} + +static int juniper_i2c_cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &data->group); + kfree(data->group.attrs); + juniper_i2c_cpld_remove_client(client); + return 0; +} + +int juniper_i2c_cpld_read(u8 cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_read_byte_data(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(juniper_i2c_cpld_read); + +int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(juniper_i2c_cpld_write); + + +static const struct i2c_device_id juniper_i2c_cpld_id[] = { + { "cpld_as7712", AS7712_32X}, + { "cpld_as7716", AS7716_32X}, + { "cpld_qfx5210", qfx5210_64X}, + { "cpld_as7312", AS7312_54X}, + { "cpld_plain", PLAIN_CPLD}, + { }, +}; +MODULE_DEVICE_TABLE(i2c, juniper_i2c_cpld_id); + +static struct i2c_driver juniper_i2c_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "juniper_i2c_cpld", + }, + .probe = juniper_i2c_cpld_probe, + .remove = juniper_i2c_cpld_remove, + .id_table = juniper_i2c_cpld_id, + .address_list = normal_i2c, +}; + + +static int __init juniper_i2c_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&juniper_i2c_cpld_driver); +} + +static void __exit juniper_i2c_cpld_exit(void) +{ + i2c_del_driver(&juniper_i2c_cpld_driver); +} + +module_init(juniper_i2c_cpld_init); +module_exit(juniper_i2c_cpld_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("juniper_i2c_cpld driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-juniper/common/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-juniper/common/modules/ym2651y.c new file mode 100644 index 000000000000..3ade5684107a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/common/modules/ym2651y.c @@ -0,0 +1,622 @@ +/* + * An hwmon driver for the 3Y Power YM-2651Y Power Module + * + * Tested and validated on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_FAN_DUTY_CYCLE 100 + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END }; + +enum chips { + YM2651, + YM2401, + YM2851, +}; + +/* Each client has this additional data + */ +struct ym2651y_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 capability; /* Register value */ + u16 status_word; /* Register value */ + u8 fan_fault; /* Register value */ + u8 over_temp; /* Register value */ + u16 v_out; /* Register value */ + u16 i_out; /* Register value */ + u16 p_out; /* Register value */ + u16 temp; /* Register value */ + u16 fan_speed; /* Register value */ + u16 fan_duty_cycle[2]; /* Register value */ + u8 fan_dir[4]; /* Register value */ + u8 pmbus_revision; /* Register value */ + u8 mfr_id[10]; /* Register value */ + u8 mfr_model[10]; /* Register value */ + u8 mfr_revsion[3]; /* Register value */ + u16 mfr_vin_min; /* Register value */ + u16 mfr_vin_max; /* Register value */ + u16 mfr_iin_max; /* Register value */ + u16 mfr_iout_max; /* Register value */ + u16 mfr_pin_max; /* Register value */ + u16 mfr_pout_max; /* Register value */ + u16 mfr_vout_min; /* Register value */ + u16 mfr_vout_max; /* Register value */ +}; + +static ssize_t show_byte(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_word(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf); +static struct ym2651y_data *ym2651y_update_device(struct device *dev); +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); + +enum ym2651y_sysfs_attributes { + PSU_POWER_ON = 0, + PSU_TEMP_FAULT, + PSU_POWER_GOOD, + PSU_FAN1_FAULT, + PSU_FAN_DIRECTION, + PSU_OVER_TEMP, + PSU_V_OUT, + PSU_I_OUT, + PSU_P_OUT, + PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/ + PSU_TEMP1_INPUT, + PSU_FAN1_SPEED, + PSU_FAN1_DUTY_CYCLE, + PSU_PMBUS_REVISION, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_REVISION, + PSU_MFR_VIN_MIN, + PSU_MFR_VIN_MAX, + PSU_MFR_VOUT_MIN, + PSU_MFR_VOUT_MAX, + PSU_MFR_IIN_MAX, + PSU_MFR_IOUT_MAX, + PSU_MFR_PIN_MAX, + PSU_MFR_POUT_MAX +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_power_on, S_IRUGO, show_word, NULL, PSU_POWER_ON); +static SENSOR_DEVICE_ATTR(psu_temp_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_word, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_fan1_fault, S_IRUGO, show_fan_fault, NULL, PSU_FAN1_FAULT); +static SENSOR_DEVICE_ATTR(psu_over_temp, S_IRUGO, show_over_temp, NULL, PSU_OVER_TEMP); +static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_linear, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); +static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION); +static SENSOR_DEVICE_ATTR(psu_pmbus_revision, S_IRUGO, show_byte, NULL, PSU_PMBUS_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_id, S_IRUGO, show_ascii, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MFR_REVISION); +static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); + +/*Duplicate nodes for lm-sensors.*/ +static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_linear, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV); +static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); + +static struct attribute *ym2651y_attributes[] = { + &sensor_dev_attr_psu_power_on.dev_attr.attr, + &sensor_dev_attr_psu_temp_fault.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_fan1_fault.dev_attr.attr, + &sensor_dev_attr_psu_over_temp.dev_attr.attr, + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, + &sensor_dev_attr_psu_fan_dir.dev_attr.attr, + &sensor_dev_attr_psu_pmbus_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_id.dev_attr.attr, + &sensor_dev_attr_psu_mfr_model.dev_attr.attr, + &sensor_dev_attr_psu_mfr_revision.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vin_min.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_pout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_iin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_pin_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, + &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, + &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, + /*Duplicate nodes for lm-sensors.*/ + &sensor_dev_attr_curr2_input.dev_attr.attr, + &sensor_dev_attr_in3_input.dev_attr.attr, + &sensor_dev_attr_power2_input.dev_attr.attr, + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_fan1_input.dev_attr.attr, + &sensor_dev_attr_temp1_fault.dev_attr.attr, + NULL +}; + +static ssize_t show_byte(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : + sprintf(buf, "0\n"); +} + +static ssize_t show_word(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u16 status = 0; + + switch (attr->index) { + case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ + status = (data->status_word & 0x40) ? 0 : 1; + break; + case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ + status = (data->status_word & 0x4) >> 2; + break; + case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ + status = (data->status_word & 0x800) ? 0 : 1; + break; + } + + return sprintf(buf, "%d\n", status); +} + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + int nr = (attr->index == PSU_FAN1_DUTY_CYCLE) ? 0 : 1; + long speed; + int error; + + error = kstrtol(buf, 10, &speed); + if (error) + return error; + + if (speed < 0 || speed > MAX_FAN_DUTY_CYCLE) + return -EINVAL; + + mutex_lock(&data->update_lock); + data->fan_duty_cycle[nr] = speed; + ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + mutex_unlock(&data->update_lock); + + return count; +} + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + switch (attr->index) { + case PSU_V_OUT: + value = data->v_out; + break; + case PSU_I_OUT: + value = data->i_out; + break; + case PSU_P_OUT_UV: + multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/ + /*Passing through*/ + case PSU_P_OUT: + value = data->p_out; + break; + case PSU_TEMP1_INPUT: + value = data->temp; + break; + case PSU_FAN1_SPEED: + value = data->fan_speed; + multiplier = 1; + break; + case PSU_FAN1_DUTY_CYCLE: + value = data->fan_duty_cycle[0]; + multiplier = 1; + break; + case PSU_MFR_VIN_MIN: + value = data->mfr_vin_min; + break; + case PSU_MFR_VIN_MAX: + value = data->mfr_vin_max; + break; + case PSU_MFR_VOUT_MIN: + value = data->mfr_vout_min; + break; + case PSU_MFR_VOUT_MAX: + value = data->mfr_vout_max; + break; + case PSU_MFR_PIN_MAX: + value = data->mfr_pin_max; + break; + case PSU_MFR_POUT_MAX: + value = data->mfr_pout_max; + break; + case PSU_MFR_IOUT_MAX: + value = data->mfr_iout_max; + break; + case PSU_MFR_IIN_MAX: + value = data->mfr_iin_max; + break; + } + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + + u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + + return sprintf(buf, "%d\n", data->fan_fault >> shift); +} + +static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct ym2651y_data *data = ym2651y_update_device(dev); + + return sprintf(buf, "%d\n", data->over_temp >> 7); +} + +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct ym2651y_data *data = ym2651y_update_device(dev); + u8 *ptr = NULL; + + switch (attr->index) { + case PSU_FAN_DIRECTION: /* psu_fan_dir */ + ptr = data->fan_dir; + break; + case PSU_MFR_ID: /* psu_mfr_id */ + ptr = data->mfr_id; + break; + case PSU_MFR_MODEL: /* psu_mfr_model */ + ptr = data->mfr_model; + break; + case PSU_MFR_REVISION: /* psu_mfr_revision */ + ptr = data->mfr_revsion; + break; + default: + return 0; + } + + return sprintf(buf, "%s\n", ptr); +} + +static const struct attribute_group ym2651y_group = { + .attrs = ym2651y_attributes, +}; + +static int ym2651y_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct ym2651y_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct ym2651y_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &ym2651y_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &ym2651y_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int ym2651y_remove(struct i2c_client *client) +{ + struct ym2651y_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &ym2651y_group); + kfree(data); + + return 0; +} + +static const struct i2c_device_id ym2651y_id[] = { + { "ym2651", YM2651 }, + { "ym2401", YM2401 }, + { "ym2851", YM2851 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, ym2651y_id); + +static struct i2c_driver ym2651y_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "ym2651", + }, + .probe = ym2651y_probe, + .remove = ym2651y_remove, + .id_table = ym2651y_id, + .address_list = normal_i2c, +}; + +static int ym2651y_read_byte(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int ym2651y_read_word(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_word_data(client, reg); +} + +static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) +{ + return i2c_smbus_write_word_data(client, reg, value); +} + +static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + + if (unlikely(result < 0)) + goto abort; + if (unlikely(result != data_len)) { + result = -EIO; + goto abort; + } + + result = 0; + +abort: + return result; +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + +static struct ym2651y_data *ym2651y_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i, status; + u8 command; + u8 fan_dir[5] = {0}; + struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, + {0x7d, &data->over_temp}, + {0x81, &data->fan_fault}, + {0x98, &data->pmbus_revision} + }; + struct reg_data_word regs_word[] = { {0x79, &data->status_word}, + {0x8b, &data->v_out}, + {0x8c, &data->i_out}, + {0x96, &data->p_out}, + {0x8d, &data->temp}, + {0x3b, &(data->fan_duty_cycle[0])}, + {0x3c, &(data->fan_duty_cycle[1])}, + {0x90, &data->fan_speed}, + {0xa0, &data->mfr_vin_min}, + {0xa1, &data->mfr_vin_max}, + {0xa2, &data->mfr_iin_max}, + {0xa3, &data->mfr_pin_max}, + {0xa4, &data->mfr_vout_min}, + {0xa5, &data->mfr_vout_max}, + {0xa6, &data->mfr_iout_max}, + {0xa7, &data->mfr_pout_max} + }; + + dev_dbg(&client->dev, "Starting ym2651 update\n"); + + /* Read byte data */ + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = ym2651y_read_byte(client, regs_byte[i].reg); + + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + } + else { + *(regs_byte[i].value) = status; + } + } + + /* Read word data */ + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + status = ym2651y_read_word(client, regs_word[i].reg); + + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + *(regs_word[i].value) = 0; + } + else { + *(regs_word[i].value) = status; + } + } + + /* Read fan_direction */ + command = 0xC3; + status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + } + + strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); + data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + + /* Read mfr_id */ + command = 0x99; + status = ym2651y_read_block(client, command, data->mfr_id, + ARRAY_SIZE(data->mfr_id)-1); + data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; + + if (status < 0) + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + + /* Read mfr_model */ + command = 0x9a; + status = ym2651y_read_block(client, command, data->mfr_model, + ARRAY_SIZE(data->mfr_model)-1); + data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; + + if (status < 0) + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + + /* Read mfr_revsion */ + command = 0x9b; + status = ym2651y_read_block(client, command, data->mfr_revsion, + ARRAY_SIZE(data->mfr_revsion)-1); + data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; + + if (status < 0) + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +module_i2c_driver(ym2651y_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); +MODULE_LICENSE("GPL"); + + diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/changelog b/platform/broadcom/sonic-platform-modules-juniper/debian/changelog new file mode 100755 index 000000000000..bc640fa563af --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/changelog @@ -0,0 +1,6 @@ +sonic-juniper-platform-modules (1.1) unstable; urgency=low + + * Initial release: Add support for QFX5210. + -- Juniper Networks + Ciju Rajan K Tue, 30 July 2019 + diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/compat b/platform/broadcom/sonic-platform-modules-juniper/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/compat @@ -0,0 +1 @@ +9 diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/control b/platform/broadcom/sonic-platform-modules-juniper/debian/control new file mode 100755 index 000000000000..c9310069f9f9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/control @@ -0,0 +1,11 @@ +Source: sonic-juniper-platform-modules +Section: main +Priority: extra +Maintainer: Juniper Networks +Build-Depends: debhelper (>= 9), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-juniper-qfx5210 +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp + diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/files b/platform/broadcom/sonic-platform-modules-juniper/debian/files new file mode 100644 index 000000000000..24ef0ffef22b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/files @@ -0,0 +1,2 @@ +sonic-juniper-platform-modules_1.1_amd64.buildinfo main extra +sonic-platform-juniper-qfx5210_1.1_amd64.deb main extra diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/rules b/platform/broadcom/sonic-platform-modules-juniper/debian/rules new file mode 100755 index 000000000000..2be5594acd3d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/rules @@ -0,0 +1,86 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +include /usr/share/dpkg/pkg-info.mk + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export INSTALL_MOD_DIR:=extra + +PYTHON ?= python2 + +PACKAGE_PRE_NAME := sonic-platform-juniper +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +MODULE_DIRS:= qfx5210 +MODULE_DIR := modules +UTILS_DIR := utils +SERVICE_DIR := service +PLATFORM_DIR := sonic_platform +CONF_DIR := conf + +%: + dh $@ --with systemd,python2,python3 --buildsystem=pybuild + +clean: + dh_testdir + dh_testroot + dh_clean + +build: + #make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC) + (for mod in $(MODULE_DIRS); do \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules || exit 1; \ + $(PYTHON) $${mod}/setup.py build; \ + done) + +binary: binary-arch binary-indep + # Nothing to do + +binary-arch: + # Nothing to do + +#install: build + #dh_testdir + #dh_testroot + #dh_clean -k + #dh_installdirs + +binary-indep: + dh_testdir + dh_installdirs + + # Custom package commands + (for mod in $(MODULE_DIRS); do \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/local/bin; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /lib/systemd/system; \ + cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ + $(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + done) + # Resuming debhelper scripts + dh_testroot + dh_install + dh_installchangelogs + dh_installdocs + dh_systemd_enable + dh_installinit + dh_systemd_start + dh_link + dh_fixperms + dh_compress + dh_strip + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +.PHONY: build binary binary-arch binary-indep clean diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.install b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.install new file mode 100644 index 000000000000..db8c036fdd0d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.install @@ -0,0 +1,4 @@ +qfx5210/utils/juniper_qfx5210_util.py usr/local/bin +qfx5210/utils/juniper_qfx5210_monitor.py usr/local/bin +qfx5210/utils/platform_poweroff usr/local/bin +qfx5210/service/qfx5210-platform-init.service etc/systemd/system diff --git a/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst new file mode 100644 index 000000000000..1b00ceb568e6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/debian/sonic-platform-juniper-qfx5210.postinst @@ -0,0 +1,2 @@ +systemctl enable qfx5210-platform-init.service +systemctl start qfx5210-platform-init.service diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/Makefile b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/Makefile new file mode 100644 index 000000000000..85f96f1dd83d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/Makefile @@ -0,0 +1,2 @@ +obj-m:=x86-64-juniper-qfx5210-64x-fan.o x86-64-juniper-qfx5210-64x-sfp.o x86-64-juniper-qfx5210-64x-leds.o \ + x86-64-juniper-qfx5210-64x-psu.o juniper_i2c_cpld.o ym2651y.o diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c new file mode 120000 index 000000000000..843ce05a4313 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/juniper_i2c_cpld.c @@ -0,0 +1 @@ +../../common/modules/juniper_i2c_cpld.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-fan.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-fan.c new file mode 100644 index 000000000000..3e9b67a5da63 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-fan.c @@ -0,0 +1,470 @@ +/* + * A hwmon driver for the juniper qfx5210-64x fan + * + * Modified and tested to work on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2014 juniper Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "qfx5210_64x_fan" + +static struct qfx5210_64x_fan_data *qfx5210_64x_fan_update_device(struct device *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x80, /* fan 1-4 present status */ + 0x81, /* fan 1-4 direction(0:F2B 1:B2F) */ + 0x87, /* fan PWM(for all fan) */ + 0x90, /* front fan 1 speed(rpm) */ + 0x91, /* front fan 2 speed(rpm) */ + 0x92, /* front fan 3 speed(rpm) */ + 0x93, /* front fan 4 speed(rpm) */ + 0x98, /* rear fan 1 speed(rpm) */ + 0x99, /* rear fan 2 speed(rpm) */ + 0x9A, /* rear fan 3 speed(rpm) */ + 0x9B, /* rear fan 4 speed(rpm) */ +}; + +/* Each client has this additional data */ +struct qfx5210_64x_fan_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ +}; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID +}; + +enum sysfs_fan_attributes { + FAN_PRESENT_REG, + FAN_DIRECTION_REG, + FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ + FAN1_FRONT_SPEED_RPM, + FAN2_FRONT_SPEED_RPM, + FAN3_FRONT_SPEED_RPM, + FAN4_FRONT_SPEED_RPM, + FAN1_REAR_SPEED_RPM, + FAN2_REAR_SPEED_RPM, + FAN3_REAR_SPEED_RPM, + FAN4_REAR_SPEED_RPM, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN4_FAULT +}; + +/* Define attributes + */ +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT);\ + static SENSOR_DEVICE_ATTR(fan##index2##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index, index2) &sensor_dev_attr_fan##index##_fault.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_fault.dev_attr.attr + +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IRUGO, fan_show_value, NULL, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN_DUTY_CYCLE_PERCENTAGE);\ + static SENSOR_DEVICE_ATTR(pwm##index, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN_DUTY_CYCLE_PERCENTAGE) + +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan_duty_cycle_percentage.dev_attr.attr, \ + &sensor_dev_attr_pwm##index.dev_attr.attr + + +#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT) +#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr + +#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_front_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_rear_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index2##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM) +#define DECLARE_FAN_SPEED_RPM_ATTR(index, index2) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_input.dev_attr.attr + +/* 6 fan fault attributes in this platform */ +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1,11); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2,12); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3,13); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4,14); +/* 6 fan speed(rpm) attributes in this platform */ +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1,11); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2,12); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3,13); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4,14); +/* 6 fan present attributes in this platform */ +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); +/* 6 fan direction attribute in this platform */ +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +/* 1 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1); + +static struct attribute *qfx5210_64x_fan_attributes[] = { + /* fan related attributes */ + DECLARE_FAN_FAULT_ATTR(1,11), + DECLARE_FAN_FAULT_ATTR(2,12), + DECLARE_FAN_FAULT_ATTR(3,13), + DECLARE_FAN_FAULT_ATTR(4,14), + DECLARE_FAN_SPEED_RPM_ATTR(1,11), + DECLARE_FAN_SPEED_RPM_ATTR(2,12), + DECLARE_FAN_SPEED_RPM_ATTR(3,13), + DECLARE_FAN_SPEED_RPM_ATTR(4,14), + DECLARE_FAN_PRESENT_ATTR(1), + DECLARE_FAN_PRESENT_ATTR(2), + DECLARE_FAN_PRESENT_ATTR(3), + DECLARE_FAN_PRESENT_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DUTY_CYCLE_ATTR(1), + NULL +}; + +#define FAN_DUTY_CYCLE_REG_MASK 0xF +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 100 + +static int qfx5210_64x_fan_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int qfx5210_64x_fan_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + reg_val &= FAN_DUTY_CYCLE_REG_MASK; + + if (!reg_val) { + return 0; + } + + if (reg_val == 0xF) { + return FAN_MAX_DUTY_CYCLE; + } + + return (reg_val * 6) + 10; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + if (duty_cycle < 16) { + return 0; + } + + if (duty_cycle >= 100) { + return 0xF; + } + + return (duty_cycle - 10) / 6; +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << id); + return !!(reg_val & mask); +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + u8 mask = (1 << id); + return !(reg_val & mask); +} + +static u8 is_fan_fault(struct qfx5210_64x_fan_data *data, enum fan_id id) +{ + u8 ret = 1; + int front_fan_index = FAN1_FRONT_SPEED_RPM + id; + int rear_fan_index = FAN1_REAR_SPEED_RPM + id; + + /* Check if the speed of front or rear fan is ZERO, + */ + if (reg_val_to_speed_rpm(data->reg_val[front_fan_index]) && + reg_val_to_speed_rpm(data->reg_val[rear_fan_index])) { + ret = 0; + } + + return ret; +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct i2c_client *client = to_i2c_client(dev); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + if (value > FAN_MAX_DUTY_CYCLE) + value = FAN_MAX_DUTY_CYCLE; + if (value < 0) + return -EINVAL; + + qfx5210_64x_fan_write_value(client, 0x28, 0); /* Disable fan speed watch dog */ + qfx5210_64x_fan_write_value(client, fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); + return count; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct qfx5210_64x_fan_data *data = qfx5210_64x_fan_update_device(dev); + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) { + case FAN_DUTY_CYCLE_PERCENTAGE: + { + u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[FAN_DUTY_CYCLE_PERCENTAGE]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + } + case FAN1_FRONT_SPEED_RPM: + case FAN2_FRONT_SPEED_RPM: + case FAN3_FRONT_SPEED_RPM: + case FAN4_FRONT_SPEED_RPM: + case FAN1_REAR_SPEED_RPM: + case FAN2_REAR_SPEED_RPM: + case FAN3_REAR_SPEED_RPM: + case FAN4_REAR_SPEED_RPM: + { + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + } + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG], + attr->index - FAN1_PRESENT)); + break; + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); + break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + ret = sprintf(buf, "%d\n", + reg_val_to_direction(data->reg_val[FAN_DIRECTION_REG], + attr->index - FAN1_DIRECTION)); + break; + default: + break; + } + } + + return ret; +} + +static const struct attribute_group qfx5210_64x_fan_group = { + .attrs = qfx5210_64x_fan_attributes, +}; + +static struct qfx5210_64x_fan_data *qfx5210_64x_fan_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qfx5210_64x_fan_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting qfx5210_64x_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + int status = qfx5210_64x_fan_read_value(client, fan_reg[i]); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "reg %d, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static int qfx5210_64x_fan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct qfx5210_64x_fan_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct qfx5210_64x_fan_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &qfx5210_64x_fan_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: fan '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &qfx5210_64x_fan_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int qfx5210_64x_fan_remove(struct i2c_client *client) +{ + struct qfx5210_64x_fan_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &qfx5210_64x_fan_group); + + return 0; +} + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static const struct i2c_device_id qfx5210_64x_fan_id[] = { + { "qfx5210_64x_fan", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, qfx5210_64x_fan_id); + +static struct i2c_driver qfx5210_64x_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = qfx5210_64x_fan_probe, + .remove = qfx5210_64x_fan_remove, + .id_table = qfx5210_64x_fan_id, + .address_list = normal_i2c, +}; + +static int __init qfx5210_64x_fan_init(void) +{ + return i2c_add_driver(&qfx5210_64x_fan_driver); +} + +static void __exit qfx5210_64x_fan_exit(void) +{ + i2c_del_driver(&qfx5210_64x_fan_driver); +} + +module_init(qfx5210_64x_fan_init); +module_exit(qfx5210_64x_fan_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("qfx5210_64x_fan driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-leds.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-leds.c new file mode 100644 index 000000000000..66d097734392 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-leds.c @@ -0,0 +1,450 @@ +/* + * LED driver for the qfx5210 + * + * Modified and tested to work on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/*#define DEBUG*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern int juniper_i2c_cpld_read (u8 cpld_addr, u8 reg); +extern int juniper_i2c_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +extern void led_classdev_unregister(struct led_classdev *led_cdev); +extern int led_classdev_register(struct device *parent, struct led_classdev *led_cdev); +extern void led_classdev_resume(struct led_classdev *led_cdev); +extern void led_classdev_suspend(struct led_classdev *led_cdev); + +#define DRVNAME "qfx5210_64x_led" + +struct qfx5210_64x_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[1]; /* only 1 register*/ +}; + +static struct qfx5210_64x_led_data *ledctl = NULL; + +/* + * LED related data + */ + +#define LED_CNTRLER_I2C_ADDRESS (0x60) /* CPLD1 i2c address */ + +#define LED_TYPE_ALARM_REG_MASK (0x03) +#define LED_MODE_ALARM_RED_VALUE (0x01) +#define LED_MODE_ALARM_AMBER_VALUE (0x02) +#define LED_MODE_ALARM_OFF_VALUE (0x00) + +#define LED_TYPE_SYSTEM_REG_MASK (0x0C) +#define LED_MODE_SYSTEM_GREEN_VALUE (0x04) +#define LED_MODE_SYSTEM_GREEN_BLINKING_VALUE (0x08) +#define LED_MODE_SYSTEM_OFF_VALUE (0x00) + +#define LED_TYPE_MASTER_REG_MASK (0x30) +#define LED_MODE_MASTER_GREEN_VALUE (0x10) +#define LED_MODE_MASTER_GREEN_BLINKING_VALUE (0x20) +#define LED_MODE_MASTER_OFF_VALUE (0x00) + +#define LED_TYPE_BEACON_REG_MASK (0xC0) +#define LED_MODE_BEACON_VALUE (0x40) +#define LED_MODE_BEACON_OFF_VALUE (0x00) + +enum led_type { + LED_TYPE_ALARM, + LED_TYPE_SYSTEM, + LED_TYPE_MASTER, + LED_TYPE_BEACON +}; + +struct led_reg { + u32 types; + u8 reg_addr; +}; + +static const struct led_reg led_reg_map[] = { + {(1 << LED_TYPE_ALARM) | (1 << LED_TYPE_SYSTEM) | (1 << LED_TYPE_MASTER) | (1 << LED_TYPE_BEACON), 0x30}, +}; + +enum led_light_mode { + LED_MODE_OFF = 0, + LED_MODE_RED = 1, + LED_MODE_AMBER = 2, + LED_MODE_GREEN = 1, + LED_MODE_GREEN_BLINKING = 2, + LED_MODE_BLUE_BLINKING = 1 +}; + +struct led_type_mode { + enum led_type type; + enum led_light_mode mode; + int reg_bit_mask; + int mode_value; +}; + +static struct led_type_mode led_type_mode_data[] = { + {LED_TYPE_ALARM, LED_MODE_RED, LED_TYPE_ALARM_REG_MASK, LED_MODE_ALARM_RED_VALUE}, + {LED_TYPE_ALARM, LED_MODE_AMBER, LED_TYPE_ALARM_REG_MASK, LED_MODE_ALARM_AMBER_VALUE}, + {LED_TYPE_ALARM, LED_MODE_OFF, LED_TYPE_ALARM_REG_MASK, LED_MODE_ALARM_OFF_VALUE}, + + {LED_TYPE_SYSTEM, LED_MODE_GREEN, LED_TYPE_SYSTEM_REG_MASK, LED_MODE_SYSTEM_GREEN_VALUE}, + {LED_TYPE_SYSTEM, LED_MODE_GREEN_BLINKING, LED_TYPE_SYSTEM_REG_MASK, LED_MODE_SYSTEM_GREEN_BLINKING_VALUE}, + {LED_TYPE_SYSTEM, LED_MODE_OFF, LED_TYPE_SYSTEM_REG_MASK, LED_MODE_SYSTEM_OFF_VALUE}, + + {LED_TYPE_MASTER, LED_MODE_GREEN, LED_TYPE_MASTER_REG_MASK, LED_MODE_MASTER_GREEN_VALUE}, + {LED_TYPE_MASTER, LED_MODE_GREEN_BLINKING, LED_TYPE_MASTER_REG_MASK, LED_MODE_MASTER_GREEN_BLINKING_VALUE}, + {LED_TYPE_MASTER, LED_MODE_OFF, LED_TYPE_MASTER_REG_MASK, LED_MODE_MASTER_OFF_VALUE}, + + {LED_TYPE_BEACON, LED_MODE_BLUE_BLINKING, LED_TYPE_BEACON_REG_MASK, LED_MODE_BEACON_VALUE}, + {LED_TYPE_BEACON, LED_MODE_OFF, LED_TYPE_BEACON_REG_MASK, LED_MODE_BEACON_OFF_VALUE} +}; + +static int get_led_reg(enum led_type type, u8 *reg) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(led_reg_map); i++) { + if(led_reg_map[i].types & (1 << type)) { + *reg = led_reg_map[i].reg_addr; + return 0; + } + } + + return 1; +} + +static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + + if (type != led_type_mode_data[i].type) + continue; + + if ((led_type_mode_data[i].reg_bit_mask & reg_val) == + led_type_mode_data[i].mode_value) + { + return led_type_mode_data[i].mode; + } + } + + return 0; +} + +static u8 led_light_mode_to_reg_val(enum led_type type, + enum led_light_mode mode, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + reg_val = led_type_mode_data[i].mode_value | + (reg_val & (~led_type_mode_data[i].reg_bit_mask)); + break; + } + + return reg_val; +} + +static int qfx5210_64x_led_read_value(u8 reg) +{ + return juniper_i2c_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); +} + +static int qfx5210_64x_led_write_value(u8 reg, u8 value) +{ + return juniper_i2c_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); +} + +static void qfx5210_64x_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting qfx5210_64x_led update\n"); + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = qfx5210_64x_led_read_value(led_reg_map[i].reg_addr); + + if (status < 0) { + ledctl->valid = 0; + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg_map[i].reg_addr, status); + goto exit; + } + else + { + ledctl->reg_val[i] = status; + } + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void qfx5210_64x_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + enum led_type type) +{ + int reg_val; + u8 reg ; + mutex_lock(&ledctl->update_lock); + + if( !get_led_reg(type, ®)) { + dev_dbg(&ledctl->pdev->dev, "Not match register for %d.\n", type); + } + + reg_val = qfx5210_64x_led_read_value(reg); + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + qfx5210_64x_led_write_value(reg, reg_val); + + /* to prevent the slow-update issue */ + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + + +static void qfx5210_64x_led_system_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + qfx5210_64x_led_set(led_cdev, led_light_mode, LED_TYPE_SYSTEM); +} + +static enum led_brightness qfx5210_64x_led_system_get(struct led_classdev *cdev) +{ + qfx5210_64x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_SYSTEM, ledctl->reg_val[0]); +} + +static void qfx5210_64x_led_master_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + qfx5210_64x_led_set(led_cdev, led_light_mode, LED_TYPE_MASTER); +} + +static enum led_brightness qfx5210_64x_led_master_get(struct led_classdev *cdev) +{ + qfx5210_64x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_MASTER, ledctl->reg_val[0]); +} + +static void qfx5210_64x_led_alarm_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + qfx5210_64x_led_set(led_cdev, led_light_mode, LED_TYPE_ALARM); +} + +static enum led_brightness qfx5210_64x_led_alarm_get(struct led_classdev *cdev) +{ + qfx5210_64x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_ALARM, ledctl->reg_val[0]); +} + +static void qfx5210_64x_led_beacon_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + qfx5210_64x_led_set(led_cdev, led_light_mode, LED_TYPE_BEACON); +} + +static enum led_brightness qfx5210_64x_led_beacon_get(struct led_classdev *cdev) +{ + qfx5210_64x_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_BEACON, ledctl->reg_val[0]); +} + +static struct led_classdev qfx5210_64x_leds[] = { + [LED_TYPE_ALARM] = { + .name = "alarm", + .default_trigger = "unused", + .brightness_set = qfx5210_64x_led_alarm_set, + .brightness_get = qfx5210_64x_led_alarm_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_SYSTEM] = { + .name = "system", + .default_trigger = "unused", + .brightness_set = qfx5210_64x_led_system_set, + .brightness_get = qfx5210_64x_led_system_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN_BLINKING, + }, + [LED_TYPE_MASTER] = { + .name = "master", + .default_trigger = "unused", + .brightness_set = qfx5210_64x_led_master_set, + .brightness_get = qfx5210_64x_led_master_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_GREEN_BLINKING, + }, + [LED_TYPE_BEACON] = { + .name = "beacon", + .default_trigger = "unused", + .brightness_set = qfx5210_64x_led_beacon_set, + .brightness_get = qfx5210_64x_led_beacon_get, + .flags = LED_CORE_SUSPENDRESUME, + .max_brightness = LED_MODE_BLUE_BLINKING, + }, +}; + +static int qfx5210_64x_led_suspend(struct platform_device *dev, + pm_message_t state) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(qfx5210_64x_leds); i++) { + led_classdev_suspend(&qfx5210_64x_leds[i]); + } + + return 0; +} + +static int qfx5210_64x_led_resume(struct platform_device *dev) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(qfx5210_64x_leds); i++) { + led_classdev_resume(&qfx5210_64x_leds[i]); + } + + return 0; +} + +static int qfx5210_64x_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(qfx5210_64x_leds); i++) { + ret = led_classdev_register(&pdev->dev, &qfx5210_64x_leds[i]); + + if (ret < 0) + break; + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(qfx5210_64x_leds)){ + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&qfx5210_64x_leds[i]); + } + } + + return ret; +} + +static int qfx5210_64x_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(qfx5210_64x_leds); i++) { + led_classdev_unregister(&qfx5210_64x_leds[i]); + } + + return 0; +} + +static struct platform_driver qfx5210_64x_led_driver = { + .probe = qfx5210_64x_led_probe, + .remove = qfx5210_64x_led_remove, + .suspend = qfx5210_64x_led_suspend, + .resume = qfx5210_64x_led_resume, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init qfx5210_64x_led_init(void) +{ + int ret; + + ret = platform_driver_register(&qfx5210_64x_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct qfx5210_64x_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + platform_driver_unregister(&qfx5210_64x_led_driver); + goto exit; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + platform_driver_unregister(&qfx5210_64x_led_driver); + kfree(ledctl); + goto exit; + } + +exit: + return ret; +} + +static void __exit qfx5210_64x_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&qfx5210_64x_led_driver); + kfree(ledctl); +} + +module_init(qfx5210_64x_led_init); +module_exit(qfx5210_64x_led_exit); + +MODULE_AUTHOR("Ciju Rajan K "); +MODULE_DESCRIPTION("qfx5210_64x_led driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c new file mode 100644 index 000000000000..526e46433ce7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-psu.c @@ -0,0 +1,242 @@ +/* + * An hwmon driver for juniper qfx5210_64x Power Module + * + * Tested and validated on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PSU_STATUS_I2C_ADDR 0x60 +#define PSU_STATUS_I2C_REG_OFFSET 0x03 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(2+id))) +#define IS_PRESENT(id, value) (!(value & BIT(id))) + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static struct qfx5210_64x_psu_data *qfx5210_64x_psu_update_device(struct device *dev); +extern int juniper_i2c_cpld_read (u8 cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct qfx5210_64x_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ +}; + +enum qfx5210_64x_psu_sysfs_attributes { + PSU_PRESENT, + PSU_POWER_GOOD +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); + +static struct attribute *qfx5210_64x_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct qfx5210_64x_psu_data *data = qfx5210_64x_psu_update_device(dev); + u8 status = 0; + + if (!data->valid) { + return -EIO; + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + return sprintf(buf, "%d\n", status); +} + +static const struct attribute_group qfx5210_64x_psu_group = { + .attrs = qfx5210_64x_psu_attributes, +}; + +static int qfx5210_64x_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct qfx5210_64x_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct qfx5210_64x_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &qfx5210_64x_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register(&client->dev); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &qfx5210_64x_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int qfx5210_64x_psu_remove(struct i2c_client *client) +{ + struct qfx5210_64x_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &qfx5210_64x_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + qfx5210_64x_psu1, + qfx5210_64x_psu2 +}; + +static const struct i2c_device_id qfx5210_64x_psu_id[] = { + { "qfx5210_64x_psu1", qfx5210_64x_psu1 }, + { "qfx5210_64x_psu2", qfx5210_64x_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, qfx5210_64x_psu_id); + +static struct i2c_driver qfx5210_64x_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "qfx5210_64x_psu", + }, + .probe = qfx5210_64x_psu_probe, + .remove = qfx5210_64x_psu_remove, + .id_table = qfx5210_64x_psu_id, + .address_list = normal_i2c, +}; + +static struct qfx5210_64x_psu_data *qfx5210_64x_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct qfx5210_64x_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + + data->valid = 0; + dev_dbg(&client->dev, "Starting qfx5210_64x update\n"); + + /* Read psu status */ + status = juniper_i2c_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init qfx5210_64x_psu_init(void) +{ + return i2c_add_driver(&qfx5210_64x_psu_driver); +} + +static void __exit qfx5210_64x_psu_exit(void) +{ + i2c_del_driver(&qfx5210_64x_psu_driver); +} + +module_init(qfx5210_64x_psu_init); +module_exit(qfx5210_64x_psu_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("qfx5210_64x_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-sfp.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-sfp.c new file mode 100644 index 000000000000..0a173965fdf9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/x86-64-juniper-qfx5210-64x-sfp.c @@ -0,0 +1,1579 @@ +/* + * SFP driver for juniper qfx5210_64x sfp + * + * Tested and validated on Juniper QFX5210 + * Ciju Rajan K + * + * Copyright (C) Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "qfx5210_64x_sfp" /* Platform dependent */ + +#define DEBUG_MODE 0 + +#if (DEBUG_MODE == 1) + #define DEBUG_PRINT(fmt, args...) \ + printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) +#endif + +#define NUM_OF_SFP_PORT 24 +#define EEPROM_NAME "sfp_eeprom" +#define EEPROM_SIZE 256 /* 256 byte eeprom */ +#define BIT_INDEX(i) (1ULL << (i)) +#define USE_I2C_BLOCK_READ 1 /* Platform dependent */ +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +#define SFP_EEPROM_A0_I2C_ADDR (0xA0 >> 1) + +#define SFF8024_PHYSICAL_DEVICE_ID_ADDR 0x0 +#define SFF8024_DEVICE_ID_SFP 0x3 +#define SFF8024_DEVICE_ID_QSFP 0xC +#define SFF8024_DEVICE_ID_QSFP_PLUS 0xD +#define SFF8024_DEVICE_ID_QSFP28 0x11 + +#define SFF8436_RX_LOS_ADDR 3 +#define SFF8436_TX_FAULT_ADDR 4 +#define SFF8436_TX_DISABLE_ADDR 86 + +#define MULTIPAGE_SUPPORT 1 + +#if (MULTIPAGE_SUPPORT == 1) +/* fundamental unit of addressing for SFF_8472/SFF_8436 */ +#define SFF_8436_PAGE_SIZE 128 +/* + * The current 8436 (QSFP) spec provides for only 4 supported + * pages (pages 0-3). + * This driver is prepared to support more, but needs a register in the + * EEPROM to indicate how many pages are supported before it is safe + * to implement more pages in the driver. + */ +#define SFF_8436_SPECED_PAGES 4 +#define SFF_8436_EEPROM_SIZE ((1 + SFF_8436_SPECED_PAGES) * SFF_8436_PAGE_SIZE) +#define SFF_8436_EEPROM_UNPAGED_SIZE (2 * SFF_8436_PAGE_SIZE) +/* + * The current 8472 (SFP) spec provides for only 3 supported + * pages (pages 0-2). + * This driver is prepared to support more, but needs a register in the + * EEPROM to indicate how many pages are supported before it is safe + * to implement more pages in the driver. + */ +#define SFF_8472_SPECED_PAGES 3 +#define SFF_8472_EEPROM_SIZE ((3 + SFF_8472_SPECED_PAGES) * SFF_8436_PAGE_SIZE) +#define SFF_8472_EEPROM_UNPAGED_SIZE (4 * SFF_8436_PAGE_SIZE) + +/* a few constants to find our way around the EEPROM */ +#define SFF_8436_PAGE_SELECT_REG 0x7F +#define SFF_8436_PAGEABLE_REG 0x02 +#define SFF_8436_NOT_PAGEABLE (1<<2) +#define SFF_8472_PAGEABLE_REG 0x40 +#define SFF_8472_PAGEABLE (1<<4) + +/* + * This parameter is to help this driver avoid blocking other drivers out + * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C + * clock, one 256 byte read takes about 1/43 second which is excessive; + * but the 1/170 second it takes at 400 kHz may be quite reasonable; and + * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. + * + * This value is forced to be a power of two so that writes align on pages. + */ +static unsigned io_limit = SFF_8436_PAGE_SIZE; + +/* + * specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +static unsigned write_timeout = 25; + +typedef enum qsfp_opcode { + QSFP_READ_OP = 0, + QSFP_WRITE_OP = 1 +} qsfp_opcode_e; +#endif + +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_present(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, const char *buf, size_t count);; +static ssize_t sfp_eeprom_read(struct i2c_client *, u8, u8 *,int); +static ssize_t sfp_eeprom_write(struct i2c_client *, u8 , const char *,int); +extern int juniper_i2c_cpld_read (u8 cpld_addr, u8 reg); + +enum sfp_sysfs_attributes { + PRESENT, + PRESENT_ALL, + PORT_NUMBER, + PORT_TYPE, + DDM_IMPLEMENTED, + TX_FAULT, + TX_FAULT1, + TX_FAULT2, + TX_FAULT3, + TX_FAULT4, + TX_DISABLE, + TX_DISABLE1, + TX_DISABLE2, + TX_DISABLE3, + TX_DISABLE4, + RX_LOS, + RX_LOS1, + RX_LOS2, + RX_LOS3, + RX_LOS4, + RX_LOS_ALL +}; + +/* SFP/QSFP common attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_port_number, S_IRUGO, show_port_number, NULL, PORT_NUMBER); +static SENSOR_DEVICE_ATTR(sfp_is_present, S_IRUGO, show_present, NULL, PRESENT); +static SENSOR_DEVICE_ATTR(sfp_is_present_all, S_IRUGO, show_present, NULL, PRESENT_ALL); +static SENSOR_DEVICE_ATTR(sfp_tx_disable, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE); +static SENSOR_DEVICE_ATTR(sfp_tx_fault, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT); + +/* QSFP attributes for sysfs */ +static SENSOR_DEVICE_ATTR(sfp_rx_los, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS); +static SENSOR_DEVICE_ATTR(sfp_rx_los1, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS1); +static SENSOR_DEVICE_ATTR(sfp_rx_los2, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS2); +static SENSOR_DEVICE_ATTR(sfp_rx_los3, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS3); +static SENSOR_DEVICE_ATTR(sfp_rx_los4, S_IRUGO, qsfp_show_tx_rx_status, NULL, RX_LOS4); +static SENSOR_DEVICE_ATTR(sfp_tx_disable1, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE1); +static SENSOR_DEVICE_ATTR(sfp_tx_disable2, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE2); +static SENSOR_DEVICE_ATTR(sfp_tx_disable3, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE3); +static SENSOR_DEVICE_ATTR(sfp_tx_disable4, S_IWUSR | S_IRUGO, qsfp_show_tx_rx_status, qsfp_set_tx_disable, TX_DISABLE4); +static SENSOR_DEVICE_ATTR(sfp_tx_fault1, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT1); +static SENSOR_DEVICE_ATTR(sfp_tx_fault2, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT2); +static SENSOR_DEVICE_ATTR(sfp_tx_fault3, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT3); +static SENSOR_DEVICE_ATTR(sfp_tx_fault4, S_IRUGO, qsfp_show_tx_rx_status, NULL, TX_FAULT4); +static struct attribute *qsfp_attributes[] = { + &sensor_dev_attr_sfp_port_number.dev_attr.attr, + &sensor_dev_attr_sfp_is_present.dev_attr.attr, + &sensor_dev_attr_sfp_is_present_all.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los1.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los2.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los3.dev_attr.attr, + &sensor_dev_attr_sfp_rx_los4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_disable4.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault1.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault2.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault3.dev_attr.attr, + &sensor_dev_attr_sfp_tx_fault4.dev_attr.attr, + NULL +}; + +/* Platform dependent +++ */ +#define CPLD_PORT_TO_FRONT_PORT(port) (port+1) + +enum port_numbers { +qfx5210_64x_port1, qfx5210_64x_port2, qfx5210_64x_port3, qfx5210_64x_port4, +qfx5210_64x_port5, qfx5210_64x_port6, qfx5210_64x_port7, qfx5210_64x_port8, +qfx5210_64x_port9, qfx5210_64x_port10, qfx5210_64x_port11, qfx5210_64x_port12, +qfx5210_64x_port13, qfx5210_64x_port14, qfx5210_64x_port15, qfx5210_64x_port16, +qfx5210_64x_port17, qfx5210_64x_port18, qfx5210_64x_port19, qfx5210_64x_port20, +qfx5210_64x_port21, qfx5210_64x_port22, qfx5210_64x_port23, qfx5210_64x_port24, +qfx5210_64x_port25, qfx5210_64x_port26, qfx5210_64x_port27, qfx5210_64x_port28, +qfx5210_64x_port29, qfx5210_64x_port30, qfx5210_64x_port31, qfx5210_64x_port32, +qfx5210_64x_port33, qfx5210_64x_port34, qfx5210_64x_port35, qfx5210_64x_port36, +qfx5210_64x_port37, qfx5210_64x_port38, qfx5210_64x_port39, qfx5210_64x_port40, +qfx5210_64x_port41, qfx5210_64x_port42, qfx5210_64x_port43, qfx5210_64x_port44, +qfx5210_64x_port45, qfx5210_64x_port46, qfx5210_64x_port47, qfx5210_64x_port48, +qfx5210_64x_port49, qfx5210_64x_port50, qfx5210_64x_port51, qfx5210_64x_port52, +qfx5210_64x_port53, qfx5210_64x_port54, qfx5210_64x_port55, qfx5210_64x_port56, +qfx5210_64x_port57, qfx5210_64x_port58, qfx5210_64x_port59, qfx5210_64x_port60, +qfx5210_64x_port61, qfx5210_64x_port62, qfx5210_64x_port63, qfx5210_64x_port64 +}; + +#define I2C_DEV_ID(x) { #x, x} + +static const struct i2c_device_id sfp_device_id[] = { +I2C_DEV_ID(qfx5210_64x_port1), +I2C_DEV_ID(qfx5210_64x_port2), +I2C_DEV_ID(qfx5210_64x_port3), +I2C_DEV_ID(qfx5210_64x_port4), +I2C_DEV_ID(qfx5210_64x_port5), +I2C_DEV_ID(qfx5210_64x_port6), +I2C_DEV_ID(qfx5210_64x_port7), +I2C_DEV_ID(qfx5210_64x_port8), +I2C_DEV_ID(qfx5210_64x_port9), +I2C_DEV_ID(qfx5210_64x_port10), +I2C_DEV_ID(qfx5210_64x_port11), +I2C_DEV_ID(qfx5210_64x_port12), +I2C_DEV_ID(qfx5210_64x_port13), +I2C_DEV_ID(qfx5210_64x_port14), +I2C_DEV_ID(qfx5210_64x_port15), +I2C_DEV_ID(qfx5210_64x_port16), +I2C_DEV_ID(qfx5210_64x_port17), +I2C_DEV_ID(qfx5210_64x_port18), +I2C_DEV_ID(qfx5210_64x_port19), +I2C_DEV_ID(qfx5210_64x_port20), +I2C_DEV_ID(qfx5210_64x_port21), +I2C_DEV_ID(qfx5210_64x_port22), +I2C_DEV_ID(qfx5210_64x_port23), +I2C_DEV_ID(qfx5210_64x_port24), +I2C_DEV_ID(qfx5210_64x_port25), +I2C_DEV_ID(qfx5210_64x_port26), +I2C_DEV_ID(qfx5210_64x_port27), +I2C_DEV_ID(qfx5210_64x_port28), +I2C_DEV_ID(qfx5210_64x_port29), +I2C_DEV_ID(qfx5210_64x_port30), +I2C_DEV_ID(qfx5210_64x_port31), +I2C_DEV_ID(qfx5210_64x_port32), +I2C_DEV_ID(qfx5210_64x_port33), +I2C_DEV_ID(qfx5210_64x_port34), +I2C_DEV_ID(qfx5210_64x_port35), +I2C_DEV_ID(qfx5210_64x_port36), +I2C_DEV_ID(qfx5210_64x_port37), +I2C_DEV_ID(qfx5210_64x_port38), +I2C_DEV_ID(qfx5210_64x_port39), +I2C_DEV_ID(qfx5210_64x_port40), +I2C_DEV_ID(qfx5210_64x_port41), +I2C_DEV_ID(qfx5210_64x_port42), +I2C_DEV_ID(qfx5210_64x_port43), +I2C_DEV_ID(qfx5210_64x_port44), +I2C_DEV_ID(qfx5210_64x_port45), +I2C_DEV_ID(qfx5210_64x_port46), +I2C_DEV_ID(qfx5210_64x_port47), +I2C_DEV_ID(qfx5210_64x_port48), +I2C_DEV_ID(qfx5210_64x_port49), +I2C_DEV_ID(qfx5210_64x_port50), +I2C_DEV_ID(qfx5210_64x_port51), +I2C_DEV_ID(qfx5210_64x_port52), +I2C_DEV_ID(qfx5210_64x_port53), +I2C_DEV_ID(qfx5210_64x_port54), +I2C_DEV_ID(qfx5210_64x_port55), +I2C_DEV_ID(qfx5210_64x_port56), +I2C_DEV_ID(qfx5210_64x_port57), +I2C_DEV_ID(qfx5210_64x_port58), +I2C_DEV_ID(qfx5210_64x_port59), +I2C_DEV_ID(qfx5210_64x_port60), +I2C_DEV_ID(qfx5210_64x_port61), +I2C_DEV_ID(qfx5210_64x_port62), +I2C_DEV_ID(qfx5210_64x_port63), +I2C_DEV_ID(qfx5210_64x_port64), +{ /* LIST END */ } +}; +MODULE_DEVICE_TABLE(i2c, sfp_device_id); +/* Platform dependent --- */ + +enum driver_type_e { + DRIVER_TYPE_SFP_MSA, + DRIVER_TYPE_SFP_DDM, + DRIVER_TYPE_QSFP, + DRIVER_TYPE_XFP +}; + +/* Each client has this additional data + */ +struct eeprom_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + struct bin_attribute bin; /* eeprom data */ +}; + +struct qsfp_data { + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 status[3]; /* bit0:port0, bit1:port1 and so on */ + /* index 0 => tx_fail + 1 => tx_disable + 2 => rx_loss */ + u8 device_id; + struct eeprom_data eeprom; +}; + +struct sfp_port_data { + struct mutex update_lock; + enum driver_type_e driver_type; + int port; /* CPLD port index */ + u64 present; /* present status, bit0:port0, bit1:port1 and so on */ + + struct qsfp_data *qsfp; + + struct i2c_client *client; +#if (MULTIPAGE_SUPPORT == 1) + int use_smbus; + u8 *writebuf; + unsigned write_max; +#endif +}; + +#if (MULTIPAGE_SUPPORT == 1) +static ssize_t sfp_port_read_write(struct sfp_port_data *port_data, + char *buf, loff_t off, size_t len, qsfp_opcode_e opcode); +#endif +static ssize_t show_port_number(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + return sprintf(buf, "%d\n", CPLD_PORT_TO_FRONT_PORT(data->port)); +} + +/* Platform dependent +++ */ +static struct sfp_port_data *sfp_update_present(struct i2c_client *client) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + int i = 0; + int status = -1; + u8 regs[] = {0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77}; + + DEBUG_PRINT("Starting sfp present status update"); + mutex_lock(&data->update_lock); + + /* Read present status of port 1~64 */ + data->present = 0; + + for (i = 0; i < ARRAY_SIZE(regs); i++) { + status = juniper_i2c_cpld_read(0x60, regs[i]); + + if (status < 0) { + DEBUG_PRINT("cpld(0x60) reg(0x%x) err %d", regs[i], status); + goto exit; + } + + DEBUG_PRINT("Present status = 0x%lx", data->present); + data->present |= (u64)status << (i*8); + } + + DEBUG_PRINT("Present status = 0x%lx", data->present); +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +/* Platform dependent --- */ + +static int sfp_is_port_present(struct i2c_client *client, int port) +{ + struct sfp_port_data *data = i2c_get_clientdata(client); + + data = sfp_update_present(client); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + return (data->present & BIT_INDEX(data->port)) ? 0 : 1; /* Platform dependent */ +} + +/* Platform dependent +++ */ +static ssize_t show_present(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + + if (PRESENT_ALL == attr->index) { + int i; + u8 values[8] = {0}; + struct sfp_port_data *data = sfp_update_present(client); + + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + for (i = 0; i < ARRAY_SIZE(values); i++) { + values[i] = ~(u8)(data->present >> (i * 8)); + } + + /* Return values 1 -> 64 in order */ + return sprintf(buf, "%.2x %.2x %.2x %.2x %.2x %.2x %.2x %.2x\n", + values[0], values[1], values[2], values[3], + values[4], values[5], values[6], values[7]); + } + else { + struct sfp_port_data *data = i2c_get_clientdata(client); + int present = sfp_is_port_present(client, data->port); + + if (IS_ERR_VALUE(present)) { + return present; + } + + /* PRESENT */ + return sprintf(buf, "%d\n", present); + } +} +/* Platform dependent --- */ + +static struct sfp_port_data *qsfp_update_tx_rx_status(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + int i, status = -1; + u8 buf = 0; + u8 reg[] = {SFF8436_TX_FAULT_ADDR, SFF8436_TX_DISABLE_ADDR, SFF8436_RX_LOS_ADDR}; + + if (time_before(jiffies, data->qsfp->last_updated + HZ + HZ / 2) && data->qsfp->valid) { + return data; + } + + DEBUG_PRINT("Starting sfp tx rx status update"); + mutex_lock(&data->update_lock); + data->qsfp->valid = 0; + memset(data->qsfp->status, 0, sizeof(data->qsfp->status)); + + /* Notify device to update tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + goto exit; + } + } + msleep(200); + + /* Read actual tx fault/ tx disable/ rx los status */ + for (i = 0; i < ARRAY_SIZE(reg); i++) { + status = sfp_eeprom_read(client, reg[i], &buf, sizeof(buf)); + if (unlikely(status < 0)) { + goto exit; + } + + DEBUG_PRINT("qsfp reg(0x%x) status = (0x%x)", reg[i], data->qsfp->status[i]); + data->qsfp->status[i] = (buf & 0xF); + } + + data->qsfp->valid = 1; + data->qsfp->last_updated = jiffies; + +exit: + mutex_unlock(&data->update_lock); + return (status < 0) ? ERR_PTR(status) : data; +} + +static ssize_t qsfp_show_tx_rx_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + int present; + u8 val = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + present = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENXIO; + } + + data = qsfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + switch (attr->index) { + case TX_FAULT: + val = !!(data->qsfp->status[2] & 0xF); + break; + case TX_FAULT1: + case TX_FAULT2: + case TX_FAULT3: + case TX_FAULT4: + val = !!(data->qsfp->status[2] & BIT_INDEX(attr->index - TX_FAULT1)); + break; + case TX_DISABLE: + val = data->qsfp->status[1] & 0xF; + break; + case TX_DISABLE1: + case TX_DISABLE2: + case TX_DISABLE3: + case TX_DISABLE4: + val = !!(data->qsfp->status[1] & BIT_INDEX(attr->index - TX_DISABLE1)); + break; + case RX_LOS: + val = !!(data->qsfp->status[0] & 0xF); + break; + case RX_LOS1: + case RX_LOS2: + case RX_LOS3: + case RX_LOS4: + val = !!(data->qsfp->status[0] & BIT_INDEX(attr->index - RX_LOS1)); + break; + default: + break; + } + + return sprintf(buf, "%d\n", val); +} + +static ssize_t qsfp_set_tx_disable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + long disable; + int status; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct sfp_port_data *data = i2c_get_clientdata(client); + + status = sfp_is_port_present(client, data->port); + if (IS_ERR_VALUE(status)) { + return status; + } + + if (!status) { + /* port is not present */ + return -ENXIO; + } + + status = kstrtol(buf, 10, &disable); + if (status) { + return status; + } + + data = qsfp_update_tx_rx_status(dev); + if (IS_ERR(data)) { + return PTR_ERR(data); + } + + mutex_lock(&data->update_lock); + + if (attr->index == TX_DISABLE) { + if (disable) { + data->qsfp->status[1] |= 0xF; + } + else { + data->qsfp->status[1] &= ~0xF; + } + } + else {/* TX_DISABLE1 ~ TX_DISABLE4*/ + if (disable) { + data->qsfp->status[1] |= (1 << (attr->index - TX_DISABLE1)); + } + else { + data->qsfp->status[1] &= ~(1 << (attr->index - TX_DISABLE1)); + } + } + + DEBUG_PRINT("index = (%d), status = (0x%x)", attr->index, data->qsfp->status[1]); + status = sfp_eeprom_write(data->client, SFF8436_TX_DISABLE_ADDR, &data->qsfp->status[1], sizeof(data->qsfp->status[1])); + if (unlikely(status < 0)) { + count = status; + } + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t sfp_eeprom_write(struct i2c_client *client, u8 command, const char *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_write_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return data_len; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, command, *data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + return status; + } + + return 1; +#endif + + +} + +#if (MULTIPAGE_SUPPORT == 0) +static ssize_t sfp_port_write(struct sfp_port_data *data, + const char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + return count; + } + + /* + * Write data to chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_write(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; +} +#endif + +static ssize_t sfp_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("%s(%d) offset = (%d), count = (%d)", off, count); + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + +#if (MULTIPAGE_SUPPORT == 1) + return sfp_port_read_write(data, buf, off, count, QSFP_WRITE_OP); +#else + return sfp_port_write(data, buf, off, count); +#endif +} + +static ssize_t sfp_eeprom_read(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ +#if USE_I2C_BLOCK_READ + int status, retry = I2C_RW_RETRY_COUNT; + + if (data_len > I2C_SMBUS_BLOCK_MAX) { + data_len = I2C_SMBUS_BLOCK_MAX; + } + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + goto abort; + } + if (unlikely(status != data_len)) { + status = -EIO; + goto abort; + } + + //result = data_len; + +abort: + return status; +#else + int status, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + status = 1; + +abort: + return status; +#endif +} + +#if (MULTIPAGE_SUPPORT == 1) +/*-------------------------------------------------------------------------*/ +/* + * This routine computes the addressing information to be used for + * a given r/w request. + * + * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), + * the page, and the offset. + * + * Handles both SFP and QSFP. + * For SFP, offset 0-255 are on client[0], >255 is on client[1] + * Offset 256-383 are on the lower half of client[1] + * Pages are accessible on the upper half of client[1]. + * Offset >383 are in 128 byte pages mapped into the upper half + * + * For QSFP, all offsets are on client[0] + * offset 0-127 are on the lower half of client[0] (no paging) + * Pages are accessible on the upper half of client[1]. + * Offset >127 are in 128 byte pages mapped into the upper half + * + * Callers must not read/write beyond the end of a client or a page + * without recomputing the client/page. Hence offset (within page) + * plus length must be less than or equal to 128. (Note that this + * routine does not have access to the length of the call, hence + * cannot do the validity check.) + * + * Offset within Lower Page 00h and Upper Page 00h are not recomputed + */ +static uint8_t sff_8436_translate_offset(struct sfp_port_data *port_data, + loff_t *offset, struct i2c_client **client) +{ + unsigned page = 0; + + *client = port_data->client; + + /* + * if offset is in the range 0-128... + * page doesn't matter (using lower half), return 0. + * offset is already correct (don't add 128 to get to paged area) + */ + if (*offset < SFF_8436_PAGE_SIZE) + return page; + + /* note, page will always be positive since *offset >= 128 */ + page = (*offset >> 7)-1; + /* 0x80 places the offset in the top half, offset is last 7 bits */ + *offset = SFF_8436_PAGE_SIZE + (*offset & 0x7f); + + return page; /* note also returning client and offset */ +} + +static ssize_t sff_8436_eeprom_read(struct sfp_port_data *port_data, + struct i2c_client *client, + char *buf, unsigned offset, size_t count) +{ + struct i2c_msg msg[2]; + u8 msgbuf[2]; + unsigned long timeout, read_time; + int status, i; + + memset(msg, 0, sizeof(msg)); + + switch (port_data->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + /*smaller eeproms can work given some SMBus extension calls */ + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + break; + case I2C_SMBUS_WORD_DATA: + /* Check for odd length transaction */ + count = (count == 1) ? 1 : 2; + break; + case I2C_SMBUS_BYTE_DATA: + count = 1; + break; + default: + /* + * When we have a better choice than SMBus calls, use a + * combined I2C message. Write address; then read up to + * io_limit data bytes. msgbuf is u8 and will cast to our + * needs. + */ + i = 0; + msgbuf[i++] = offset; + + msg[0].addr = client->addr; + msg[0].buf = msgbuf; + msg[0].len = i; + + msg[1].addr = client->addr; + msg[1].flags = I2C_M_RD; + msg[1].buf = buf; + msg[1].len = count; + } + + /* + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + read_time = jiffies; + + switch (port_data->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + status = i2c_smbus_read_i2c_block_data(client, offset, + count, buf); + break; + case I2C_SMBUS_WORD_DATA: + status = i2c_smbus_read_word_data(client, offset); + if (status >= 0) { + buf[0] = status & 0xff; + if (count == 2) + buf[1] = status >> 8; + status = count; + } + break; + case I2C_SMBUS_BYTE_DATA: + status = i2c_smbus_read_byte_data(client, offset); + if (status >= 0) { + buf[0] = status; + status = count; + } + break; + default: + status = i2c_transfer(client->adapter, msg, 2); + if (status == 2) + status = count; + } + + dev_dbg(&client->dev, "eeprom read %zu@%d --> %d (%ld)\n", + count, offset, status, jiffies); + + if (status == count) /* happy path */ + return count; + + if (status == -ENXIO) /* no module present */ + return status; + + /* REVISIT: at HZ=100, this is sloooow */ + msleep(1); + } while (time_before(read_time, timeout)); + + return -ETIMEDOUT; +} + +static ssize_t sff_8436_eeprom_write(struct sfp_port_data *port_data, + struct i2c_client *client, + const char *buf, + unsigned offset, size_t count) +{ + struct i2c_msg msg; + ssize_t status; + unsigned long timeout, write_time; + unsigned next_page_start; + int i = 0; + + /* write max is at most a page + * (In this driver, write_max is actually one byte!) + */ + if (count > port_data->write_max) + count = port_data->write_max; + + /* shorten count if necessary to avoid crossing page boundary */ + next_page_start = roundup(offset + 1, SFF_8436_PAGE_SIZE); + if (offset + count > next_page_start) + count = next_page_start - offset; + + switch (port_data->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + /*smaller eeproms can work given some SMBus extension calls */ + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + break; + case I2C_SMBUS_WORD_DATA: + /* Check for odd length transaction */ + count = (count == 1) ? 1 : 2; + break; + case I2C_SMBUS_BYTE_DATA: + count = 1; + break; + default: + /* If we'll use I2C calls for I/O, set up the message */ + msg.addr = client->addr; + msg.flags = 0; + + /* msg.buf is u8 and casts will mask the values */ + msg.buf = port_data->writebuf; + + msg.buf[i++] = offset; + memcpy(&msg.buf[i], buf, count); + msg.len = i + count; + break; + } + + /* + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + write_time = jiffies; + + switch (port_data->use_smbus) { + case I2C_SMBUS_I2C_BLOCK_DATA: + status = i2c_smbus_write_i2c_block_data(client, + offset, count, buf); + if (status == 0) + status = count; + break; + case I2C_SMBUS_WORD_DATA: + if (count == 2) { + status = i2c_smbus_write_word_data(client, + offset, (u16)((buf[0])|(buf[1] << 8))); + } else { + /* count = 1 */ + status = i2c_smbus_write_byte_data(client, + offset, buf[0]); + } + if (status == 0) + status = count; + break; + case I2C_SMBUS_BYTE_DATA: + status = i2c_smbus_write_byte_data(client, offset, + buf[0]); + if (status == 0) + status = count; + break; + default: + status = i2c_transfer(client->adapter, &msg, 1); + if (status == 1) + status = count; + break; + } + + dev_dbg(&client->dev, "eeprom write %zu@%d --> %ld (%lu)\n", + count, offset, (long int) status, jiffies); + + if (status == count) + return count; + + /* REVISIT: at HZ=100, this is sloooow */ + msleep(1); + } while (time_before(write_time, timeout)); + + return -ETIMEDOUT; +} + + +static ssize_t sff_8436_eeprom_update_client(struct sfp_port_data *port_data, + char *buf, loff_t off, + size_t count, qsfp_opcode_e opcode) +{ + struct i2c_client *client; + ssize_t retval = 0; + u8 page = 0; + loff_t phy_offset = off; + int ret = 0; + + page = sff_8436_translate_offset(port_data, &phy_offset, &client); + + dev_dbg(&client->dev, + "sff_8436_eeprom_update_client off %lld page:%d phy_offset:%lld, count:%ld, opcode:%d\n", + off, page, phy_offset, (long int) count, opcode); + if (page > 0) { + ret = sff_8436_eeprom_write(port_data, client, &page, + SFF_8436_PAGE_SELECT_REG, 1); + if (ret < 0) { + dev_dbg(&client->dev, + "Write page register for page %d failed ret:%d!\n", + page, ret); + return ret; + } + } + + while (count) { + ssize_t status; + + if (opcode == QSFP_READ_OP) { + status = sff_8436_eeprom_read(port_data, client, + buf, phy_offset, count); + } else { + status = sff_8436_eeprom_write(port_data, client, + buf, phy_offset, count); + } + if (status <= 0) { + if (retval == 0) + retval = status; + break; + } + buf += status; + phy_offset += status; + count -= status; + retval += status; + } + + + if (page > 0) { + /* return the page register to page 0 (why?) */ + page = 0; + ret = sff_8436_eeprom_write(port_data, client, &page, + SFF_8436_PAGE_SELECT_REG, 1); + if (ret < 0) { + dev_err(&client->dev, + "Restore page register to page %d failed ret:%d!\n", + page, ret); + return ret; + } + } + return retval; +} + + +/* + * Figure out if this access is within the range of supported pages. + * Note this is called on every access because we don't know if the + * module has been replaced since the last call. + * If/when modules support more pages, this is the routine to update + * to validate and allow access to additional pages. + * + * Returns updated len for this access: + * - entire access is legal, original len is returned. + * - access begins legal but is too long, len is truncated to fit. + * - initial offset exceeds supported pages, return -EINVAL + */ +static ssize_t sff_8436_page_legal(struct sfp_port_data *port_data, + loff_t off, size_t len) +{ + struct i2c_client *client = port_data->client; + u8 regval; + int status; + size_t maxlen; + + if (off < 0) return -EINVAL; + if (port_data->driver_type == DRIVER_TYPE_SFP_MSA) { + /* SFP case */ + /* if no pages needed, we're good */ + if ((off + len) <= SFF_8472_EEPROM_UNPAGED_SIZE) return len; + /* if offset exceeds possible pages, we're not good */ + if (off >= SFF_8472_EEPROM_SIZE) return -EINVAL; + /* in between, are pages supported? */ + status = sff_8436_eeprom_read(port_data, client, ®val, + SFF_8472_PAGEABLE_REG, 1); + if (status < 0) return status; /* error out (no module?) */ + if (regval & SFF_8472_PAGEABLE) { + /* Pages supported, trim len to the end of pages */ + maxlen = SFF_8472_EEPROM_SIZE - off; + } else { + /* pages not supported, trim len to unpaged size */ + maxlen = SFF_8472_EEPROM_UNPAGED_SIZE - off; + } + len = (len > maxlen) ? maxlen : len; + dev_dbg(&client->dev, + "page_legal, SFP, off %lld len %ld\n", + off, (long int) len); + } + else if (port_data->driver_type == DRIVER_TYPE_QSFP || + port_data->driver_type == DRIVER_TYPE_XFP) { + /* QSFP case */ + /* if no pages needed, we're good */ + if ((off + len) <= SFF_8436_EEPROM_UNPAGED_SIZE) return len; + /* if offset exceeds possible pages, we're not good */ + if (off >= SFF_8436_EEPROM_SIZE) return -EINVAL; + /* in between, are pages supported? */ + status = sff_8436_eeprom_read(port_data, client, ®val, + SFF_8436_PAGEABLE_REG, 1); + if (status < 0) return status; /* error out (no module?) */ + if (regval & SFF_8436_NOT_PAGEABLE) { + /* pages not supported, trim len to unpaged size */ + maxlen = SFF_8436_EEPROM_UNPAGED_SIZE - off; + } else { + /* Pages supported, trim len to the end of pages */ + maxlen = SFF_8436_EEPROM_SIZE - off; + } + len = (len > maxlen) ? maxlen : len; + dev_dbg(&client->dev, + "page_legal, QSFP, off %lld len %ld\n", + off, (long int) len); + } + else { + return -EINVAL; + } + return len; +} + + +static ssize_t sfp_port_read_write(struct sfp_port_data *port_data, + char *buf, loff_t off, size_t len, qsfp_opcode_e opcode) +{ + struct i2c_client *client = port_data->client; + int chunk; + int status = 0; + ssize_t retval; + size_t pending_len = 0, chunk_len = 0; + loff_t chunk_offset = 0, chunk_start_offset = 0; + + if (unlikely(!len)) + return len; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&port_data->update_lock); + + /* + * Confirm this access fits within the device suppored addr range + */ + len = sff_8436_page_legal(port_data, off, len); + if (len < 0) { + status = len; + goto err; + } + + /* + * For each (128 byte) chunk involved in this request, issue a + * separate call to sff_eeprom_update_client(), to + * ensure that each access recalculates the client/page + * and writes the page register as needed. + * Note that chunk to page mapping is confusing, is different for + * QSFP and SFP, and never needs to be done. Don't try! + */ + pending_len = len; /* amount remaining to transfer */ + retval = 0; /* amount transferred */ + for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { + + /* + * Compute the offset and number of bytes to be read/write + * + * 1. start at offset 0 (within the chunk), and read/write + * the entire chunk + * 2. start at offset 0 (within the chunk) and read/write less + * than entire chunk + * 3. start at an offset not equal to 0 and read/write the rest + * of the chunk + * 4. start at an offset not equal to 0 and read/write less than + * (end of chunk - offset) + */ + chunk_start_offset = chunk * SFF_8436_PAGE_SIZE; + + if (chunk_start_offset < off) { + chunk_offset = off; + if ((off + pending_len) < (chunk_start_offset + + SFF_8436_PAGE_SIZE)) + chunk_len = pending_len; + else + chunk_len = (chunk+1)*SFF_8436_PAGE_SIZE - off;/*SFF_8436_PAGE_SIZE - off;*/ + } else { + chunk_offset = chunk_start_offset; + if (pending_len > SFF_8436_PAGE_SIZE) + chunk_len = SFF_8436_PAGE_SIZE; + else + chunk_len = pending_len; + } + + dev_dbg(&client->dev, + "sff_r/w: off %lld, len %ld, chunk_start_offset %lld, chunk_offset %lld, chunk_len %ld, pending_len %ld\n", + off, (long int) len, chunk_start_offset, chunk_offset, + (long int) chunk_len, (long int) pending_len); + + /* + * note: chunk_offset is from the start of the EEPROM, + * not the start of the chunk + */ + status = sff_8436_eeprom_update_client(port_data, buf, + chunk_offset, chunk_len, opcode); + if (status != chunk_len) { + /* This is another 'no device present' path */ + dev_dbg(&client->dev, + "sff_8436_update_client for chunk %d chunk_offset %lld chunk_len %ld failed %d!\n", + chunk, chunk_offset, (long int) chunk_len, status); + goto err; + } + buf += status; + pending_len -= status; + retval += status; + } + mutex_unlock(&port_data->update_lock); + + return retval; + +err: + mutex_unlock(&port_data->update_lock); + + return status; +} + +#else +static ssize_t sfp_port_read(struct sfp_port_data *data, + char *buf, loff_t off, size_t count) +{ + ssize_t retval = 0; + + if (unlikely(!count)) { + DEBUG_PRINT("Count = 0, return"); + return count; + } + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&data->update_lock); + + while (count) { + ssize_t status; + + status = sfp_eeprom_read(data->client, off, buf, count); + if (status <= 0) { + if (retval == 0) { + retval = status; + } + break; + } + + buf += status; + off += status; + count -= status; + retval += status; + } + + mutex_unlock(&data->update_lock); + return retval; + +} +#endif + +static ssize_t sfp_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + int present; + struct sfp_port_data *data; + DEBUG_PRINT("offset = (%d), count = (%d)", off, count); + + data = dev_get_drvdata(container_of(kobj, struct device, kobj)); + present = sfp_is_port_present(data->client, data->port); + if (IS_ERR_VALUE(present)) { + return present; + } + + if (present == 0) { + /* port is not present */ + return -ENODEV; + } + +#if (MULTIPAGE_SUPPORT == 1) + return sfp_port_read_write(data, buf, off, count, QSFP_READ_OP); +#else + return sfp_port_read(data, buf, off, count); +#endif +} + +#if (MULTIPAGE_SUPPORT == 1) +static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom, size_t size) +#else +static int sfp_sysfs_eeprom_init(struct kobject *kobj, struct bin_attribute *eeprom) +#endif +{ + int err; + + sysfs_bin_attr_init(eeprom); + eeprom->attr.name = EEPROM_NAME; + eeprom->attr.mode = S_IWUSR | S_IRUGO; + eeprom->read = sfp_bin_read; + eeprom->write = sfp_bin_write; +#if (MULTIPAGE_SUPPORT == 1) + eeprom->size = size; +#else + eeprom->size = EEPROM_SIZE; +#endif + + /* Create eeprom file */ + err = sysfs_create_bin_file(kobj, eeprom); + if (err) { + return err; + } + + return 0; +} + +static int sfp_sysfs_eeprom_cleanup(struct kobject *kobj, struct bin_attribute *eeprom) +{ + sysfs_remove_bin_file(kobj, eeprom); + return 0; +} + + +#if (MULTIPAGE_SUPPORT == 0) +static int sfp_i2c_check_functionality(struct i2c_client *client) +{ +#if USE_I2C_BLOCK_READ + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK); +#else + return i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA); +#endif +} +#endif + + +static const struct attribute_group qsfp_group = { + .attrs = qsfp_attributes, +}; + +static int qsfp_probe(struct i2c_client *client, const struct i2c_device_id *dev_id, + struct qsfp_data **data) +{ + int status; + struct qsfp_data *qsfp; + +#if (MULTIPAGE_SUPPORT == 0) + if (!sfp_i2c_check_functionality(client)) { + status = -EIO; + goto exit; + } +#endif + + qsfp = kzalloc(sizeof(struct qsfp_data), GFP_KERNEL); + if (!qsfp) { + status = -ENOMEM; + goto exit; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &qsfp_group); + if (status) { + goto exit_free; + } + + /* init eeprom */ +#if (MULTIPAGE_SUPPORT == 1) + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin, SFF_8436_EEPROM_SIZE); +#else + status = sfp_sysfs_eeprom_init(&client->dev.kobj, &qsfp->eeprom.bin); +#endif + if (status) { + goto exit_remove; + } + + *data = qsfp; + dev_info(&client->dev, "qsfp '%s'\n", client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &qsfp_group); +exit_free: + kfree(qsfp); +exit: + + return status; +} + +/* Platform dependent +++ */ +static int sfp_device_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int ret = 0; + struct sfp_port_data *data = NULL; + + if (client->addr != SFP_EEPROM_A0_I2C_ADDR) { + return -ENODEV; + } + + if (dev_id->driver_data < qfx5210_64x_port1 || dev_id->driver_data > qfx5210_64x_port64) { + return -ENXIO; + } + + data = kzalloc(sizeof(struct sfp_port_data), GFP_KERNEL); + if (!data) { + return -ENOMEM; + } + +#if (MULTIPAGE_SUPPORT == 1) + data->use_smbus = 0; + + /* Use I2C operations unless we're stuck with SMBus extensions. */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_I2C_BLOCK)) { + data->use_smbus = I2C_SMBUS_I2C_BLOCK_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_WORD_DATA)) { + data->use_smbus = I2C_SMBUS_WORD_DATA; + } else if (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_READ_BYTE_DATA)) { + data->use_smbus = I2C_SMBUS_BYTE_DATA; + } else { + ret = -EPFNOSUPPORT; + goto exit_kfree; + } + } + + if (!data->use_smbus || + (i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_WORD_DATA) || + i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { + /* + * NOTE: AN-2079 + * Finisar recommends that the host implement 1 byte writes + * only since this module only supports 32 byte page boundaries. + * 2 byte writes are acceptable for PE and Vout changes per + * Application Note AN-2071. + */ + unsigned write_max = 1; + + if (write_max > io_limit) + write_max = io_limit; + if (data->use_smbus && write_max > I2C_SMBUS_BLOCK_MAX) + write_max = I2C_SMBUS_BLOCK_MAX; + data->write_max = write_max; + + /* buffer (data + address at the beginning) */ + data->writebuf = kmalloc(write_max + 2, GFP_KERNEL); + if (!data->writebuf) { + ret = -ENOMEM; + goto exit_kfree; + } + } else { + dev_warn(&client->dev, + "cannot write due to controller restrictions."); + } + + if (data->use_smbus == I2C_SMBUS_WORD_DATA || + data->use_smbus == I2C_SMBUS_BYTE_DATA) { + dev_notice(&client->dev, "Falling back to %s reads, " + "performance will suffer\n", data->use_smbus == + I2C_SMBUS_WORD_DATA ? "word" : "byte"); + } +#endif + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->port = dev_id->driver_data; + data->client = client; + data->driver_type = DRIVER_TYPE_QSFP; + + ret = qsfp_probe(client, dev_id, &data->qsfp); + if (ret < 0) { + goto exit_kfree_buf; + } + + return ret; + +exit_kfree_buf: +#if (MULTIPAGE_SUPPORT == 1) + if (data->writebuf) kfree(data->writebuf); +#endif + +exit_kfree: + kfree(data); + return ret; +} +/* Platform dependent --- */ + +static int qsfp_remove(struct i2c_client *client, struct qsfp_data *data) +{ + sfp_sysfs_eeprom_cleanup(&client->dev.kobj, &data->eeprom.bin); + sysfs_remove_group(&client->dev.kobj, &qsfp_group); + kfree(data); + return 0; +} + +static int sfp_device_remove(struct i2c_client *client) +{ + int ret = 0; + struct sfp_port_data *data = i2c_get_clientdata(client); + + if (data->driver_type == DRIVER_TYPE_QSFP) { + ret = qsfp_remove(client, data->qsfp); + } + + kfree(data); + return ret; +} + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static struct i2c_driver sfp_driver = { + .driver = { + .name = DRIVER_NAME, + }, + .probe = sfp_device_probe, + .remove = sfp_device_remove, + .id_table = sfp_device_id, + .address_list = normal_i2c, +}; + +static int __init sfp_init(void) +{ + return i2c_add_driver(&sfp_driver); +} + +static void __exit sfp_exit(void) +{ + i2c_del_driver(&sfp_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("juniper qfx5210_64x_sfp driver"); +MODULE_LICENSE("GPL"); + +module_init(sfp_init); +module_exit(sfp_exit); + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c new file mode 120000 index 000000000000..f4d67640ccc3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service new file mode 100755 index 000000000000..b6a446ec1752 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/service/qfx5210-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Juniper QFX5210 initialization service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +ExecStartPre=/usr/local/bin/juniper_qfx5210_util.py install +ExecStart=/usr/local/bin/juniper_qfx5210_monitor.py +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/setup.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/setup.py new file mode 100755 index 000000000000..536f814a3509 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='sonic_platform', + version='1.0', + description='Module to initialize Juniper QFX5210-64X platforms', + + packages=['sonic_platform'], + package_dir={'sonic_platform': 'qfx5210/sonic_platform'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/__init__.py new file mode 100755 index 000000000000..9e1b2e56b1c4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/__init__.py @@ -0,0 +1 @@ +import platform diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py new file mode 100755 index 000000000000..5d56ef3a0cde --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/chassis.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# which provide the chassis specific details +# +# Copyright (c) 2019, Juniper Networks, Inc. +# All rights reserved. +# +# Notice and Disclaimer: This code is licensed to you under the GNU General +# Public License as published by the Free Software Foundation, version 3 or +# any later version. This code is not an official Juniper product. You can +# obtain a copy of the License at +# +# OSS License: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Third-Party Code: This code may depend on other components under separate +# copyright notice and license terms. Your use of the source code for those +# components is subject to the terms and conditions of the respective license +# as noted in the Third-Party source code file. +# + +try: + import os + import commands + import sys + import time + from sonic_platform_base.chassis_base import ChassisBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Chassis(ChassisBase): + """ + JUNIPER QFX5210 Platform-specific Chassis class + """ + + # Find the last reboot reason out of following + # CPLD_WATCHDOG_RESET 0x08 + # POWER_ON_RESET 0x20 + # CPU_WATCHDOG_RESET 0x40 + # SOFTWARE_RESET 0x80 + + def __init__(self): + ChassisBase.__init__(self) + + def get_qfx5210_parameter_value(self,parameter_name): + try: + with open("/var/run/qfx5210_eeprom", "r") as file: + for item in file: + content = item.split('=') + if content[0] == parameter_name: + return content[1:] + return "False" + except IOError: + print "Error: File not found" + return "False" + + def get_product_name(self): + product_name_list = self.get_qfx5210_parameter_value('ProductName') + if product_name_list: + product_name = ''.join(product_name_list) + return product_name + else: + return False + + def get_part_number(self): + part_number_list = self.get_qfx5210_parameter_value('PartNumber') + if part_number_list: + part_number = ''.join(part_number_list) + return part_number + else: + return False + + def get_serial_number(self): + serial_number_list = self.get_qfx5210_parameter_value('SerialNumber') + if serial_number_list: + serial_number = ''.join(serial_number_list) + return serial_number + else: + return False + + def get_base_mac(self): + mac_list = self.get_qfx5210_parameter_value('MAC') + if mac_list: + mac = ''.join(mac_list) + return mac + else: + return False + + def get_platform_name(self): + platform_name_list = self.get_qfx5210_parameter_value('PlatformName') + if platform_name_list: + platform_name = ''.join(platform_name_list) + return platform_name + else: + return False + + def get_fan_type(self, fantype_path): + try: + fan_type_file = open(fantype_path) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return "-1" + else: + fan_type = fan_type_file.read() + fan_type_file.close() + return str(fan_type) + + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + """ + status, last_reboot_reason = commands.getstatusoutput("i2cget -y 0 0x65 0x24") + if (status == 0): + if last_reboot_reason == "0x80": + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) + elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": + return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif last_reboot_reason == "0x20": + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + else: + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") + else: + time.sleep(3) + status, last_reboot_reason = commands.getstatusoutput("i2cget -y 0 0x65 0x24") + if last_reboot_reason == "0x80": + return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, None) + elif last_reboot_reason == "0x40" or last_reboot_reason == "0x08": + return (ChassisBase.REBOOT_CAUSE_WATCHDOG, None) + elif last_reboot_reason == "0x20": + return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None) + else: + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Unknown reason") diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/platform.py new file mode 100755 index 000000000000..5620fec54f65 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/sonic_platform/platform.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# which provide the platform specific details +# +# Copyright (c) 2019, Juniper Networks, Inc. +# All rights reserved. +# +# Notice and Disclaimer: This code is licensed to you under the GNU General +# Public License as published by the Free Software Foundation, version 3 or +# any later version. This code is not an official Juniper product. You can +# obtain a copy of the License at +# +# OSS License: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Third-Party Code: This code may depend on other components under separate +# copyright notice and license terms. Your use of the source code for those +# components is subject to the terms and conditions of the respective license +# as noted in the Third-Party source code file. +# + + +import sys + +try: + from sonic_platform_base.platform_base import PlatformBase +except ImportError as e: + raise ImportError("%s - required module not found" % e) + +platformDict = {'platform':'QFX5210-64C'} + +class Platform(PlatformBase): + def __init__(self): + self.platform = self.getPlatform() + + def getPlatformDict(self): + global platformDict + if platformDict: + return platformDict + + def readPlatformName(self): + return self.getPlatformDict().get('platform') + + def getPlatform(self): + platformCls = self.readPlatformName() + return platformCls + + def get_chassis(self): + from chassis import Chassis + chassis = Chassis() + return chassis + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README new file mode 100755 index 000000000000..490844f2137d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/README @@ -0,0 +1,87 @@ + +Copyright (c) 2019, Juniper Networks, Inc. +All rights reserved. + +Front panel LEDs +================ +There are 4 system LEDs in the front panel. Master, System, Alarm, & Beacon. +LED controls can be found under /sys/class/leds. The sysfs interface & +colour mappings are as follows: + +For master LED: /sys/class/leds/master/brightness + 0 => off + 1 => green + +For system LED: /sys/class/leds/system/brightness + 0 => off + 1 => green + +For alarm LED: /sys/class/leds/alarm/brightness + 0 => off + 1 => amber + 2 => red + +For beacon LED: /sys/class/leds/beacon/brightness + 0 => off + 1 => blue + +For any of the above LEDs, max_brightness file can tell the maximum value +accepted. + +System FANs +=========== +There are 4 fans and each of the fan has 2 fan modules. Overall there are +8 fans in the system. + +Fan controls can be found in /sys/bus/i2c/devices/17-0068. All the fans +are controlled by one duty cycle value, ranges from 0 to 100 + +Fan duty cycle can be controlled through /sys/bus/i2c/devices/17-0068/pwm1 + +Fan module presence is given by /sys/bus/i2c/devices/17-0068/fan[1-4]_present +file. A value of '1' indicate that fan is present & a value of '0' otherwise. + +Fan rotation direction is given by /sys/bus/i2c/devices/17-0068/fan[1-4]_direction. +A value of '0' indicate the direction is AFO (Front to back airflow) or Airflow +out. A value of '1' indicate that direction is AFI (Back to front airflow) or +Airflow in. + +Fan speed is given by fan[1-4]_input + +Temperature sensors +=================== +There are 6 temperature sensors. The readings are available in +/sys/bus/i2c/devices/{0}-00{1}/hwmon/hwmon*/temp1_input + +System PSUs +=========== +There are two independent PSUs. These are controlled by a dedicated CPLD. +The status registers are mapped under /sys/bus/i2c/devices/9-0050 and +/sys/bus/i2c/devices/10-0053. + +SFPs +==== +There are 64 QSFP+ modules supported in qfx5210 platform. EEPORMs will be +mapped under /sys/bus/i2c/devices/[25-88]-0050/ sysfs directory + +Sensor details +============== +LM75 supported sensor modules will be available under 'sensors' command. +If you want to get all the sensor data including the SFPs & LEDs, you can +invoke 'sudo juniper_qfx5210_util.py show' + +Platform poweroff +================= +Linux poweroff commands such as 'poweroff', 'shutdown', 'halt', etc. will not +power off qfx5210 platform as there are custom CPLDs control the power off +sequences. Use the command 'sudo platform_poweroff' to power off qfx5210 +platform + +Platform monitoring daemon +========================== +“juniper_qfx5210_monitor.py” is the platform monitoring script. +It implements the qfx5210 EM policy. This script will run as system service +and monitor the temperature sensors in every 20 seconds. Based on the EM +policy thresholds, it controls the fan rpm, manage alarm leds, and +shutdown the box. + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py new file mode 100755 index 000000000000..a74bce042ac3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_monitor.py @@ -0,0 +1,454 @@ +#!/usr/bin/env python +# +# Name: juniper_qfx5210_monitor.py version: 1.0 +# +# Description: This file contains the EM implementation for qfx5210 platform +# +# Copyright (c) 2019, Juniper Networks, Inc. +# All rights reserved. +# +# Notice and Disclaimer: This code is licensed to you under the GNU General +# Public License as published by the Free Software Foundation, version 3 or +# any later version. This code is not an official Juniper product. You can +# obtain a copy of the License at +# +# OSS License: +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +# Third-Party Code: This code may depend on other components under separate +# copyright notice and license terms. Your use of the source code for those +# components is subject to the terms and conditions of the respective license +# as noted in the Third-Party source code file. + +try: + import os + import commands + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import logging.handlers + import types + import time + import traceback + import glob + import collections + from tabulate import tabulate +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/juniper_qfx5210_monitor' + + +global isPlatformAFI + +temp_policy_AFI = { + 0: [[70, 0, 48000], [70, 48000, 53000], [80, 53000, 0], [80, 53000, 58000], [100, 58000, 0], ['Yellow Alarm', 64000, 70000], ['Red Alarm', 70000, 75000], ['Fire Shut Alarm', 75000, 0]], + 1: [[70, 0, 41000], [70, 41000, 47000], [80, 47000, 0], [80, 47000, 52000], [100, 52000, 0], ['Yellow Alarm', 58000, 64000], ['Red Alarm', 64000, 69000], ['Fire Shut Alarm', 69000, 0]], + 2: [[70, 0, 33000], [70, 33000, 39000], [80, 39000, 0], [80, 39000, 45000], [100, 45000, 0], ['Yellow Alarm', 53000, 59000], ['Red Alarm', 59000, 64000], ['Fire Shut Alarm', 64000, 0]], + 3: [[70, 0, 31000], [70, 31000, 36000], [80, 36000, 0], [80, 36000, 42000], [100, 42000, 0], ['Yellow Alarm', 48000, 55000], ['Red Alarm', 55000, 60000], ['Fire Shut Alarm', 60000, 0]], + 4: [[70, 0, 31000], [70, 31000, 36000], [80, 36000, 0], [80, 36000, 42000], [100, 42000, 0], ['Yellow Alarm', 48000, 55000], ['Red Alarm', 55000, 60000], ['Fire Shut Alarm', 60000, 0]], + 5: [[70, 0, 31000], [70, 31000, 36000], [80, 36000, 0], [80, 36000, 43000], [100, 43000, 0], ['Yellow Alarm', 49000, 56000], ['Red Alarm', 56000, 61000], ['Fire Shut Alarm', 61000, 0]], + 6: [[70, 0, 70000], [70, 70000, 78000], [80, 78000, 0], [80, 78000, 86000], [100, 86000, 0], ['Yellow Alarm', 91000, 96000], ['Red Alarm', 96000, 102000], ['Fire Shut Alarm', 102000, 0]], + } + +temp_policy_AFO = { + 0: [[60, 0, 49000], [60, 49000, 55000], [80, 55000, 0], [80, 55000, 62000], [100, 62000, 0], ['Yellow Alarm', 68000, 74000], ['Red Alarm', 74000, 78000], ['Fire Shut Alarm', 78000, 0]], + 1: [[60, 0, 55000], [60, 55000, 60000], [80, 60000, 0], [80, 60000, 65000], [100, 65000, 0], ['Yellow Alarm', 70000, 76000], ['Red Alarm', 76000, 80000], ['Fire Shut Alarm', 80000, 0]], + 2: [[60, 0, 34000], [60, 34000, 40000], [80, 40000, 0], [80, 40000, 47000], [100, 47000, 0], ['Yellow Alarm', 54000, 60000], ['Red Alarm', 60000, 64000], ['Fire Shut Alarm', 64000, 0]], + 3: [[60, 0, 36000], [60, 36000, 41000], [80, 41000, 0], [80, 41000, 47000], [100, 47000, 0], ['Yellow Alarm', 54000, 60000], ['Red Alarm', 60000, 64000], ['Fire Shut Alarm', 64000, 0]], + 4: [[60, 0, 39000], [60, 39000, 45000], [80, 45000, 0], [80, 45000, 52000], [100, 52000, 0], ['Yellow Alarm', 59000, 65000], ['Red Alarm', 65000, 69000], ['Fire Shut Alarm', 69000, 0]], + 5: [[60, 0, 37000], [60, 37000, 43000], [80, 43000, 0], [80, 43000, 50000], [100, 50000, 0], ['Yellow Alarm', 57000, 63000], ['Red Alarm', 63000, 67000], ['Fire Shut Alarm', 67000, 0]], + 6: [[60, 0, 70000], [60, 70000, 78000], [80, 78000, 0], [80, 78000, 86000], [100, 86000, 0], ['Yellow Alarm', 91000, 96000], ['Red Alarm', 96000, 102000], ['Fire Shut Alarm', 102000, 0]], + } + +class QFX5210_FanUtil(object): + """QFX5210 Platform FanUtil class""" + + FANBASE_VAL_PATH = '/sys/bus/i2c/devices/17-0068/{0}' + FAN_DUTY_PATH = '/sys/bus/i2c/devices/17-0068/fan_duty_cycle_percentage' + + def __init__(self): + fan_path = self.FANBASE_VAL_PATH + + def get_fan_duty_cycle(self): + try: + val_file = open(self.FAN_DUTY_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + return int(content) + + def set_fan_duty_cycle(self, val): + + try: + fan_file = open(self.FAN_DUTY_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + fan_file.write(str(val)) + fan_file.close() + return True + +class QFX5210_ThermalUtil(object): + """QFX5210 Platform ThermalUtil class""" + + SENSOR_NUM_ON_MAIN_BOARD = 6 + SENSOR_CORETEMP_NUM_ON_MAIN_BOARD = 7 + CORETEMP_NUM_ON_MAIN_BOARD = 5 + THERMAL_NUM_RANGE = 8 + SENSOR_NUM_1_IDX = 1 + SENSORS_PATH = '/sys/bus/i2c/devices/{0}-00{1}/hwmon/hwmon*/temp1_input' + CORETEMP_PATH = '/sys/bus/platform/devices/coretemp.0/hwmon/hwmon1/temp{0}_input' + ALARM_LED_PATH = '/sys/class/leds/alarm/brightness' + + """ Dictionary where + key1 = thermal id index (integer) starting from 1 + value = path to fan device file (string) """ + _sensor_to_device_path_mapping = {} + + _sensor_to_device_node_mapping = [ + ['18', '48'], + ['18', '49'], + ['18', '4a'], + ['18', '4b'], + ['17', '4d'], + ['17', '4e'], + ] + + _coretemp_to_device_path_mapping = {} + + _coretemp_to_device_node_mapping = [1, 2, 3, 4, 5] + + def __init__(self): + sensor_path = self.SENSORS_PATH + coretemp_path = self.CORETEMP_PATH + for x in range(self.SENSOR_NUM_ON_MAIN_BOARD): + self._sensor_to_device_path_mapping[x+1] = sensor_path.format( + self._sensor_to_device_node_mapping[x][0], + self._sensor_to_device_node_mapping[x][1]) + + for x in range(self.CORETEMP_NUM_ON_MAIN_BOARD): + self._coretemp_to_device_path_mapping[x] = coretemp_path.format( + self._coretemp_to_device_node_mapping[x]) + + + """ Function reads the 5 temp inputs in CORETEMP_PATH + and returns the average of these 5 temp readings """ + def get_coretempValue(self): + sum = 0 + for x in range(self.CORETEMP_NUM_ON_MAIN_BOARD): + sum += self._get_coretemp_node_val(x) + avg = sum/self.CORETEMP_NUM_ON_MAIN_BOARD + return int(avg) + + + """ Function takes the Sensor number as input, constructs the device path, + opens sensor file, reads the temp content from the file and returns the value """ + def _get_sensor_node_val(self, thermal_num): + if thermal_num < self.SENSOR_NUM_1_IDX or thermal_num > self.SENSOR_NUM_ON_MAIN_BOARD: + logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) + return None + + device_path = self.get_thermal_to_device_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + + """ Function takes the coretemp number as input, constructs the device path, + opens sensor file, reads the temp content from the file and returns the value """ + def _get_coretemp_node_val(self, thermal_num): + + device_path = self.get_coretemp_to_device_path(thermal_num) + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + + def get_thermal_to_device_path(self, thermal_num): + return self._sensor_to_device_path_mapping[thermal_num] + + + def get_coretemp_to_device_path(self, thermal_num): + return self._coretemp_to_device_path_mapping[thermal_num] + + + """ Function opens the alarm LED file, reads the content from the file + and returns the value.This value indicates the Brigthness level. + The value of 1 = YELLOW ALARM + The value of 2 = RED ALARM + The value of 0 = NO ALARM """ + def get_alarm_led_brightness(self): + try: + val_file = open(self.ALARM_LED_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + return int(content) + + + """ Function takes the value to set in the alarm LED file as input. + Reads the content from the file and sets the value.This value indicates the Brigthness level. + The value of 1 = YELLOW ALARM + The value of 2 = RED ALARM + The value of 0 = NO ALARM """ + def set_alarm_led_brightness(self, val): + try: + val_file = open(self.ALARM_LED_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + val_file.write(str(val)) + val_file.close() + return True + + + + """ Function is called periodically every 20 secs. It reads the 6 Temp sensors and 1 core Temp sensor and sets + Sensor flags accordingly. Also reads the Fan duty cycle and depending on the FAN duty cycle reading and temp sensor reading, + set the different parameters """ + def getSensorTemp(self): + sum = 0 + global isPlatformAFI + #AFI + if (isPlatformAFI == True): + temp_policy = temp_policy_AFI + else: + #AFO + temp_policy = temp_policy_AFO + + """ Dictionary where + key = thermal id index starting from 0. 0 is the sensor 1 ... + value = Different temp ranges """ + SensorFlag = { + 0: [0,0,0,0,0,0,0,0], + 1: [0,0,0,0,0,0,0,0], + 2: [0,0,0,0,0,0,0,0], + 3: [0,0,0,0,0,0,0,0], + 4: [0,0,0,0,0,0,0,0], + 5: [0,0,0,0,0,0,0,0], + 6: [0,0,0,0,0,0,0,0], + } + + for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD): + if x < self.SENSOR_NUM_ON_MAIN_BOARD: + value = self._get_sensor_node_val(x+1) + else: + value = self.get_coretempValue() + + # 60% Duty Cycle for AFO and 70% Duty Cycle for AFI + if value > temp_policy[x][0][1] and value <= temp_policy[x][0][2]: + SensorFlag[x][0] = True + + # 60% Prev Duty Cycle for AFO and 70% Prev Duty Cycle for AFI + elif value > temp_policy[x][1][1] and value < temp_policy[x][1][2]: + SensorFlag[x][1] = True + + # 80% Duty Cycle + elif value == temp_policy[x][2][1]: + SensorFlag[x][2] = True + + #80% Prev Duty Cycle + elif value > temp_policy[x][3][1] and value < temp_policy[x][3][2]: + SensorFlag[x][3] = True + + #100% Duty Cycle + elif value >= temp_policy[x][4][1]: + SensorFlag[x][4] = True + + else: + pass + + # Yellow Alarm + if value >= temp_policy[x][5][1] and value < temp_policy[x][5][2]: + SensorFlag[x][5] = True + + # Red Alarm + elif value >= temp_policy[x][6][1] and value < temp_policy[x][6][2]: + SensorFlag[x][6] = True + + # Fire Shut down + elif value >= temp_policy[x][7][1]: + SensorFlag[x][7] = True + + fan = QFX5210_FanUtil() + # CHECK IF ANY TEMPERATURE SENSORS HAS SET FIRE SHUTDOWN FLAG + if SensorFlag[0][7] or SensorFlag[1][7] or SensorFlag[2][7] or SensorFlag[3][7] or SensorFlag[4][7] or SensorFlag[5][7] or SensorFlag[6][7]: + value = self.get_alarm_led_brightness() + if ( value > 0): + self.set_alarm_led_brightness(0) + + # CHECK IF ANY TEMPERATURE SENSORS HAS SET 'RED' ALARM FLAG, IF YES, SET THE ALARM LED TO 'RED' + elif SensorFlag[0][6] or SensorFlag[1][6] or SensorFlag[2][6] or SensorFlag[3][6] or SensorFlag[4][6] or SensorFlag[5][6] or SensorFlag[6][6]: + self.set_alarm_led_brightness(2) + + # CHECK IF ANY TEMPERATURE SENSORS HAS SET 'YELLOW' ALARM FLAG, IF YES, SET THE ALARM LED TO 'YELLOW' + elif SensorFlag[0][5] or SensorFlag[1][5] or SensorFlag[2][5] or SensorFlag[3][5] or SensorFlag[4][5] or SensorFlag[5][5] or SensorFlag[6][5]: + self.set_alarm_led_brightness(1) + + # CHECK IF ANY TEMPERATURE SENSORS HAS SET 100% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 100% + elif SensorFlag[0][4] or SensorFlag[1][4] or SensorFlag[2][4] or SensorFlag[3][4] or SensorFlag[4][4] or SensorFlag[5][4] or SensorFlag[6][4]: + fan.set_fan_duty_cycle(100) + value = self.get_alarm_led_brightness() + if ( value > 0): + self.set_alarm_led_brightness(0) + + # CHECK IF ANY TEMPERATURE SENSORS HAS SET 80% DUTY CYCLE PREV FLAG, IF YES, SET THE FAN DUTY CYCLE TO 80% + elif SensorFlag[0][3] or SensorFlag[1][3] or SensorFlag[2][3] or SensorFlag[3][3] or SensorFlag[4][3] or SensorFlag[5][3] or SensorFlag[6][3]: + fan.set_fan_duty_cycle(80) + value = self.get_alarm_led_brightness() + if ( value > 0): + self.set_alarm_led_brightness(0) + + # CHECK IF ANY TEMPERATURE SENSORS HAS SET 80% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 80% + elif SensorFlag[0][2] or SensorFlag[1][2] or SensorFlag[2][2] or SensorFlag[3][2] or SensorFlag[4][2] or SensorFlag[5][2] or SensorFlag[6][2]: + fan.set_fan_duty_cycle(80) + value = self.get_alarm_led_brightness() + if ( value > 0): + self.set_alarm_led_brightness(0) + + # FOR "AFO" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 60% DUTY CYCLE PREV FLAG, IF YES, SET THE FAN DUTY CYCLE TO 60% + # FOR "AFI" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 70% DUTY CYCLE PREV FLAG, IF YES, SET THE FAN DUTY CYCLE TO 70% + elif SensorFlag[0][1] or SensorFlag[1][1] or SensorFlag[2][1] or SensorFlag[3][1] or SensorFlag[4][1] or SensorFlag[5][1] or SensorFlag[6][1]: + if (isPlatformAFI == True): + fan.set_fan_duty_cycle(70) + else: + fan.set_fan_duty_cycle(60) + value = self.get_alarm_led_brightness() + if ( value > 0): + self.set_alarm_led_brightness(0) + + # FOR "AFO" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 60% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 60% + # FOR "AFI" Platform CHECK IF ANY TEMPERATURE SENSORS HAS SET 70% DUTY CYCLE FLAG, IF YES, SET THE FAN DUTY CYCLE TO 70% + elif SensorFlag[0][0] or SensorFlag[1][0] or SensorFlag[2][0] or SensorFlag[3][0] or SensorFlag[4][0] or SensorFlag[5][0] or SensorFlag[6][0]: + if (isPlatformAFI == True): + fan.set_fan_duty_cycle(70) + else: + fan.set_fan_duty_cycle(60) + value = self.get_alarm_led_brightness() + if ( value > 0): + self.set_alarm_led_brightness(0) + + else: + pass + + + # RESET ALL THE SENSOR FLAGS + for x in range(self.SENSOR_CORETEMP_NUM_ON_MAIN_BOARD): + for y in range(self.THERMAL_NUM_RANGE): + SensorFlag[x][y] = 0 + + +class device_monitor(object): + + def __init__(self): + global isPlatformAFI + MASTER_LED_PATH = '/sys/class/leds/master/brightness' + SYSTEM_LED_PATH = '/sys/class/leds/system/brightness' + FANTYPE_PATH = '/sys/bus/i2c/devices/17-0068/fan1_direction' + + import sonic_platform + platform = sonic_platform.platform.Platform() + chassis = platform.get_chassis() + fan_type = chassis.get_fan_type(FANTYPE_PATH) + + # the return value of get_fan_type is AFO = 0, AFI = 1 and for error condition it is -1 + # In the error condition also, we are making default platform as AFO, to continue with Energy Monitoring + if (fan_type == -1 or fan_type == 0): + if (fan_type == -1): + print "Error: unable to open sys file for fan handling, defaulting it to AFO" + isPlatformAFI = False + else: + isPlatformAFI = True + + + master_led_value = 1 + try: + masterLED_file = open(MASTER_LED_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + masterLED_file.write(str(master_led_value)) + masterLED_file.close() + + system_led_value = 1 + try: + systemLED_file = open(SYSTEM_LED_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + systemLED_file.write(str(system_led_value)) + systemLED_file.close() + pass + + def manage_device(self): + thermal = QFX5210_ThermalUtil() + thermal.getSensorTemp() + +def main(): + monitor = device_monitor() + while True: + monitor.manage_device() + time.sleep(20) + +if __name__ == '__main__': + main() + diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py new file mode 100755 index 000000000000..2e65b76148bb --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/juniper_qfx5210_util.py @@ -0,0 +1,545 @@ +#!/usr/bin/env python +# +# Modified to work on Juniper QFX5210 +# +# Based on accton_as7816_util.py +# +# Copyright (C) 2016 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import os +import commands +import sys, getopt +import binascii +import logging +import re +import time +import random +import optparse +from collections import namedtuple + + + + +PROJECT_NAME = 'qfx5210_64x' +version = '0.1.0' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':4, 'fan':4,'thermal':6, 'psu':2, 'sfp':64} +FORCE = 0 +#logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +#logging.basicConfig(level=logging.INFO) + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(args)!=2: + show_eeprom_help() + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(args[1]) + return + elif arg == 'set': + if len(args)<3: + show_set_help() + else: + set_device(args[1:]) + return + else: + show_help() + + DisableWatchDogCmd = '/usr/sbin/i2cset -y 0 0x65 0x3 0x04' + # Disable watchdog + try: + os.system(DisableWatchDogCmd) + except OSError: + print 'Error: Execution of "%s" failed', DisableWatchDogCmd + return False + + CPUeepromFileCmd = 'cat /sys/devices/pci0000:00/0000:00:1f.3/i2c-0/0-0056/eeprom > /etc/init.d/eeprom_qfx5210_ascii' + # Write the contents of CPU EEPROM to file + try: + os.system(CPUeepromFileCmd) + except OSError: + print 'Error: Execution of "%s" failed', CPUeepromFileCmd + return False + + return True + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print cmd +" [led|sfp|fan]" + print " use \""+ cmd + " led 0-4 \" to set led color" + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable" + sys.exit(0) + +def show_eeprom_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print " use \""+ cmd + " 1-32 \" to dump sfp# eeprom" + sys.exit(0) + +def my_log(txt): + if DEBUG == True: + print "[ROY]"+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_check(): + ret, lsmod = log_os_system("lsmod| grep juniper", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + return True + + + +kos = [ +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x', +'modprobe juniper_i2c_cpld' , +'modprobe ym2651y' , +'modprobe x86-64-juniper-qfx5210-64x-fan' , +'modprobe x86-64-juniper-qfx5210-64x-sfp' , +'modprobe x86-64-juniper-qfx5210-64x-leds' , +'modprobe x86-64-juniper-qfx5210-64x-psu' ] + +def driver_install(): + global FORCE + status, output = log_os_system("depmod", 1) + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0,len(kos)): + rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +led_prefix ='/sys/class/leds/' +hwmon_types = {'led': ['alarm','system','master','beacon']} +hwmon_nodes = {'led': ['brightness'] } +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'fan': ['17-0068'] , + 'thermal': ['18-0048','18-0049', '18-004a' , '18-004b', '17-004d', '17-004e'] , + 'psu': ['10-0053','9-0050'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] , + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['sfp_is_present ', 'sfp_tx_disable']} + +sfp_map = [37,38,39,40,42,41,44,43,33,34,35,36,45,46,47,48,49,50,51,52, + 61,62,63,64,53,54,55,56,57,58,59,60,69,70,71,72,77,78,79,80,65, + 66,67,68,73,74,75,76,85,86,87,88,31,32,29,30,81,82,83,84,25,26, + 27,28] + +mknod =[ +'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-2/new_device', +'echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo qfx5210_64x_psu1 0x53 > /sys/bus/i2c/devices/i2c-10/new_device', +'echo ym2851 0x5b > /sys/bus/i2c/devices/i2c-10/new_device', +'echo qfx5210_64x_psu2 0x50 > /sys/bus/i2c/devices/i2c-9/new_device', +'echo ym2851 0x58 > /sys/bus/i2c/devices/i2c-9/new_device', +'echo qfx5210_64x_fan 0x68 > /sys/bus/i2c/devices/i2c-17/new_device', +'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-18/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-18/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-18/new_device', +'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-18/new_device', +'echo lm75 0x4d > /sys/bus/i2c/devices/i2c-17/new_device', +'echo lm75 0x4e > /sys/bus/i2c/devices/i2c-17/new_device', +'echo cpld_qfx5210 0x60 > /sys/bus/i2c/devices/i2c-19/new_device', +'echo cpld_plain 0x62 > /sys/bus/i2c/devices/i2c-20/new_device', +'echo cpld_plain 0x64 > /sys/bus/i2c/devices/i2c-21/new_device', +'echo cpld_plain 0x66 > /sys/bus/i2c/devices/i2c-22/new_device'] + +def i2c_order_check(): + return 0 + +def device_install(): + global FORCE + + for i in range(0,len(mknod)): + #for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(1) + + status, output = log_os_system(mknod[i], 1) + if status: + print output + if FORCE == 0: + return status + + for i in range(0,len(sfp_map)): + status, output =log_os_system("echo qfx5210_64x_port"+str(i+1)+" 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + return + +def device_uninstall(): + global FORCE + + status, output =log_os_system("ls /sys/bus/i2c/devices/1-0076", 0) + + for i in range(0,len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" + status, output =log_os_system("echo 0x50 > "+ target, 1) + if status: + print output + if FORCE == 0: + return status + + nodelist = mknod + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print output + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_check() == False: + return False + if not device_exist(): + return False + return True + +def do_install(): + print "Checking system...." + if driver_check() == False: + print "No driver, installing...." + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" drivers detected...." + if not device_exist(): + print "No device, installing...." + status = device_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" devices detected...." + return + +def do_uninstall(): + print "Checking system...." + if not device_exist(): + print PROJECT_NAME.upper() +" has no device installed...." + else: + print "Removing device...." + status = device_uninstall() + if status: + if FORCE == 0: + return status + + if driver_check()== False : + print PROJECT_NAME.upper() +" has no driver installed...." + else: + print "Removing installed driver...." + status = driver_uninstall() + if status: + if FORCE == 0: + return status + + return + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key]= {} + for i in range(0,DEVICE_NO[key]): + ALL_DEVICE[key][key+str(i+1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0,len(buses)): + for j in range(0,len(nodes)): + if 'fan' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + else: + node = key+str(i+1) + path = i2c_prefix+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][ key+str(i+1)].append(path) + + #show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i+": ") + for j in sorted(ALL_DEVICE[i].keys()): + print(" "+j) + for k in (ALL_DEVICE[i][j]): + print(" "+" "+k) + return + +def show_eeprom(index): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] + node = node.replace(node.split("/")[-1], 'sfp_eeprom') + # check if got hexdump command in current environment + ret, log = log_os_system("which hexdump", 0) + ret, log2 = log_os_system("which busybox hexdump", 0) + if len(log): + hex_cmd = 'hexdump' + elif len(log2): + hex_cmd = ' busybox hexdump' + else: + log = 'Failed : no hexdump cmd!!' + logging.info(log) + print log + return 1 + + print node + ":" + ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) + if ret==0: + print log + else: + print "**********device no found**********" + return + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + + if args[0]=='led': + if int(args[1])>4: + show_set_help() + return + #print ALL_DEVICE['led'] + for i in range(0,len(ALL_DEVICE['led'])): + for k in (ALL_DEVICE['led']['led'+str(i+1)]): + ret, log = log_os_system("echo "+args[1]+" >"+k, 1) + if ret: + return ret + elif args[0]=='fan': + if int(args[1])>100: + show_set_help() + return + #print ALL_DEVICE['fan'] + #fan1~6 is all fine, all fan share same setting + node = ALL_DEVICE['fan'] ['fan1'][0] + node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') + ret, log = log_os_system("cat "+ node, 1) + if ret==0: + print ("Previous fan duty: " + log.strip() +"%") + ret, log = log_os_system("echo "+args[1]+" >"+node, 1) + if ret==0: + print ("Current fan duty: " + args[1] +"%") + return ret + elif args[0]=='sfp': + if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: + show_set_help() + return + if len(args)<2: + show_set_help() + return + + if int(args[2])>1: + show_set_help() + return + + #print ALL_DEVICE[args[0]] + for i in range(0,len(ALL_DEVICE[args[0]])): + for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: + if j.find('tx_disable')!= -1: + ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) + if ret: + return ret + + return + +#get digits inside a string. +#Ex: 31 for "sfp31" +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + +def device_traversal(): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print("============================================") + print(i.upper()+": ") + print("============================================") + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print " "+j+":", + for k in (ALL_DEVICE[i][j]): + ret, log = log_os_system("cat "+k, 0) + func = k.split("/")[-1].strip() + func = re.sub(j+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) + if ret==0: + print func+"="+log+" ", + else: + print func+"="+"X"+" ", + print + print("----------------------------------------------------------------") + + + print + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0076", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/platform_poweroff b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/platform_poweroff new file mode 100755 index 000000000000..27b23cff93ab --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-juniper/qfx5210/utils/platform_poweroff @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# +# Name: platform_poweroff version: 1.0 +# +# Description: This file contains the implementation of qfx5210 poweroff +# sequences +# +# Copyright (c) 2019, Juniper Networks, Inc. +# All rights reserved. +# +# Notice and Disclaimer: This code is licensed to you under the GNU General +# Public License as published by the Free Software Foundation, version 2 or +# any later version. This code is not an official Juniper product. You can +# obtain a copy of the License at +# +# OSS License: +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# +# Third-Party Code: This code may depend on other components under separate +# copyright notice and license terms. Your use of the source code for those +# components is subject to the terms and conditions of the respective license +# as noted in the Third-Party source code file. + +LOGFILE="/var/log/poweroff_log" +TIMESTAMP=`date "+%Y-%m-%d %H:%M:%S"` + +retry() +{ + local ret_value=0 + + if [ $# -ne 3 ]; then + echo 'usage: retry ""' + exit 1 + fi + retries=$1 + wait_retry=$2 + command=$3 + for i in `seq 1 $retries`; do + echo "$TIMESTAMP $command" >> $LOGFILE + $command + ret_value=$? + [ $ret_value -eq 0 ] && break + echo "$TIMESTAMP Error: Command Execution failed with $ret_value, waiting to retry..." >> $LOGFILE + sleep $wait_retry + done + return $ret_value +} + + +if [ -f /usr/sbin/i2cset ] && [ -f /usr/sbin/i2cget ]; then + #Check if the CPU CPLD address is present on the bus or not + #0x65 - Azurite CPU CPLD I2C Addr + retry 128 1 "i2cget -y 0 0x65 0x0" + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "$TIMESTAMP CPU CPLD I2C Addr is not accessible...Terminating the halt.." >> $LOGFILE + return $ret_value + fi + #Initing Halt condition + retry 128 1 "/usr/sbin/i2cset -f -y 0 0x65 0x14 0x00" + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "$TIMESTAMP Halt Init Failed..." >> $LOGFILE + return $ret_value + fi + #Enable 0x77 MUX's First channel to access 0x76 MUX + retry 128 1 "/usr/sbin/i2cset -f -y 0 0x77 0 0x01" + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "$TIMESTAMP Mux Level1 enabling failed..." >> $LOGFILE + return $ret_value + fi + #Enable 0x76 MUX's Third channel to access Main Board CPLD @0x60 + retry 128 1 "/usr/sbin/i2cset -f -y 0 0x76 0 0x04" + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "$TIMESTAMP Mux Level2 enabling failed..." >> $LOGFILE + return $ret_value + fi + + sync + + echo "$TIMESTAMP System is going to Halt now ........" | tee $LOGFILE + #Sleeping for sometime, so that Print can reach to logger + sleep 1 + #Asserting the Halt on Azurite + retry 128 1 "/usr/sbin/i2cset -f -y 0 0x60 0x24 0x00" + ret_val=$? + if [ $ret_val -ne 0 ]; then + echo "$TIMESTAMP Halt command execution failed...Terminating the halt.." | tee $LOGFILE + return $ret_value + fi +fi diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py b/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py index e69de29bb2d1..d94d4c9ec820 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * \ No newline at end of file diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py index 41d237143d58..814c7aca8178 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/chassis.py @@ -10,15 +10,7 @@ try: from sonic_platform_base.chassis_base import ChassisBase - from sonic_platform.psu import Psu - from sonic_platform.fan import Fan - from sonic_platform.fan import FAN_PATH - from sonic_platform.sfp import SFP - from sonic_platform.thermal import Thermal, initialize_thermals - from sonic_platform.watchdog import get_watchdog from sonic_daemon_base.daemon_base import Logger - from eeprom import Eeprom - from sfp_event import sfp_event from os import listdir from os.path import isfile, join import sys @@ -43,11 +35,6 @@ #reboot cause related definitions REBOOT_CAUSE_ROOT = HWMGMT_SYSTEM_ROOT -REBOOT_CAUSE_POWER_LOSS_FILE = 'reset_main_pwr_fail' -REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE = 'reset_asic_thermal' -REBOOT_CAUSE_WATCHDOG_FILE = 'reset_hotswap_or_wd' -REBOOT_CAUSE_MLNX_FIRMWARE_RESET = 'reset_fw_reset' - REBOOT_CAUSE_FILE_LENGTH = 1 #version retrieving related definitions @@ -84,14 +71,30 @@ def __init__(self): # Initialize SKU name self.sku_name = self._get_sku_name() + # move the initialization of each components to their dedicated initializer + # which will be called from platform + self.sfp_module_initialized = False + self.sfp_event_initialized = False + self.reboot_cause_initialized = False + logger.log_info("Chassis loaded successfully") + + def __del__(self): + if self.sfp_event_initialized: + self.sfp_event.deinitialize() + + def initialize_psu(self): + from sonic_platform.psu import Psu # Initialize PSU list + self.psu_module = Psu for index in range(MLNX_NUM_PSU): psu = Psu(index, self.sku_name) self._psu_list.append(psu) - # Initialize watchdog - self._watchdog = get_watchdog() - + def initialize_fan(self): + from sonic_platform.fan import Fan + from sonic_platform.fan import FAN_PATH + self.fan_module = Fan + self.fan_path = FAN_PATH # Initialize FAN list multi_rotor_in_drawer = False num_of_fan, num_of_drawer = self._extract_num_of_fans_and_fan_drawers() @@ -104,6 +107,11 @@ def __init__(self): fan = Fan(index, index) self._fan_list.append(fan) + def initialize_sfp(self): + from sonic_platform.sfp import SFP + + self.sfp_module = SFP + # Initialize SFP list port_position_tuple = self._get_port_position_tuple_by_sku_name() self.PORT_START = port_position_tuple[0] @@ -118,31 +126,82 @@ def __init__(self): sfp_module = SFP(index, 'SFP') self._sfp_list.append(sfp_module) + self.sfp_module_initialized = True + + def initialize_thermals(self): + from sonic_platform.thermal import initialize_thermals # Initialize thermals initialize_thermals(self.sku_name, self._thermal_list, self._psu_list) + def initialize_eeprom(self): + from eeprom import Eeprom # Initialize EEPROM - self.eeprom = Eeprom() + self._eeprom = Eeprom() + def initialize_components_list(self): # Initialize component list self._component_name_list.append(COMPONENT_BIOS) self._component_name_list.append(COMPONENT_FIRMWARE) self._component_name_list.append(COMPONENT_CPLD1) self._component_name_list.append(COMPONENT_CPLD2) - # Initialize sfp-change-listening stuff - self._init_sfp_change_event() + ############################################## + # SFP methods + ############################################## + def get_num_sfps(self): + """ + Retrieves the number of sfps available on this chassis + + Returns: + An integer, the number of sfps available on this chassis + """ + if not self.sfp_module_initialized: + self.initialize_sfp() + return len(self._sfp_list) + + def get_all_sfps(self): + """ + Retrieves all sfps available on this chassis + + Returns: + A list of objects derived from SfpBase representing all sfps + available on this chassis + """ + if not self.sfp_module_initialized: + self.initialize_sfp() + return self._sfp_list + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + if not self.sfp_module_initialized: + self.initialize_sfp() + + sfp = None + + try: + sfp = self._sfp_list[index] + except IndexError: + sys.stderr.write("SFP index {} out of range (0-{})\n".format( + index, len(self._sfp_list)-1)) - def _init_sfp_change_event(self): - self.sfp_event = sfp_event() - self.sfp_event.initialize() - self.MAX_SELECT_EVENT_RETURNED = self.PORT_END + return sfp def _extract_num_of_fans_and_fan_drawers(self): num_of_fan = 0 num_of_drawer = 0 - for f in listdir(FAN_PATH): - if isfile(join(FAN_PATH, f)): + for f in listdir(self.fan_path): + if isfile(join(self.fan_path, f)): match_obj = re.match('fan(\d+)_speed_get', f) if match_obj != None: if int(match_obj.group(1)) > num_of_fan: @@ -163,6 +222,30 @@ def _get_port_position_tuple_by_sku_name(self): position_tuple = port_position_tuple_list[hwsku_dict_port[self.sku_name]] return position_tuple + def get_watchdog(self): + """ + Retrieves hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + + Note: + We overload this method to ensure that watchdog is only initialized + when it is referenced. Currently, only one daemon can open the watchdog. + To initialize watchdog in the constructor causes multiple daemon + try opening watchdog when loading and constructing a chassis object + and fail. By doing so we can eliminate that risk. + """ + try: + if self._watchdog is None: + from sonic_platform.watchdog import get_watchdog + self._watchdog = get_watchdog() + except Exception as e: + logger.log_info("Fail to load watchdog due to {}".format(repr(e))) + + return self._watchdog + def get_base_mac(self): """ Retrieves the base MAC address for the chassis @@ -171,7 +254,7 @@ def get_base_mac(self): A string containing the MAC address in the format 'XX:XX:XX:XX:XX:XX' """ - return self.eeprom.get_base_mac() + return self._eeprom.get_base_mac() def get_serial_number(self): """ @@ -180,7 +263,7 @@ def get_serial_number(self): Returns: A string containing the hardware serial number for this chassis. """ - return self.eeprom.get_serial_number() + return self._eeprom.get_serial_number() def get_system_eeprom_info(self): """ @@ -191,7 +274,7 @@ def get_system_eeprom_info(self): OCP ONIE TlvInfo EEPROM format and values are their corresponding values. """ - return self.eeprom.get_system_eeprom_info() + return self._eeprom.get_system_eeprom_info() def _read_generic_file(self, filename, len): """ @@ -205,7 +288,7 @@ def _read_generic_file(self, filename, len): return result except Exception as e: logger.log_info("Fail to read file {} due to {}".format(filename, repr(e))) - return '' + return '0' def _verify_reboot_cause(self, filename): ''' @@ -215,6 +298,31 @@ def _verify_reboot_cause(self, filename): ''' return bool(int(self._read_generic_file(join(REBOOT_CAUSE_ROOT, filename), REBOOT_CAUSE_FILE_LENGTH).rstrip('\n'))) + def initialize_reboot_cause(self): + self.reboot_major_cause_dict = { + 'reset_main_pwr_fail' : self.REBOOT_CAUSE_POWER_LOSS, + 'reset_aux_pwr_or_ref' : self.REBOOT_CAUSE_POWER_LOSS, + 'reset_asic_thermal' : self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, + 'reset_hotswap_or_wd' : self.REBOOT_CAUSE_WATCHDOG, + 'reset_swb_wd' : self.REBOOT_CAUSE_WATCHDOG, + 'reset_sff_wd' : self.REBOOT_CAUSE_WATCHDOG + } + self.reboot_minor_cause_dict = { + 'reset_fw_reset' : "Reset by ASIC firmware", + 'reset_long_pb' : "Reset by long press on power button", + 'reset_short_pb' : "Reset by short press on power button", + 'reset_comex_thermal' : "ComEx thermal shutdown", + 'reset_comex_pwr_fail' : "ComEx power fail", + 'reset_comex_wd' : "Reset requested from ComEx", + 'reset_from_asic' : "Reset requested from ASIC", + 'reset_reload_bios' : "Reset caused by BIOS reload", + 'reset_sw_reset' : "Software reset", + 'reset_hotswap_or_halt' : "Reset caused by hotswap or halt", + 'reset_from_comex' : "Reset from ComEx", + 'reset_voltmon_upgrade_fail': "Reset due to voltage monitor devices upgrade failure" + } + self.reboot_cause_initialized = True + def get_reboot_cause(self): """ Retrieves the cause of the previous reboot @@ -227,21 +335,18 @@ def get_reboot_cause(self): to pass a description of the reboot cause. """ #read reboot causes files in the following order - minor_cause = '' - if self._verify_reboot_cause(REBOOT_CAUSE_POWER_LOSS_FILE): - major_cause = self.REBOOT_CAUSE_POWER_LOSS - elif self._verify_reboot_cause(REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC_FILE): - major_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC - elif self._verify_reboot_cause(REBOOT_CAUSE_WATCHDOG_FILE): - major_cause = self.REBOOT_CAUSE_WATCHDOG - else: - major_cause = self.REBOOT_CAUSE_HARDWARE_OTHER - if self._verify_reboot_cause(REBOOT_CAUSE_MLNX_FIRMWARE_RESET): - minor_cause = "Reset by ASIC firmware" - else: - major_cause = self.REBOOT_CAUSE_NON_HARDWARE + if not self.reboot_cause_initialized: + self.initialize_reboot_cause() + + for reset_file, reset_cause in self.reboot_major_cause_dict.iteritems(): + if self._verify_reboot_cause(reset_file): + return reset_cause, '' - return major_cause, minor_cause + for reset_file, reset_cause in self.reboot_minor_cause_dict.iteritems(): + if self._verify_reboot_cause(reset_file): + return self.REBOOT_CAUSE_HARDWARE_OTHER, reset_cause + + return self.REBOOT_CAUSE_NON_HARDWARE, '' def _get_cpld_version(self, version_file): cpld_version = self._read_generic_file(join(CPLD_VERSION_ROOT, version_file), CPLD_VERSION_MAX_LENGTH) @@ -383,6 +488,14 @@ def get_change_event(self, timeout=0): indicates that fan 0 has been removed, fan 2 has been inserted and sfp 11 has been removed. """ + # Initialize SFP event first + if not self.sfp_event_initialized: + from sonic_platform.sfp_event import sfp_event + self.sfp_event = sfp_event() + self.sfp_event.initialize() + self.MAX_SELECT_EVENT_RETURNED = self.PORT_END + self.sfp_event_initialized = True + wait_for_ever = (timeout == 0) port_dict = {} if wait_for_ever: diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py new file mode 100644 index 000000000000..fc555bc479a3 --- /dev/null +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/platform.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +############################################################################# +# Mellanox +# +# implementation of new platform api +############################################################################# + +try: + import subprocess + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Platform(PlatformBase): + def __init__(self): + PlatformBase.__init__(self) + if self._is_host(): + self._chassis = Chassis() + else: + self._chassis = Chassis() + self._chassis.initialize_psu() + self._chassis.initialize_fan() + self._chassis.initialize_eeprom() + self._chassis.initialize_components_list() + + def _is_host(self): + """ + Test whether current process is running on the host or an docker + return True for host and False for docker + """ + is_host = False + try: + proc = subprocess.Popen("docker --version 2>/dev/null", stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n') + if result != '': + is_host = True + + except OSError, e: + pass + + return is_host diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py index 9ea9c21899f5..be59451a8cb7 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/sfp.py @@ -63,6 +63,24 @@ XCVR_VENDOR_DATE_WIDTH = 8 XCVR_DOM_CAPABILITY_OFFSET = 92 XCVR_DOM_CAPABILITY_WIDTH = 2 +# to improve performance we retrieve all eeprom data via a single ethtool command +# in function get_transceiver_info and get_transceiver_bulk_status +# XCVR_INTERFACE_DATA_SIZE stands for the max size to be read +# this variable is only used by get_transceiver_info. +# please be noted that each time some new value added to the function +# we should make sure that it falls into the area +# [XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE] or +# adjust XCVR_INTERFACE_MAX_SIZE to contain the new data +# It's same for [QSFP_DOM_BULK_DATA_START, QSFP_DOM_BULK_DATA_SIZE] and +# [SFP_DOM_BULK_DATA_START, SFP_DOM_BULK_DATA_SIZE] which are used by +# get_transceiver_bulk_status +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 # definitions of the offset for values in OSFP info eeprom OSFP_TYPE_OFFSET = 0 @@ -229,7 +247,7 @@ def get_presence(self): bool: True if device is present, False if not """ presence = False - ethtool_cmd = "ethtool -m sfp{} 2>/dev/null".format(self.index) + ethtool_cmd = "ethtool -m sfp{} hex on offset 0 length 4 2>/dev/null".format(self.index) try: proc = subprocess.Popen(ethtool_cmd, stdout=subprocess.PIPE, shell=True, stderr=subprocess.STDOUT) stdout = proc.communicate()[0] @@ -261,6 +279,15 @@ def _read_eeprom_specific_bytes(self, offset, num_bytes): return eeprom_raw def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + if self.sfp_type == "QSFP": self.calibration = 1 sfpi_obj = sff8436InterfaceId() @@ -466,47 +493,37 @@ def get_transceiver_info(self): print("Error: sfp_object open failed") return None - sfp_interface_bulk_raw = self._read_eeprom_specific_bytes((offset + XCVR_INTFACE_BULK_OFFSET), interface_info_bulk_width) - if sfp_interface_bulk_raw is not None: - sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) - else: + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes(offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is None: return None - sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) - if sfp_vendor_name_raw is not None: - sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) - else: - return None + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) - if sfp_vendor_pn_raw is not None: - sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) - else: - return None + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET), vendor_rev_width) - if sfp_vendor_rev_raw is not None: - sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) - else: - return None + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) - if sfp_vendor_sn_raw is not None: - sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) - else: - return None + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_oui_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) - if sfp_vendor_oui_raw is not None: - sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) - else: - return None + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) - sfp_vendor_date_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) - if sfp_vendor_date_raw is not None: - sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) - else: - return None + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] transceiver_info_dict['manufacturename'] = sfp_vendor_name_data['data']['Vendor Name']['value'] @@ -578,84 +595,63 @@ def get_transceiver_bulk_status(self): """ transceiver_dom_info_dict = {} + dom_info_dict_keys = ['temperature', 'voltage', + 'rx1power', 'rx2power', + 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', + 'tx1power', 'tx2power', + 'tx3power', 'tx4power' + ] + transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + if self.sfp_type == OSFP_TYPE: - transceiver_dom_info_dict['temperature'] = 'N/A' - transceiver_dom_info_dict['voltage'] = 'N/A' - transceiver_dom_info_dict['rx1power'] = 'N/A' - 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'] = 'N/A' - 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'] = 'N/A' - transceiver_dom_info_dict['tx2power'] = 'N/A' - transceiver_dom_info_dict['tx3power'] = 'N/A' - transceiver_dom_info_dict['tx4power'] = 'N/A' + pass elif self.sfp_type == QSFP_TYPE: if not self.dom_supported: - return None + return transceiver_dom_info_dict offset = 0 sfpd_obj = sff8436Dom() if sfpd_obj is None: - return None + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes((offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict if self.dom_temp_supported: - dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) - if dom_temperature_raw is not None: - dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) - temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) - if temp is not None: - transceiver_dom_info_dict['temperature'] = temp - else: - transceiver_dom_info_dict['temperature'] = 'N/A' - else: - return None - else: - transceiver_dom_info_dict['temperature'] = 'N/A' + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start : end], 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp if self.dom_volt_supported: - dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) - if dom_voltage_raw is not None: - dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) - volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) - if volt is not None: - transceiver_dom_info_dict['voltage'] = volt - else: - transceiver_dom_info_dict['voltage'] = 'N/A' - else: - return None - else: - transceiver_dom_info_dict['voltage'] = 'N/A' + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start : end], 0) + volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt - dom_channel_monitor_raw = self._read_eeprom_specific_bytes((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) + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_data_raw[start : end], 0) if self.dom_tx_power_supported: transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value']) transceiver_dom_info_dict['tx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value']) transceiver_dom_info_dict['tx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value']) transceiver_dom_info_dict['tx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value']) - else: - 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' if self.dom_rx_power_supported: transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value']) transceiver_dom_info_dict['rx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value']) transceiver_dom_info_dict['rx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value']) transceiver_dom_info_dict['rx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value']) - else: - transceiver_dom_info_dict['rx1power'] = 'N/A' - 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']['TX1Bias']['value'] transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] @@ -664,46 +660,33 @@ def get_transceiver_bulk_status(self): else: if not self.dom_supported: - return None + return transceiver_dom_info_dict offset = 256 sfpd_obj = sff8472Dom() if sfpd_obj is None: - return None + return transceiver_dom_info_dict sfpd_obj._calibration_type = self.calibration - - dom_temperature_raw = self._read_eeprom_specific_bytes((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 None - dom_voltage_raw = self._read_eeprom_specific_bytes((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 None + dom_data_raw = self._read_eeprom_specific_bytes((offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) - dom_channel_monitor_raw = self._read_eeprom_specific_bytes((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 None + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_data_raw[start: end], 0) transceiver_dom_info_dict['temperature'] = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) transceiver_dom_info_dict['voltage'] = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(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'] = self._convert_string_to_num(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'] = self._convert_string_to_num(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 @@ -1036,7 +1019,7 @@ def get_tx_bias(self): sfpd_obj = sff8472Dom() if sfpd_obj is None: return None - sfpd_obj._calibration_type = 1 + sfpd_obj._calibration_type = self.calibration if self.dom_supported: dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) @@ -1145,7 +1128,7 @@ def get_tx_power(self): return None if self.dom_supported: - sfpd_obj._calibration_type = 1 + sfpd_obj._calibration_type = self.calibration dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) if dom_channel_monitor_raw is not None: diff --git a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py index 5195d378a468..6614e368e547 100644 --- a/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py +++ b/platform/mellanox/mlnx-platform-api/sonic_platform/thermal.py @@ -49,8 +49,8 @@ THERMAL_API_GET_HIGH_THRESHOLD:"cpu_pack_max" } thermal_api_handler_module = { - THERMAL_API_GET_TEMPERATURE:"temp_input_module{}", - THERMAL_API_GET_HIGH_THRESHOLD:"temp_crit_module{}" + THERMAL_API_GET_TEMPERATURE:"module{}_temp_input", + THERMAL_API_GET_HIGH_THRESHOLD:"module{}_temp_crit" } thermal_api_handler_psu = { THERMAL_API_GET_TEMPERATURE:"psu{}_temp", diff --git a/rules/docker-platform-monitor.mk b/rules/docker-platform-monitor.mk index 8a4c9391f8aa..617cf39e8b87 100644 --- a/rules/docker-platform-monitor.mk +++ b/rules/docker-platform-monitor.mk @@ -38,6 +38,7 @@ $(DOCKER_PLATFORM_MONITOR)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro # Mount Arista python library on Aboot images to be used by plugins $(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista:/usr/lib/python2.7/dist-packages/arista:ro +$(DOCKER_PLATFORM_MONITOR)_aboot_RUN_OPT += -v /usr/lib/python2.7/dist-packages/arista/utils/sonic_platform:/usr/lib/python2.7/dist-packages/sonic_platform:ro $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += sensors:/usr/bin/sensors $(DOCKER_PLATFORM_MONITOR)_BASE_IMAGE_FILES += smartctl:/usr/sbin/smartctl diff --git a/scripts/dbg_files.sh b/scripts/dbg_files.sh index 1515639bc9d7..6624fca83f34 100755 --- a/scripts/dbg_files.sh +++ b/scripts/dbg_files.sh @@ -2,8 +2,11 @@ # Provide file paths to archive for debug image as relative to src subdir # -for i in $debug_src_archive -do - find $i/ -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" -type f -done +if [ "$DEBUG_IMG" == "y" ] +then + for i in $DEBUG_SRC_ARCHIVE_DIRS + do + find src/$i/ -name "*.c" -o -name "*.cpp" -o -name "*.h" -o -name "*.hpp" -type f + done | tar -czf $DEBUG_SRC_ARCHIVE_FILE -T - +fi diff --git a/slave.mk b/slave.mk index 15e3f7738ede..6a52b71507db 100644 --- a/slave.mk +++ b/slave.mk @@ -37,6 +37,7 @@ PROJECT_ROOT = $(shell pwd) STRETCH_DEBS_PATH = $(TARGET_PATH)/debs/stretch STRETCH_FILES_PATH = $(TARGET_PATH)/files/stretch DBG_IMAGE_MARK = dbg +DBG_SRC_ARCHIVE_FILE = $(TARGET_PATH)/sonic_src.tar.gz CONFIGURED_PLATFORM := $(shell [ -f .platform ] && cat .platform || echo generic) PLATFORM_PATH = platform/$(CONFIGURED_PLATFORM) @@ -667,9 +668,13 @@ $(addprefix $(TARGET_PATH)/, $(SONIC_INSTALLERS)) : $(TARGET_PATH)/% : \ chmod +x sonic_debian_extension.sh, ) - export debug_src_archive="$(DBG_SRC_ARCHIVE)" + DEBUG_IMG="$(INSTALL_DEBUG_TOOLS)" \ + DEBUG_SRC_ARCHIVE_DIRS="$(DBG_SRC_ARCHIVE)" \ + DEBUG_SRC_ARCHIVE_FILE="$(DBG_SRC_ARCHIVE_FILE)" \ + scripts/dbg_files.sh DEBUG_IMG="$(INSTALL_DEBUG_TOOLS)" \ + DEBUG_SRC_ARCHIVE_FILE="$(DBG_SRC_ARCHIVE_FILE)" \ USERNAME="$(USERNAME)" \ PASSWORD="$(PASSWORD)" \ ./build_debian.sh $(LOG) diff --git a/src/libteam/patch/0010-When-read-of-timerfd-returned-0-don-t-consider-this-.patch b/src/libteam/patch/0010-When-read-of-timerfd-returned-0-don-t-consider-this-.patch new file mode 100644 index 000000000000..e703d73e0263 --- /dev/null +++ b/src/libteam/patch/0010-When-read-of-timerfd-returned-0-don-t-consider-this-.patch @@ -0,0 +1,39 @@ +From 038bed6fe3970dc829dbf9a282f7bea7198e7826 Mon Sep 17 00:00:00 2001 +From: Pavel Shirshov +Date: Wed, 28 Aug 2019 16:39:35 -0700 +Subject: [PATCH] When read of timerfd returned 0, don't consider this an error + +Just skip this event. +--- + teamd/teamd.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/teamd/teamd.c b/teamd/teamd.c +index 96794e8..a5ce745 100644 +--- a/teamd/teamd.c ++++ b/teamd/teamd.c +@@ -285,6 +285,10 @@ static int handle_period_fd(int fd) + teamd_log_err("read() failed."); + return -errno; + } ++ if (ret == 0) { ++ teamd_log_warn("read() for timer_fd returned 0."); ++ return 1; ++ } + if (ret != sizeof(uint64_t)) { + teamd_log_err("read() returned unexpected number of bytes."); + return -EINVAL; +@@ -345,7 +349,9 @@ static int teamd_run_loop_do_callbacks(struct list_item *lcb_list, fd_set *fds, + continue; + if (lcb->is_period) { + err = handle_period_fd(lcb->fd); +- if (err) ++ if (err == 1) ++ continue; /* timerfd returned 0. Don't do anything */ ++ if (err < 0) + return err; + } + err = lcb->func(ctx, events, lcb->priv); +-- +2.7.4 + diff --git a/src/libteam/patch/series b/src/libteam/patch/series index c30bdc7dd861..7be69525d9d0 100644 --- a/src/libteam/patch/series +++ b/src/libteam/patch/series @@ -7,3 +7,4 @@ 0007-Send-LACP-PDU-immediately-if-our-state-changed.patch 0008-libteam-Add-warm_reboot-mode.patch 0009-Fix-ifinfo_link_with_port-race-condition-with-newlink.patch +0010-When-read-of-timerfd-returned-0-don-t-consider-this-.patch diff --git a/src/sonic-config-engine/minigraph.py b/src/sonic-config-engine/minigraph.py index 8461aad1fed5..a65f2ef0007b 100644 --- a/src/sonic-config-engine/minigraph.py +++ b/src/sonic-config-engine/minigraph.py @@ -716,19 +716,21 @@ def parse_xml(filename, platform=None, port_config_file=None): results['TACPLUS_SERVER'] = dict((item, {'priority': '1', 'tcp_port': '49'}) for item in tacacs_servers) results['ACL_TABLE'] = acls - mirror_sessions = {} - if erspan_dst: - lo_addr = '0.0.0.0' - for lo in lo_intfs: - lo_network = ipaddress.IPNetwork(lo[1]) - if lo_network.version == 4: - lo_addr = str(lo_network.ip) - break - count = 0 - for dst in erspan_dst: - mirror_sessions['everflow{}'.format(count)] = {"dst_ip": dst, "src_ip": lo_addr} - count += 1 - results['MIRROR_SESSION'] = mirror_sessions + + # Do not configure the minigraph's mirror session, which is currently unused + # mirror_sessions = {} + # if erspan_dst: + # lo_addr = '0.0.0.0' + # for lo in lo_intfs: + # lo_network = ipaddress.IPNetwork(lo[1]) + # if lo_network.version == 4: + # lo_addr = str(lo_network.ip) + # break + # count = 0 + # for dst in erspan_dst: + # mirror_sessions['everflow{}'.format(count)] = {"dst_ip": dst, "src_ip": lo_addr} + # count += 1 + # results['MIRROR_SESSION'] = mirror_sessions # Special parsing for spine chassis frontend routers if current_device['type'] == spine_chassis_frontend_role: diff --git a/src/sonic-config-engine/tests/test_cfggen.py b/src/sonic-config-engine/tests/test_cfggen.py index a28e1263c475..d6544dc063e4 100644 --- a/src/sonic-config-engine/tests/test_cfggen.py +++ b/src/sonic-config-engine/tests/test_cfggen.py @@ -104,10 +104,11 @@ def test_minigraph_acl(self): "'SSH_ACL': {'services': ['SSH'], 'type': 'CTRLPLANE', 'policy_desc': 'SSH_ACL'}, " "'EVERFLOWV6': {'type': 'MIRRORV6', 'policy_desc': 'EVERFLOWV6', 'ports': ['PortChannel01', 'PortChannel02', 'PortChannel03', 'PortChannel04', 'Ethernet24', 'Ethernet40', 'Ethernet20', 'Ethernet44', 'Ethernet48', 'Ethernet28', 'Ethernet96', 'Ethernet92', 'Ethernet76', 'Ethernet72', 'Ethernet52', 'Ethernet80', 'Ethernet56', 'Ethernet32', 'Ethernet16', 'Ethernet36', 'Ethernet12', 'Ethernet60', 'Ethernet8', 'Ethernet4', 'Ethernet0', 'Ethernet64', 'Ethernet68', 'Ethernet84', 'Ethernet88', 'Ethernet108', 'Ethernet104', 'Ethernet100']}}") - def test_minigraph_everflow(self): - argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v MIRROR_SESSION' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '2.2.2.2'}}") +# everflow portion is not used +# def test_minigraph_everflow(self): +# argument = '-m "' + self.sample_graph_t0 + '" -p "' + self.port_config + '" -v MIRROR_SESSION' +# output = self.run_script(argument) +# self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '2.2.2.2'}}") def test_minigraph_mgmt_ports(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v MGMT_PORT' @@ -234,10 +235,11 @@ def test_minigraph_extra_ethernet_interfaces(self): "'Ethernet20': {'alias': 'fortyGigE0/20', 'pfc_asym': 'off', 'lanes': '45,46,47,48', 'description': 'fortyGigE0/20', 'mtu': '9100'}, " "'Ethernet24': {'alias': 'fortyGigE0/24', 'pfc_asym': 'off', 'lanes': '5,6,7,8', 'description': 'fortyGigE0/24', 'mtu': '9100'}}") - def test_metadata_everflow(self): - argument = '-m "' + self.sample_graph_metadata + '" -p "' + self.port_config + '" -v "MIRROR_SESSION"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '10.0.100.1'}}") +# everflow portion is not used +# def test_metadata_everflow(self): +# argument = '-m "' + self.sample_graph_metadata + '" -p "' + self.port_config + '" -v "MIRROR_SESSION"' +# output = self.run_script(argument) +# self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '10.0.100.1'}}") def test_metadata_tacacs(self): argument = '-m "' + self.sample_graph_metadata + '" -p "' + self.port_config + '" -v "TACPLUS_SERVER"' diff --git a/src/sonic-config-engine/tests/test_minigraph_case.py b/src/sonic-config-engine/tests/test_minigraph_case.py index ded5d6182341..71d0c3d7db57 100644 --- a/src/sonic-config-engine/tests/test_minigraph_case.py +++ b/src/sonic-config-engine/tests/test_minigraph_case.py @@ -59,10 +59,11 @@ def test_render_template(self): output = self.run_script(argument) self.assertEqual(output.strip(), 'value1\nvalue2') - def test_minigraph_everflow(self): - argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v MIRROR_SESSION' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '10.0.100.1'}}") +# everflow portion is not used +# def test_minigraph_everflow(self): +# argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v MIRROR_SESSION' +# output = self.run_script(argument) +# self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '10.0.100.1'}}") def test_minigraph_interfaces(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v \'INTERFACE.keys()\'' @@ -104,10 +105,11 @@ def test_minigraph_neighbor_metadata(self): output = self.run_script(argument) self.assertEqual(output.strip(), "{'switch-01t1': {'lo_addr': '10.1.0.186/32', 'mgmt_addr': '10.7.0.196/26', 'hwsku': 'Force10-S6000', 'type': 'LeafRouter', 'deployment_id': '2'}}") - def test_metadata_everflow(self): - argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "MIRROR_SESSION"' - output = self.run_script(argument) - self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '10.0.100.1'}}") +# everflow portion is not used +# def test_metadata_everflow(self): +# argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "MIRROR_SESSION"' +# output = self.run_script(argument) +# self.assertEqual(output.strip(), "{'everflow0': {'src_ip': '10.1.0.32', 'dst_ip': '10.0.100.1'}}") def test_metadata_tacacs(self): argument = '-m "' + self.sample_graph + '" -p "' + self.port_config + '" -v "TACPLUS_SERVER"' diff --git a/src/sonic-device-data/tests/config_checker b/src/sonic-device-data/tests/config_checker index 29f1ba3cd74b..a0e3b0cbd45c 100755 --- a/src/sonic-device-data/tests/config_checker +++ b/src/sonic-device-data/tests/config_checker @@ -33,7 +33,7 @@ def check_file(file_name): # Remove trailing unit ".$" p = re.sub(r"\.[0-9]+$", '', p) # Remove trailing port name - p = re.sub(r"_[cxg]e(\d+)?$", '', p) + p = re.sub(r"_[cxg][de](\d+)?$", '', p) # Remove trailing port id "{id/number}" p = re.sub(r"\{.*\}", '', p) # Remove trailing port name example diff --git a/src/sonic-device-data/tests/permitted_list b/src/sonic-device-data/tests/permitted_list index 6e5a066fff65..47eea9fa9dba 100644 --- a/src/sonic-device-data/tests/permitted_list +++ b/src/sonic-device-data/tests/permitted_list @@ -132,6 +132,7 @@ serdes_pre_driver_current serdes_preemphasis serdes_rx_los serdes_sgmii_m +serdes_tx_taps skip_L2_USER_ENTRY sram_scan_enable stable_size diff --git a/src/sonic-utilities b/src/sonic-utilities index cb0e745d6ad1..a6a44e82402b 160000 --- a/src/sonic-utilities +++ b/src/sonic-utilities @@ -1 +1 @@ -Subproject commit cb0e745d6ad105f5bc486ec77955f06a7c25912e +Subproject commit a6a44e82402bdcc48423ac93e137673e59e50c78 diff --git a/src/tacacs/nss/0005-libnss-Modify-parsing-of-IP-addr-and-port-number-str.patch b/src/tacacs/nss/0005-libnss-Modify-parsing-of-IP-addr-and-port-number-str.patch new file mode 100644 index 000000000000..247972b63b55 --- /dev/null +++ b/src/tacacs/nss/0005-libnss-Modify-parsing-of-IP-addr-and-port-number-str.patch @@ -0,0 +1,26 @@ +From aa8af2b2400b7bbcbe7af0cb50047a98e93660ca Mon Sep 17 00:00:00 2001 +From: SuvarnaMeenakshi +Date: Thu, 29 Aug 2019 09:44:24 -0700 +Subject: [PATCH] libnss: Modify parsing of IP addr and port number string to + support IPv6 + +--- + nss_tacplus.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/nss_tacplus.c b/nss_tacplus.c +index f2a86e1..3ff3c35 100644 +--- a/nss_tacplus.c ++++ b/nss_tacplus.c +@@ -98,7 +98,7 @@ static int parse_tac_server(char *srv_buf) + hints.ai_socktype = SOCK_STREAM; + + srv = token + 7; +- port = strchr(srv, ':'); ++ port = strrchr(srv, ':'); + if(port) { + *port = '\0'; + port++; +-- +2.17.1 + diff --git a/src/tacacs/nss/Makefile b/src/tacacs/nss/Makefile index 51a5d63ebd1b..b9e16e812d23 100644 --- a/src/tacacs/nss/Makefile +++ b/src/tacacs/nss/Makefile @@ -22,6 +22,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : git $(GIT_APPLY) ../0002-Enable-modifying-local-user-permission.patch git $(GIT_APPLY) ../0003-management-vrf-support.patch git $(GIT_APPLY) ../0004-Skip-accessing-tacacs-servers-for-local-non-tacacs-u.patch + git $(GIT_APPLY) ../0005-libnss-Modify-parsing-of-IP-addr-and-port-number-str.patch dpkg-buildpackage -rfakeroot -b -us -uc popd diff --git a/src/tacacs/pam/0005-pam-Modify-parsing-of-IP-address-and-port-number-to-.patch b/src/tacacs/pam/0005-pam-Modify-parsing-of-IP-address-and-port-number-to-.patch new file mode 100644 index 000000000000..541333232b56 --- /dev/null +++ b/src/tacacs/pam/0005-pam-Modify-parsing-of-IP-address-and-port-number-to-.patch @@ -0,0 +1,31 @@ +From 264de96e8a1c411371f9fc20b0b5b00c10e7052d Mon Sep 17 00:00:00 2001 +From: SuvarnaMeenakshi +Date: Thu, 29 Aug 2019 09:51:43 -0700 +Subject: [PATCH] pam: Modify parsing of IP address and port number to support + IPv6 + +--- + support.c | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/support.c b/support.c +index 44efee3..7c00618 100644 +--- a/support.c ++++ b/support.c +@@ -225,11 +226,11 @@ int _pam_parse (int argc, const char **argv) { + + if (*server_buf == '[' && (close_bracket = strchr(server_buf, ']')) != NULL) { /* Check for URI syntax */ + server_name = server_buf + 1; +- port = strchr(close_bracket, ':'); ++ port = strrchr(close_bracket, ':'); + *close_bracket = '\0'; + } else { /* Fall back to traditional syntax */ + server_name = server_buf; +- port = strchr(server_buf, ':'); ++ port = strrchr(server_buf, ':'); + } + if (port != NULL) { + *port = '\0'; +-- +2.17.1 + diff --git a/src/tacacs/pam/Makefile b/src/tacacs/pam/Makefile index c35f1aff37b3..487cf975fd77 100644 --- a/src/tacacs/pam/Makefile +++ b/src/tacacs/pam/Makefile @@ -18,6 +18,7 @@ $(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : git apply ../0002-Fix-libtac2-bin-install-directory-error.patch git apply ../0003-Obfuscate-key-before-printing-to-syslog.patch git apply ../0004-management-vrf-support.patch + git apply ../0005-pam-Modify-parsing-of-IP-address-and-port-number-to-.patch dpkg-buildpackage -rfakeroot -b -us -uc popd