From 744fd7889561fe883ea2c1f662186d51d6e8dac1 Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Tue, 1 Oct 2019 18:55:49 +0700 Subject: [PATCH 01/17] [platform/broadcom] Add Celestica Silverstone-DP platform module --- .../installer.conf | 1 + platform/broadcom/one-image.mk | 3 +- platform/broadcom/platform-modules-cel.mk | 8 +- .../sonic-platform-modules-cel/debian/control | 5 + .../platform-modules-silverstone-dp.init | 69 ++ .../platform-modules-silverstone-dp.install | 2 + .../platform-modules-silverstone-dp.postinst | 3 + .../sonic-platform-modules-cel/debian/rules | 2 +- .../cfg/silverstone-dp-modules.conf | 15 + .../silverstone-dp/modules/Makefile | 1 + .../silverstone-dp/modules/baseboard-lpc.c | 433 +++++++++ .../silverstone-dp/modules/cls-switchboard.c | 535 +++++++++++ .../silverstone-dp/modules/i2c-ocores.c | 846 ++++++++++++++++++ .../silverstone-dp/modules/i2c-ocores.h | 22 + .../silverstone-dp/modules/mc24lc64t.c | 174 ++++ .../silverstone-dp/modules/switch_cpld.c | 428 +++++++++ .../silverstone-dp/modules/xcvr-cls.c | 520 +++++++++++ .../silverstone-dp/modules/xcvr-cls.h | 41 + .../platform-modules-silverstone-dp.service | 13 + 19 files changed, 3118 insertions(+), 3 deletions(-) create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/installer.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/cfg/silverstone-dp-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/baseboard-lpc.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/mc24lc64t.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/switch_cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.h create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/systemd/platform-modules-silverstone-dp.service diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/installer.conf b/device/celestica/x86_64-cel_silverstone_dp-r0/installer.conf new file mode 100644 index 000000000000..b8b5b9419485 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/installer.conf @@ -0,0 +1 @@ +CONSOLE_SPEED=115200 \ No newline at end of file diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 3582116932b1..512cc5ca0f2e 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -54,7 +54,8 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(BRCM_XLR_GTS_PLATFORM_MODULE) \ $(DELTA_AG9032V2A_PLATFORM_MODULE) \ $(JUNIPER_QFX5210_PLATFORM_MODULE) \ - $(CEL_SILVERSTONE_PLATFORM_MODULE) + $(CEL_SILVERSTONE_PLATFORM_MODULE) \ + $(CEL_SILVERSTONE-DP_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-cel.mk b/platform/broadcom/platform-modules-cel.mk index b7371e3282de..6114f81cbf96 100644 --- a/platform/broadcom/platform-modules-cel.mk +++ b/platform/broadcom/platform-modules-cel.mk @@ -1,12 +1,14 @@ -# Celestica DX010 and Haliburton Platform modules +# Celestica Platform modules CEL_DX010_PLATFORM_MODULE_VERSION = 0.9 CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.9 CEL_SILVERSTONE_PLATFORM_MODULE_VERSION = 0.9 +CEL_SILVERSTONE-DP_PLATFORM_MODULE_VERSION = 0.9 export CEL_DX010_PLATFORM_MODULE_VERSION export CEL_HALIBURTON_PLATFORM_MODULE_VERSION export CEL_SILVERSTONE_PLATFORM_MODULE_VERSION +export CEL_SILVERSTONE-DP_PLATFORM_MODULE_VERSION CEL_DX010_PLATFORM_MODULE = platform-modules-dx010_$(CEL_DX010_PLATFORM_MODULE_VERSION)_amd64.deb $(CEL_DX010_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-cel @@ -22,4 +24,8 @@ CEL_SILVERSTONE_PLATFORM_MODULE = platform-modules-silverstone_$(CEL_SILVERSTONE $(CEL_SILVERSTONE_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone-r0 $(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE_PLATFORM_MODULE))) +CEL_SILVERSTONE-DP_PLATFORM_MODULE = platform-modules-silverstone-dp_$(CEL_SILVERSTONE-DP_PLATFORM_MODULE_VERSION)_amd64.deb +$(CEL_SILVERSTONE-DP_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone_dp-r0 +$(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE-DP_PLATFORM_MODULE))) + SONIC_STRETCH_DEBS += $(CEL_DX010_PLATFORM_MODULE) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/control b/platform/broadcom/sonic-platform-modules-cel/debian/control index 2e9b578872fa..e62ac7cd0049 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/control +++ b/platform/broadcom/sonic-platform-modules-cel/debian/control @@ -20,3 +20,8 @@ Package: platform-modules-silverstone Architecture: amd64 Depends: linux-image-4.9.0-9-2-amd64 Description: kernel modules for platform devices such as led, sfp. + +Package: platform-modules-silverstone-dp +Architecture: amd64 +Depends: linux-image-4.9.0-9-2-amd64 +Description: kernel modules for platform devices such as led, sfp. diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init new file mode 100644 index 000000000000..e1c831c160bf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init @@ -0,0 +1,69 @@ +#!/bin/bash + +### BEGIN INIT INFO +# Provides: setup-board +# Required-Start: $portmap +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Setup SilverStone DP board. +### END INIT INFO + + +case "$1" in +start) + echo -n "Setting up board... " + + modprobe i2c-dev + modprobe ipmi_devintf + modprobe mc24lc64t + modprobe baseboard-lpc + modprobe i2c-ocores + modprobe cls-switchboard + modprobe xcvr-cls + modprobe switch_cpld + + # Instantiate TLV EEPROM device on I801 bus + devname=`cat /sys/bus/i2c/devices/i2c-0/name` + if [[ $devname == 'SMBus I801 adapter at '* ]]; then + echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device + fi + + # Clear syseeprom cache + decode-syseeprom --init 2> /dev/null & + + # Attach switchboard CPLD i2c device + echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-4/new_device + + # Attach Optical Module EEPROM + # use optoe1 for QSFP, use optoe3 for QSFP-DD. + for i in {10..33} + do + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device + done + + for i in {34..39} + do + echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device + done + + echo "done." + ;; + +stop) + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-silverstone.init {start|stop}" + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install new file mode 100644 index 000000000000..e9b9ab4f8059 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install @@ -0,0 +1,2 @@ +silverstone-dp/cfg/silverstone-dp-modules.conf etc/modules-load.d +silverstone-dp/systemd/platform-modules-silverstone-dp.service lib/systemd/system \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst new file mode 100644 index 000000000000..e72b729a03e4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst @@ -0,0 +1,3 @@ +depmod -a +systemctl enable platform-modules-silverstone-dp.service +systemctl start platform-modules-silverstone-dp.service \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index dd5452ccaa11..6ea843f938d4 100755 --- a/platform/broadcom/sonic-platform-modules-cel/debian/rules +++ b/platform/broadcom/sonic-platform-modules-cel/debian/rules @@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= dx010 haliburton silverstone +MODULE_DIRS:= dx010 haliburton silverstone silverstone-dp %: dh $@ diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/cfg/silverstone-dp-modules.conf b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/cfg/silverstone-dp-modules.conf new file mode 100644 index 000000000000..cb8dcf640ba3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/cfg/silverstone-dp-modules.conf @@ -0,0 +1,15 @@ +# /etc/modules: kernel modules to load at boot time. +# +# This file contains the names of kernel modules that should be loaded +# at boot time, one per line. Lines beginning with "#" are ignored. + +i2c-i801 +i2c-isch +i2c-ismt +i2c-dev +i2c-mux +i2c-smbus + +i2c-mux-pca954x +ipmi_devintf +ipmi_si \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile new file mode 100644 index 000000000000..2702d08e3a31 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile @@ -0,0 +1 @@ +obj-m := baseboard-lpc.o mc24lc64t.o cls-switchboard.o xcvr-cls.o i2c-ocores.o switch_cpld.o \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/baseboard-lpc.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/baseboard-lpc.c new file mode 100644 index 000000000000..b6291f7d3ce4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/baseboard-lpc.c @@ -0,0 +1,433 @@ +/* + * baseboard-lpc.c - The CPLD driver for the Base Board of Silverstone + * The driver implement sysfs to access CPLD register on the baseboard of Silverstone via LPC bus. + * Copyright (C) 2018 Celestica Corp. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRIVER_NAME "baseboard-lpc" +/** + * CPLD register address for read and write. + */ +#define VERSION_ADDR 0xA100 +#define SCRATCH_ADDR 0xA101 +#define BLT_MONTH_ADDR 0xA102 +#define BLT_DATE_ADDR 0xA103 +#define REBOOT_CAUSE 0xA106 +#define SYS_LED_ADDR 0xA162 +#define CPLD_REGISTER_SIZE 0x93 + +/* System reboot cause recorded in CPLD */ +static const struct { + const char *reason; + u8 reset_code; +} reboot_causes[] = { + {"POR", 0x11}, + {"soft-warm-rst", 0x22}, + {"soft-cold-rst", 0x33}, + {"warm-rst", 0x44}, + {"cold-rst", 0x55}, + {"wdt-rst", 0x66}, + {"power-cycle", 0x77} +}; + +struct cpld_b_data { + struct mutex cpld_lock; + uint16_t read_addr; +}; + +struct cpld_b_data *cpld_data; + +static ssize_t scratch_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + unsigned char data = 0; + mutex_lock(&cpld_data->cpld_lock); + data = inb(SCRATCH_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return sprintf(buf,"0x%2.2x\n", data); +} + +static ssize_t scratch_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + unsigned long data; + char *last; + + mutex_lock(&cpld_data->cpld_lock); + data = (uint16_t)strtoul(buf,&last,16); + if(data == 0 && buf == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + outb(data, SCRATCH_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_RW(scratch); + + +/* CPLD version attributes */ +static ssize_t version_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 version; + mutex_lock(&cpld_data->cpld_lock); + version = inb(VERSION_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return sprintf(buf, "%d.%d\n", version >> 4, version & 0x0F); +} +static DEVICE_ATTR_RO(version); + +/* CPLD version attributes */ +static ssize_t build_date_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u8 month, day_of_month; + mutex_lock(&cpld_data->cpld_lock); + day_of_month = inb(BLT_DATE_ADDR); + month = inb(BLT_MONTH_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return sprintf(buf, "%x/%x\n", day_of_month, month); +} +static DEVICE_ATTR_RO(build_date); + + +static ssize_t getreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint16_t addr; + char *last; + + addr = (uint16_t)strtoul(buf,&last,16); + if(addr == 0 && buf == last){ + return -EINVAL; + } + cpld_data->read_addr = addr; + return count; +} + +static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + int len = 0; + + mutex_lock(&cpld_data->cpld_lock); + len = sprintf(buf, "0x%2.2x\n",inb(cpld_data->read_addr)); + mutex_unlock(&cpld_data->cpld_lock); + return len; +} +static DEVICE_ATTR_RW(getreg); + +static ssize_t setreg_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint16_t addr; + uint8_t value; + char *tok; + char clone[count]; + char *pclone = clone; + char *last; + + strcpy(clone, buf); + + mutex_lock(&cpld_data->cpld_lock); + tok = strsep((char**)&pclone, " "); + if(tok == NULL){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + addr = (uint16_t)strtoul(tok,&last,16); + if(addr == 0 && tok == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + + tok = strsep((char**)&pclone, " "); + if(tok == NULL){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + value = (uint8_t)strtoul(tok,&last,16); + if(value == 0 && tok == last){ + mutex_unlock(&cpld_data->cpld_lock); + return -EINVAL; + } + + outb(value,addr); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_WO(setreg); + +/** + * Read all CPLD register in binary mode. + */ +static ssize_t dump_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, char *buf, + loff_t off, size_t count) +{ + unsigned long i=0; + ssize_t status; + + mutex_lock(&cpld_data->cpld_lock); +begin: + if(i < count){ + buf[i++] = inb(VERSION_ADDR + off); + off++; + msleep(1); + goto begin; + } + status = count; + + mutex_unlock(&cpld_data->cpld_lock); + return status; +} +static BIN_ATTR_RO(dump, CPLD_REGISTER_SIZE); + +/** + * Show system led status - on/off/1hz/4hz + * @return Hex string read from scratch register. + */ +static ssize_t sys_led_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + unsigned char data = 0; + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + data = data & 0x3; + return sprintf(buf, "%s\n", + data == 0x03 ? "off" : data == 0x02 ? "4hz" : data ==0x01 ? "1hz": "on"); +} + +/** + * Set the status of system led - on/off/1hz/4hz + */ +static ssize_t sys_led_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + unsigned char led_status,data; + if(sysfs_streq(buf, "off")){ + led_status = 0x03; + }else if(sysfs_streq(buf, "4hz")){ + led_status = 0x02; + }else if(sysfs_streq(buf, "1hz")){ + led_status = 0x01; + }else if(sysfs_streq(buf, "on")){ + led_status = 0x00; + }else{ + count = -EINVAL; + return count; + } + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + data = data & ~(0x3); + data = data | led_status; + outb(data, SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_RW(sys_led); + +/** + * Show system led color - both/green/yellow/none + * @return Current led color. + */ +static ssize_t sys_led_color_show(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + unsigned char data = 0; + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + data = (data >> 4) & 0x3; + return sprintf(buf, "%s\n", + data == 0x03 ? "off" : data == 0x02 ? "yellow" : data ==0x01 ? "green": "both"); +} + +/** + * Set the color of system led - both/green/yellow/none + */ +static ssize_t sys_led_color_store(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + unsigned char led_status,data; + if(sysfs_streq(buf, "off")){ + led_status = 0x03; + }else if(sysfs_streq(buf, "yellow")){ + led_status = 0x02; + }else if(sysfs_streq(buf, "green")){ + led_status = 0x01; + }else if(sysfs_streq(buf, "both")){ + led_status = 0x00; + }else{ + count = -EINVAL; + return count; + } + mutex_lock(&cpld_data->cpld_lock); + data = inb(SYS_LED_ADDR); + data = data & ~( 0x3 << 4); + data = data | (led_status << 4); + outb(data, SYS_LED_ADDR); + mutex_unlock(&cpld_data->cpld_lock); + return count; +} +static DEVICE_ATTR_RW(sys_led_color); + +static ssize_t reboot_cause_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + ssize_t status; + u8 reg; + int i; + + mutex_lock(&cpld_data->cpld_lock); + reg = inb(REBOOT_CAUSE); + mutex_unlock(&cpld_data->cpld_lock); + + status = 0; + dev_dbg(dev,"reboot: 0x%x\n", (u8)reg); + for(i = 0; i < ARRAY_SIZE(reboot_causes); i++){ + if((u8)reg == reboot_causes[i].reset_code){ + status = sprintf(buf, "%s\n", + reboot_causes[i].reason); + break; + } + } + return status; +} +DEVICE_ATTR_RO(reboot_cause); + +static struct attribute *cpld_b_attrs[] = { + &dev_attr_version.attr, + &dev_attr_build_date.attr, + &dev_attr_scratch.attr, + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, + &dev_attr_sys_led.attr, + &dev_attr_sys_led_color.attr, + &dev_attr_reboot_cause.attr, + NULL, +}; + +static struct bin_attribute *cpld_b_bin_attrs[] = { + &bin_attr_dump, + NULL, +}; + +static struct attribute_group cpld_b_attrs_grp = { + .attrs = cpld_b_attrs, + .bin_attrs = cpld_b_bin_attrs, +}; + +static struct resource cpld_b_resources[] = { + { + .start = 0xA100, + .end = 0xA192, + .flags = IORESOURCE_IO, + }, +}; + +static void cpld_b_dev_release( struct device * dev) +{ + return; +} + +static struct platform_device cpld_b_dev = { + .name = DRIVER_NAME, + .id = -1, + .num_resources = ARRAY_SIZE(cpld_b_resources), + .resource = cpld_b_resources, + .dev = { + .release = cpld_b_dev_release, + } +}; + +static int cpld_b_drv_probe(struct platform_device *pdev) +{ + struct resource *res; + int err = 0; + + cpld_data = devm_kzalloc(&pdev->dev, sizeof(struct cpld_b_data), + GFP_KERNEL); + if (!cpld_data) + return -ENOMEM; + + mutex_init(&cpld_data->cpld_lock); + + cpld_data->read_addr = VERSION_ADDR; + + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (unlikely(!res)) { + printk(KERN_ERR "Specified Resource Not Available...\n"); + return -ENODEV; + } + + err = sysfs_create_group(&pdev->dev.kobj, &cpld_b_attrs_grp); + if (err) { + printk(KERN_ERR "Cannot create sysfs for baseboard CPLD\n"); + return err; + } + return 0; +} + +static int cpld_b_drv_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&pdev->dev.kobj, &cpld_b_attrs_grp); + return 0; +} + +static struct platform_driver cpld_b_drv = { + .probe = cpld_b_drv_probe, + .remove = __exit_p(cpld_b_drv_remove), + .driver = { + .name = DRIVER_NAME, + }, +}; + +int cpld_b_init(void) +{ + // Register platform device and platform driver + platform_device_register(&cpld_b_dev); + platform_driver_register(&cpld_b_drv); + return 0; +} + +void cpld_b_exit(void) +{ + // Unregister platform device and platform driver + platform_driver_unregister(&cpld_b_drv); + platform_device_unregister(&cpld_b_dev); +} + +module_init(cpld_b_init); +module_exit(cpld_b_exit); + + +MODULE_AUTHOR("Celestica Inc."); +MODULE_DESCRIPTION("Celestica Silverstone CPLD baseboard driver"); +MODULE_VERSION("0.2.0"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c new file mode 100644 index 000000000000..ebe5e7742a86 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c @@ -0,0 +1,535 @@ +/* + * cls-switchboard.c - PCI device driver for Silverstone DP Switch board FPGA. + * + * Author: Pradchaya Phucharoen + * + * Copyright (C) 2019 Celestica Corp. + * + * 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. + * + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-ocores.h" +#include "xcvr-cls.h" + +#define MOD_VERSION "2.1.1" +#define DRV_NAME "cls-switchboard" + +#define I2C_MUX_CHANNEL(_ch, _adap_id, _deselect) \ + [_ch] = { .adap_id = _adap_id, .deselect_on_exit = _deselect } + +#define FPGA_PCIE_DEVICE_ID 0x7021 +#define MMIO_BAR 0 +#define I2C_BUS_OFS 9 + +/* I2C ocore configurations */ +#define OCORE_REGSHIFT 2 +#define OCORE_IP_CLK_khz 62500 +#define OCORE_BUS_CLK_khz 100 +#define OCORE_REG_IO_WIDTH 1 + +/* Optical port xcvr configuration */ +#define XCVR_REG_SHIFT 2 +#define XCVR_NUM_PORT 34 +#define XCVR_PORT_REG_SIZE 0x10 + +/* i2c_bus_config - an i2c-core resource and platform data + * @id - I2C bus device ID, for identification. + * @res - resources for an i2c-core device. + * @num_res - size of the resources. + * @pdata - a platform data of an i2c-core device. + */ +struct i2c_bus_config { + int id; + struct resource *res; + ssize_t num_res; + struct ocores_i2c_platform_data pdata; +}; + +/* switchbrd_priv - switchboard private data */ +struct switchbrd_priv { + unsigned long base; + int num_i2c_bus; + struct platform_device **i2cbuses_pdev; + struct platform_device *regio_pdev; + struct platform_device *spiflash_pdev; + struct platform_device *xcvr_pdev; +}; + +/* I2C bus speed param */ +static int bus_clock_master_1 = 100; +module_param(bus_clock_master_1, int, 0660); +MODULE_PARM_DESC(bus_clock_master_1, + "I2C master 1 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_2 = 100; +module_param(bus_clock_master_2, int, 0660); +MODULE_PARM_DESC(bus_clock_master_2, + "I2C master 2 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_3 = 100; +module_param(bus_clock_master_3, int, 0660); +MODULE_PARM_DESC(bus_clock_master_3, + "I2C master 3 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_4 = 100; +module_param(bus_clock_master_4, int, 0660); +MODULE_PARM_DESC(bus_clock_master_4, + "I2C master 4 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_5 = 100; +module_param(bus_clock_master_5, int, 0660); +MODULE_PARM_DESC(bus_clock_master_5, + "I2C master 5 bus speed in KHz 50/80/100/200/400"); + +/* PCA9548 channel config on MASTER BUS 3 */ +static struct pca954x_platform_mode i2c_mux_70_modes[] = { + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 1, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 2, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 3, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 4, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 5, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 6, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 7, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 8, true), +}; + +static struct pca954x_platform_mode i2c_mux_71_modes[] = { + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 9, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 10, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 11, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 12, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 13, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 14, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 15, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 16, true), +}; + +static struct pca954x_platform_mode i2c_mux_72_modes[] = { + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 17, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 18, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 19, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 20, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 21, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 22, true), + I2C_MUX_CHANNEL(6, I2C_BUS_OFS + 23, true), + I2C_MUX_CHANNEL(7, I2C_BUS_OFS + 24, true), +}; + +static struct pca954x_platform_mode i2c_mux_73_modes[] = { + I2C_MUX_CHANNEL(0, I2C_BUS_OFS + 25, true), + I2C_MUX_CHANNEL(1, I2C_BUS_OFS + 26, true), + I2C_MUX_CHANNEL(2, I2C_BUS_OFS + 27, true), + I2C_MUX_CHANNEL(3, I2C_BUS_OFS + 28, true), + I2C_MUX_CHANNEL(4, I2C_BUS_OFS + 29, true), + I2C_MUX_CHANNEL(5, I2C_BUS_OFS + 30, true), +}; + +static struct pca954x_platform_data om_muxes[] = { + { + .modes = i2c_mux_70_modes, + .num_modes = ARRAY_SIZE(i2c_mux_70_modes), + }, + { + .modes = i2c_mux_71_modes, + .num_modes = ARRAY_SIZE(i2c_mux_71_modes), + }, + { + .modes = i2c_mux_72_modes, + .num_modes = ARRAY_SIZE(i2c_mux_72_modes), + }, + { + .modes = i2c_mux_73_modes, + .num_modes = ARRAY_SIZE(i2c_mux_73_modes), + }, +}; + +/* Optical Module bus 3 i2c muxes info */ +static struct i2c_board_info i2c_info_3[] = { + { + I2C_BOARD_INFO("pca9548", 0x70), + .platform_data = &om_muxes[0], + }, + { + I2C_BOARD_INFO("pca9548", 0x71), + .platform_data = &om_muxes[1], + }, + { + I2C_BOARD_INFO("pca9548", 0x72), + .platform_data = &om_muxes[2], + }, + { + I2C_BOARD_INFO("pca9548", 0x73), + .platform_data = &om_muxes[3], + }, +}; + +/* RESOURCE SEPERATES BY FUNCTION */ +/* Resource IOMEM for i2c bus 1 */ +static struct resource cls_i2c_res_1[] = { + { + .start = 0x800, .end = 0x81F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 2 */ +static struct resource cls_i2c_res_2[] = { + { + .start = 0x820, .end = 0x83F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 3 */ +static struct resource cls_i2c_res_3[] = { + { + .start = 0x840, .end = 0x85F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 4 */ +static struct resource cls_i2c_res_4[] = { + { + .start = 0x860, .end = 0x87F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 5 */ +static struct resource cls_i2c_res_5[] = { + { + .start = 0x880, .end = 0x89F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for reg access */ +static struct resource reg_io_res[] = { + { + .start = 0x00, .end = 0xFF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for spi flash firmware upgrade */ +static struct resource spi_flash_res[] = { + { + .start = 0x1200, .end = 0x121F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for front panel XCVR */ +static struct resource xcvr_res[] = { + { + .start = 0x4000, .end = 0x421F, + .flags = IORESOURCE_MEM,}, +}; + +static struct i2c_bus_config i2c_bus_configs[] = { + { + .id = 1, + .res = cls_i2c_res_1, + .num_res = ARRAY_SIZE(cls_i2c_res_1), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 2, + .res = cls_i2c_res_2, + .num_res = ARRAY_SIZE(cls_i2c_res_2), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 3, + .res = cls_i2c_res_3, + .num_res = ARRAY_SIZE(cls_i2c_res_3), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = ARRAY_SIZE(i2c_info_3), + .devices = i2c_info_3, + }, + }, + { + .id = 4, + .res = cls_i2c_res_4, + .num_res = ARRAY_SIZE(cls_i2c_res_4), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, + { + .id = 5, + .res = cls_i2c_res_5, + .num_res = ARRAY_SIZE(cls_i2c_res_5), + .pdata = { + .reg_shift = OCORE_REGSHIFT, + .reg_io_width = OCORE_REG_IO_WIDTH, + .clock_khz = OCORE_IP_CLK_khz, + .bus_khz = OCORE_BUS_CLK_khz, + .big_endian = false, + .num_devices = 0, + .devices = NULL, + }, + }, +}; + +/* xcvr front panel mapping */ +static struct port_info front_panel_ports[] = { + {"QSFP1", 1, QSFP}, + {"QSFP2", 2, QSFP}, + {"QSFP3", 3, QSFP}, + {"QSFP4", 4, QSFP}, + {"QSFP5", 5, QSFP}, + {"QSFP6", 6, QSFP}, + {"QSFP7", 7, QSFP}, + {"QSFP8", 8, QSFP}, + {"QSFP9", 9, QSFP}, + {"QSFP10", 10, QSFP}, + {"QSFP11", 11, QSFP}, + {"QSFP12", 12, QSFP}, + {"QSFP13", 13, QSFP}, + {"QSFP14", 14, QSFP}, + {"QSFP15", 15, QSFP}, + {"QSFP16", 16, QSFP}, + {"QSFP17", 17, QSFP}, + {"QSFP18", 18, QSFP}, + {"QSFP19", 19, QSFP}, + {"QSFP20", 20, QSFP}, + {"QSFP21", 21, QSFP}, + {"QSFP22", 22, QSFP}, + {"QSFP23", 23, QSFP}, + {"QSFP24", 24, QSFP}, + {"QSFPDD1", 25, QSFP}, + {"QSFPDD2", 26, QSFP}, + {"QSFPDD3", 27, QSFP}, + {"QSFPDD4", 28, QSFP}, + {"QSFPDD5", 29, QSFP}, + {"QSFPDD6", 30, QSFP}, + /* END OF LIST */ +}; + +static struct cls_xcvr_platform_data xcvr_data = { + .port_reg_size = 0x10, + .num_ports = ARRAY_SIZE(front_panel_ports), + .devices = front_panel_ports, +}; + + +// TODO: Add a platform configuration struct, and use probe as a factory, +// so xcvr, fwupgrade device can configured as options. + +static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + + struct switchbrd_priv *priv; + struct platform_device **i2cbuses_pdev; + struct platform_device *regio_pdev; + struct platform_device *xcvr_pdev; + unsigned long rstart; + int num_i2c_bus, i; + int err; + + err = pci_enable_device(dev); + if (err){ + dev_err(&dev->dev, "Failed to enable PCI device\n"); + goto err_exit; + } + + /* Check for valid MMIO address */ + rstart = pci_resource_start(dev, MMIO_BAR); + if (!rstart) { + dev_err(&dev->dev, "Switchboard base address uninitialized, " + "check FPGA\n"); + err = -ENODEV; + goto err_disable_device; + } + + dev_dbg(&dev->dev, "BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR, + rstart, pci_resource_end(dev, MMIO_BAR)); + + priv = devm_kzalloc(&dev->dev, + sizeof(struct switchbrd_priv), GFP_KERNEL); + if (!priv){ + err = -ENOMEM; + goto err_disable_device; + } + + pci_set_drvdata(dev, priv); + num_i2c_bus = ARRAY_SIZE(i2c_bus_configs); + i2cbuses_pdev = devm_kzalloc( + &dev->dev, + num_i2c_bus * sizeof(struct platform_device*), + GFP_KERNEL); + + reg_io_res[0].start += rstart; + reg_io_res[0].end += rstart; + + xcvr_res[0].start += rstart; + xcvr_res[0].end += rstart; + + regio_pdev = platform_device_register_resndata( + &dev->dev, "cls-swbrd-io", + -1, + reg_io_res, ARRAY_SIZE(reg_io_res), + NULL, 0); + + if (IS_ERR(regio_pdev)) { + dev_err(&dev->dev, "Failed to register cls-swbrd-io\n"); + err = PTR_ERR(regio_pdev); + goto err_disable_device; + } + + xcvr_pdev = platform_device_register_resndata( + NULL, + "cls-xcvr", + -1, + xcvr_res, + ARRAY_SIZE(xcvr_res), + &xcvr_data, + sizeof(xcvr_data)); + + if (IS_ERR(xcvr_pdev)) { + dev_err(&dev->dev, "Failed to register xcvr node\n"); + err = PTR_ERR(xcvr_pdev); + goto err_unregister_regio; + } + + for(i = 0; i < num_i2c_bus; i++){ + + i2c_bus_configs[i].res[0].start += rstart; + i2c_bus_configs[i].res[0].end += rstart; + + switch (i + 1) { + case 1: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_1; + break; + case 2: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_2; + break; + case 3: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_3; + break; + case 4: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_4; + break; + case 5: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_5; + break; + default: + i2c_bus_configs[i].pdata.bus_khz = OCORE_BUS_CLK_khz; + } + + dev_dbg(&dev->dev, "i2c-bus.%d: 0x%llx - 0x%llx\n", + i2c_bus_configs[i].id, + i2c_bus_configs[i].res[0].start, + i2c_bus_configs[i].res[0].end); + + i2cbuses_pdev[i] = platform_device_register_resndata( + &dev->dev, "cls-ocores-i2c", + i2c_bus_configs[i].id, + i2c_bus_configs[i].res, + i2c_bus_configs[i].num_res, + &i2c_bus_configs[i].pdata, + sizeof(i2c_bus_configs[i].pdata)); + + if (IS_ERR(i2cbuses_pdev[i])) { + dev_err(&dev->dev, "Failed to register ocores-i2c.%d\n", + i2c_bus_configs[i].id); + err = PTR_ERR(i2cbuses_pdev[i]); + goto err_unregister_ocore; + } + } + + priv->base = rstart; + priv->num_i2c_bus = num_i2c_bus; + priv->i2cbuses_pdev = i2cbuses_pdev; + priv->regio_pdev = regio_pdev; + priv->xcvr_pdev = xcvr_pdev; + return 0; + +err_unregister_ocore: + for(i = 0; i < num_i2c_bus; i++){ + if(priv->i2cbuses_pdev[i]){ + platform_device_unregister(priv->i2cbuses_pdev[i]); + } + } +err_unregister_xcvr: + platform_device_unregister(xcvr_pdev); +err_unregister_regio: + platform_device_unregister(regio_pdev); +err_disable_device: + pci_disable_device(dev); +err_exit: + return err; +} + +static void cls_fpga_remove(struct pci_dev *dev) +{ + int i; + struct switchbrd_priv *priv = pci_get_drvdata(dev); + + for(i = 0; i < priv->num_i2c_bus; i++){ + if(priv->i2cbuses_pdev[i]) + platform_device_unregister(priv->i2cbuses_pdev[i]); + } + platform_device_unregister(priv->xcvr_pdev); + platform_device_unregister(priv->regio_pdev); + pci_disable_device(dev); + return; +}; + +static const struct pci_device_id pci_clsswbrd[] = { + { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, + {0, } +}; + +MODULE_DEVICE_TABLE(pci, pci_clsswbrd); + +static struct pci_driver clsswbrd_pci_driver = { + .name = DRV_NAME, + .id_table = pci_clsswbrd, + .probe = cls_fpga_probe, + .remove = cls_fpga_remove, +}; + +module_pci_driver(clsswbrd_pci_driver); + +MODULE_AUTHOR("Pradchaya P."); +MODULE_DESCRIPTION("Celestica Silverstone switchboard driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c new file mode 100644 index 000000000000..587744bcb433 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c @@ -0,0 +1,846 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * i2c-ocores.c: I2C bus driver for OpenCores I2C controller + * (https://opencores.org/project/i2c/overview) + * + * Peter Korsgaard + * + * Support for the GRLIB port of the controller by + * Andreas Larsson + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "i2c-ocores.h" + +#define OCORES_FLAG_POLL BIT(0) + +/* + * 'process_lock' exists because ocores_process() and ocores_process_timeout() + * can't run in parallel. + */ +struct ocores_i2c { + void __iomem *base; + int iobase; + u32 reg_shift; + u32 reg_io_width; + unsigned long flags; + wait_queue_head_t wait; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; /* see STATE_ */ + int nack_retry; + int al_count; + spinlock_t process_lock; + struct clk *clk; + int ip_clock_khz; + int bus_clock_khz; + void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); + u8 (*getreg)(struct ocores_i2c *i2c, int reg); +}; + +/* registers */ +#define OCI2C_PRELOW 0 +#define OCI2C_PREHIGH 1 +#define OCI2C_CONTROL 2 +#define OCI2C_DATA 3 +#define OCI2C_CMD 4 /* write only */ +#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ + +#define OCI2C_CTRL_IEN 0x40 +#define OCI2C_CTRL_EN 0x80 + +#define OCI2C_CMD_START 0x91 +#define OCI2C_CMD_STOP 0x41 +#define OCI2C_CMD_READ 0x21 +#define OCI2C_CMD_WRITE 0x11 +#define OCI2C_CMD_READ_ACK 0x21 +#define OCI2C_CMD_READ_NACK 0x29 +#define OCI2C_CMD_IACK 0x01 + +#define OCI2C_STAT_IF 0x01 +#define OCI2C_STAT_TIP 0x02 +#define OCI2C_STAT_ARBLOST 0x20 +#define OCI2C_STAT_BUSY 0x40 +#define OCI2C_STAT_NACK 0x80 + +#define STATE_DONE 0 +#define STATE_START 1 +#define STATE_WRITE 2 +#define STATE_READ 3 +#define STATE_ERROR 4 + +#define TYPE_OCORES 0 +#define TYPE_GRLIB 1 + +#define AL_MAX_ALLOW 10 + +static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite8(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) +{ + iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) +{ + return ioread8(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) +{ + return ioread16(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) +{ + return ioread32(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) +{ + return ioread16be(i2c->base + (reg << i2c->reg_shift)); +} + +static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) +{ + return ioread32be(i2c->base + (reg << i2c->reg_shift)); +} + +static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) +{ + outb(value, i2c->iobase + reg); +} + +static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) +{ + return inb(i2c->iobase + reg); +} + +static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) +{ + i2c->setreg(i2c, reg, value); +} + +static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) +{ + return i2c->getreg(i2c, reg); +} + +static void ocores_process(struct ocores_i2c *i2c, u8 stat) +{ + struct i2c_msg *msg = i2c->msg; + unsigned long flags; + + /* + * If we spin here is because we are in timeout, so we are going + * to be in STATE_ERROR. See ocores_process_timeout() + */ + spin_lock_irqsave(&i2c->process_lock, flags); + + dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state); + + if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { + /* stop has been sent */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + wake_up(&i2c->wait); + goto out; + } + + /* error? */ + if (stat & OCI2C_STAT_ARBLOST) { + + if (i2c->al_count < AL_MAX_ALLOW){ + i2c->state = STATE_START; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + dev_dbg(&i2c->adap.dev, "RETRY: AL\n"); + i2c->al_count++; + } else { + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + dev_dbg(&i2c->adap.dev, "ERR: AL\n"); + } + goto out; + } + + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { + i2c->state = + (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & OCI2C_STAT_NACK) { + dev_dbg(&i2c->adap.dev, "ERR: NACK\n"); + i2c->state = STATE_ERROR; + if (!(msg->flags & I2C_M_RD)) + i2c->nack_retry = 1; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } else { + msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); + } + + /* end of msg? */ + if (i2c->pos == msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { /* end? */ + /* send start? */ + if (!(msg->flags & I2C_M_NOSTART)) { + u8 addr = i2c_8bit_addr_from_msg(msg); + + i2c->state = STATE_START; + + oc_setreg(i2c, OCI2C_DATA, addr); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + goto out; + } + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } else { + i2c->state = STATE_DONE; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + goto out; + } + } + + if (i2c->state == STATE_READ) { + oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? + OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); + } else { + oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); + } + +out: + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +static irqreturn_t ocores_isr(int irq, void *dev_id) +{ + struct ocores_i2c *i2c = dev_id; + u8 stat = oc_getreg(i2c, OCI2C_STATUS); + + dev_dbg(&i2c->adap.dev, "STATUS: 0x%x\n", stat); + + if (!(stat & OCI2C_STAT_IF)) + return IRQ_NONE; + + ocores_process(i2c, stat); + + return IRQ_HANDLED; +} + +/** + * Process timeout event + * @i2c: ocores I2C device instance + */ +static void ocores_process_timeout(struct ocores_i2c *i2c) +{ + unsigned long flags; + + spin_lock_irqsave(&i2c->process_lock, flags); + i2c->state = STATE_ERROR; + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); + spin_unlock_irqrestore(&i2c->process_lock, flags); +} + +/** + * Wait until something change in a given register + * @i2c: ocores I2C device instance + * @reg: register to query + * @mask: bitmask to apply on register value + * @val: expected result + * @timeout: timeout in jiffies + * + * Timeout is necessary to avoid to stay here forever when the chip + * does not answer correctly. + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_wait(struct ocores_i2c *i2c, + int reg, u8 mask, u8 val, + const unsigned long timeout) +{ + unsigned long j; + + j = jiffies + timeout; + while (1) { + u8 status = oc_getreg(i2c, reg); + + if ((status & mask) == val) + break; + + if (time_after(jiffies, j)) + return -ETIMEDOUT; + cpu_relax(); + cond_resched(); + } + return 0; +} + +/** + * Wait until is possible to process some data + * @i2c: ocores I2C device instance + * + * Used when the device is in polling mode (interrupts disabled). + * + * Return: 0 on success, -ETIMEDOUT on timeout + */ +static int ocores_poll_wait(struct ocores_i2c *i2c) +{ + u8 mask; + int err; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* transfer is over */ + mask = OCI2C_STAT_BUSY; + } else { + /* on going transfer */ + mask = OCI2C_STAT_TIP; + /* + * We wait for the data to be transferred (8bit), + * then we start polling on the ACK/NACK bit + */ + udelay((8 * 1000) / i2c->bus_clock_khz); + } + + dev_dbg(&i2c->adap.dev, "Wait for: 0x%x\n", mask); + + /* + * once we are here we expect to get the expected result immediately + * so if after 1ms we timeout then something is broken. + */ + err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(30)); + if (err) + dev_warn(i2c->adap.dev.parent, + "%s: STATUS timeout, bit 0x%x did not clear in 30ms\n", + __func__, mask); + return err; +} + +/** + * It handles an IRQ-less transfer + * @i2c: ocores I2C device instance + * + * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same + * (only that IRQ are not produced). This means that we can re-use entirely + * ocores_isr(), we just add our polling code around it. + * + * It can run in atomic context + */ +static void ocores_process_polling(struct ocores_i2c *i2c) +{ + while (1) { + irqreturn_t ret; + int err; + + err = ocores_poll_wait(i2c); + if (err) { + i2c->state = STATE_ERROR; + break; /* timeout */ + } + + ret = ocores_isr(-1, i2c); + if (ret == IRQ_NONE) + break; /* all messages have been transferred */ + } +} + +static int ocores_xfer_core(struct ocores_i2c *i2c, + struct i2c_msg *msgs, int num, + bool polling) +{ + int ret; + u8 ctrl; + + ctrl = oc_getreg(i2c, OCI2C_CONTROL); + if (polling) + oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); + else + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_START; + i2c->al_count = 0; + + dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state); + + oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); + + if (polling) { + ocores_process_polling(i2c); + } else { + ret = wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ); + if (ret == 0) { + ocores_process_timeout(i2c); + return -ETIMEDOUT; + } + } + + return (i2c->state == STATE_DONE) ? num : -EIO; +} + +static int ocores_xfer_polling(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); +} + +static int ocores_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + int ret; + int retry = 0; + int max_retry = 0; + struct ocores_i2c *i2c = i2c_get_adapdata(adap); + + i2c->nack_retry = 0; + + if (i2c->flags & OCORES_FLAG_POLL) { + ret = ocores_xfer_polling(adap, msgs, num); + if (num == 1) + max_retry = 5; + else + max_retry = 5; + + while ((i2c->nack_retry == 1) && (retry < max_retry)) + { + retry++; + i2c->nack_retry = 0; + ret = ocores_xfer_polling(adap, msgs, num); + } + i2c->nack_retry = 0; + return ret; + } + return ocores_xfer_core(i2c, msgs, num, false); +} + +static int ocores_init(struct device *dev, struct ocores_i2c *i2c) +{ + int prescale; + int diff; + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; + prescale = clamp(prescale, 0, 0xffff); + + diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; + if (abs(diff) > i2c->bus_clock_khz / 10) { + dev_err(dev, + "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", + i2c->ip_clock_khz, i2c->bus_clock_khz); + return -EINVAL; + } + + oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); + oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); + + dev_info(dev, "Set bus speed to %d KHz\n", i2c->bus_clock_khz); + dev_info(dev, "Prescale: %d\n", prescale); + + /* Init the device */ + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); + oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + + return 0; +} + + +static u32 ocores_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ocores_algorithm = { + .master_xfer = ocores_xfer, + .functionality = ocores_func, +}; + +static const struct i2c_adapter ocores_adapter = { + .owner = THIS_MODULE, + .name = "cls-i2c-ocores", + .class = I2C_CLASS_DEPRECATED, + .algo = &ocores_algorithm, +}; + +static const struct of_device_id ocores_i2c_match[] = { + { + .compatible = "opencores,i2c-ocores", + .data = (void *)TYPE_OCORES, + }, + { + .compatible = "aeroflexgaisler,i2cmst", + .data = (void *)TYPE_GRLIB, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, ocores_i2c_match); + +#ifdef CONFIG_OF +/* + * Read and write functions for the GRLIB port of the controller. Registers are + * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one + * register. The subsequent registers have their offsets decreased accordingly. + */ +static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) +{ + u32 rd; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PREHIGH) + return (u8)(rd >> 8); + else + return (u8)rd; +} + +static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) +{ + u32 curr, wr; + int rreg = reg; + + if (reg != OCI2C_PRELOW) + rreg--; + if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { + curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); + if (reg == OCI2C_PRELOW) + wr = (curr & 0xff00) | value; + else + wr = (((u32)value) << 8) | (curr & 0xff); + } else { + wr = value; + } + iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); +} + +static int ocores_i2c_of_probe(struct platform_device *pdev, + struct ocores_i2c *i2c) +{ + struct device_node *np = pdev->dev.of_node; + const struct of_device_id *match; + u32 val; + u32 clock_frequency; + bool clock_frequency_present; + + if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { + /* no 'reg-shift', check for deprecated 'regstep' */ + if (!of_property_read_u32(np, "regstep", &val)) { + if (!is_power_of_2(val)) { + dev_err(&pdev->dev, "invalid regstep %d\n", + val); + return -EINVAL; + } + i2c->reg_shift = ilog2(val); + dev_warn(&pdev->dev, + "regstep property deprecated, use reg-shift\n"); + } + } + + clock_frequency_present = !of_property_read_u32(np, "clock-frequency", + &clock_frequency); + i2c->bus_clock_khz = 100; + + i2c->clk = devm_clk_get(&pdev->dev, NULL); + + if (!IS_ERR(i2c->clk)) { + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(&pdev->dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + + if (i2c->ip_clock_khz == 0) { + if (of_property_read_u32(np, "opencores,ip-clock-frequency", + &val)) { + if (!clock_frequency_present) { + dev_err(&pdev->dev, + "Missing required parameter 'opencores,ip-clock-frequency'\n"); + clk_disable_unprepare(i2c->clk); + return -ENODEV; + } + i2c->ip_clock_khz = clock_frequency / 1000; + dev_warn(&pdev->dev, + "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); + } else { + i2c->ip_clock_khz = val / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; + } + } + + of_property_read_u32(pdev->dev.of_node, "reg-io-width", + &i2c->reg_io_width); + + match = of_match_node(ocores_i2c_match, pdev->dev.of_node); + if (match && (long)match->data == TYPE_GRLIB) { + dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); + i2c->setreg = oc_setreg_grlib; + i2c->getreg = oc_getreg_grlib; + } + + return 0; +} +#else +#define ocores_i2c_of_probe(pdev, i2c) -ENODEV +#endif + +static int ocores_i2c_probe(struct platform_device *pdev) +{ + struct ocores_i2c *i2c; + struct ocores_i2c_platform_data *pdata; + struct resource *res; + int irq; + int ret; + int i; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + spin_lock_init(&i2c->process_lock); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + i2c->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + } else { + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) + return -EINVAL; + i2c->iobase = res->start; + if (!devm_request_region(&pdev->dev, res->start, + resource_size(res), + pdev->name)) { + dev_err(&pdev->dev, "Can't get I/O resource.\n"); + return -EBUSY; + } + i2c->setreg = oc_setreg_io_8; + i2c->getreg = oc_getreg_io_8; + } + + pdata = dev_get_platdata(&pdev->dev); + if (pdata) { + i2c->reg_shift = pdata->reg_shift; + i2c->reg_io_width = pdata->reg_io_width; + i2c->ip_clock_khz = pdata->clock_khz; + if (pdata->bus_khz) + i2c->bus_clock_khz = pdata->bus_khz; + else + i2c->bus_clock_khz = 100; + } else { + ret = ocores_i2c_of_probe(pdev, i2c); + if (ret) + return ret; + } + + if (i2c->reg_io_width == 0) + i2c->reg_io_width = 1; /* Set to default value */ + + if (!i2c->setreg || !i2c->getreg) { + bool be = pdata ? pdata->big_endian : + of_device_is_big_endian(pdev->dev.of_node); + + switch (i2c->reg_io_width) { + case 1: + i2c->setreg = oc_setreg_8; + i2c->getreg = oc_getreg_8; + break; + + case 2: + i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; + i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; + break; + + case 4: + i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; + i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; + break; + + default: + dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", + i2c->reg_io_width); + ret = -EINVAL; + goto err_clk; + } + } + + init_waitqueue_head(&i2c->wait); + + irq = platform_get_irq(pdev, 0); + if (irq == -ENXIO) { + i2c->flags |= OCORES_FLAG_POLL; + } else { + if (irq < 0) + return irq; + } + + if (!(i2c->flags & OCORES_FLAG_POLL)) { + ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, + pdev->name, i2c); + if (ret) { + dev_err(&pdev->dev, "Cannot claim IRQ\n"); + goto err_clk; + } + } + + ret = ocores_init(&pdev->dev, i2c); + if (ret) + goto err_clk; + + /* hook up driver to tree */ + platform_set_drvdata(pdev, i2c); + i2c->adap = ocores_adapter; + i2c_set_adapdata(&i2c->adap, i2c); + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + + /* add i2c adapter to i2c tree */ + ret = i2c_add_adapter(&i2c->adap); + if (ret) + goto err_clk; + + /* add in known devices to the bus */ + if (pdata) { + for (i = 0; i < pdata->num_devices; i++) + i2c_new_device(&i2c->adap, pdata->devices + i); + } + + return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); + return ret; +} + +static int ocores_i2c_remove(struct platform_device *pdev) +{ + struct ocores_i2c *i2c = platform_get_drvdata(pdev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* disable i2c logic */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + /* remove adapter & data */ + i2c_del_adapter(&i2c->adap); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ocores_i2c_suspend(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); + + /* make sure the device is disabled */ + ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); + oc_setreg(i2c, OCI2C_CONTROL, ctrl); + + if (!IS_ERR(i2c->clk)) + clk_disable_unprepare(i2c->clk); + return 0; +} + +static int ocores_i2c_resume(struct device *dev) +{ + struct ocores_i2c *i2c = dev_get_drvdata(dev); + + if (!IS_ERR(i2c->clk)) { + unsigned long rate; + int ret = clk_prepare_enable(i2c->clk); + + if (ret) { + dev_err(dev, + "clk_prepare_enable failed: %d\n", ret); + return ret; + } + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; + } + return ocores_init(dev, i2c); +} + +static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); +#define OCORES_I2C_PM (&ocores_i2c_pm) +#else +#define OCORES_I2C_PM NULL +#endif + +static struct platform_driver ocores_i2c_driver = { + .probe = ocores_i2c_probe, + .remove = ocores_i2c_remove, + .driver = { + .name = "cls-ocores-i2c", + .of_match_table = ocores_i2c_match, + .pm = OCORES_I2C_PM, + }, +}; + +module_platform_driver(ocores_i2c_driver); + +MODULE_AUTHOR("Peter Korsgaard "); +MODULE_AUTHOR("Pradchaya P "); +MODULE_AUTHOR("Saranpong C "); +MODULE_DESCRIPTION("OpenCores I2C bus driver"); +MODULE_VERSION("1.0.1"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cls-ocores-i2c"); diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h new file mode 100644 index 000000000000..25926b385255 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * i2c-ocores.h - definitions for the i2c-ocores interface + * + * Peter Korsgaard + */ + +#ifndef _LINUX_I2C_OCORES_H +#define _LINUX_I2C_OCORES_H + +struct ocores_i2c_platform_data { + u32 reg_shift; /* register offset shift value */ + u32 reg_io_width; /* register io read/write width */ + u32 clock_khz; /* input clock in kHz */ + u32 bus_khz; /* bus clock in kHz */ + bool big_endian; /* registers are big endian */ + u8 num_devices; /* number of devices in the devices list */ + struct i2c_board_info const *devices; /* devices connected to the bus */ +}; + +#endif /* _LINUX_I2C_OCORES_H */ + diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/mc24lc64t.c new file mode 100644 index 000000000000..fc15bb74b68d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/mc24lc64t.c @@ -0,0 +1,174 @@ +/* + * mc24lc64t.c - driver for Microchip 24LC64T + * + * Copyright (C) 2017 Celestica Corp. + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define EEPROM_SIZE 8192 //mc24lt64t eeprom size in bytes. + +struct mc24lc64t_data { + struct mutex update_lock; +}; + +static ssize_t mc24lc64t_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count) +{ + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + unsigned long timeout, read_time, i = 0; + int status; + + mutex_lock(&drvdata->update_lock); + + if (i2c_smbus_write_byte_data(client, off>>8, off)) + { + status = -EIO; + goto exit; + } + + msleep(1); + +begin: + + if (i < count) + { + timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/ + do { + read_time = jiffies; + + status = i2c_smbus_read_byte(client); + if (status >= 0) + { + buf[i++] = status; + goto begin; + } + } while (time_before(read_time, timeout)); + + status = -ETIMEDOUT; + goto exit; + } + + status = count; + +exit: + mutex_unlock(&drvdata->update_lock); + + return status; +} + + +static ssize_t mc24lc64t_write (struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, + char *buf, loff_t off, size_t count){ + + struct i2c_client *client = kobj_to_i2c_client(kobj); + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + unsigned long timeout, write_time, i = 0; + int status; + u16 value; + + mutex_lock(&drvdata->update_lock); + +begin: + if (i < count){ + timeout = jiffies + msecs_to_jiffies(25); /* 25 mS timeout*/ + value = (buf[i] << 8 | ( off &0xff)); + do { + write_time = jiffies; + status = i2c_smbus_write_word_data(client, off>>8, value); + if (status >= 0) + { + // increase offset + off++; + // increase buffer index + i++; + goto begin; + } + } while (time_before(write_time, timeout)); + status = -ETIMEDOUT; + goto exit; + } + status = count; + +exit: + mutex_unlock(&drvdata->update_lock); + return status; +} + + +static struct bin_attribute mc24lc64t_bit_attr = { + .attr = { + .name = "eeprom", + .mode = S_IRUGO | S_IWUGO, + }, + .size = EEPROM_SIZE, + .read = mc24lc64t_read, + .write = mc24lc64t_write, +}; + +static int mc24lc64t_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = client->adapter; + struct mc24lc64t_data *drvdata; + int err; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA + | I2C_FUNC_SMBUS_READ_BYTE)) + return -EPFNOSUPPORT; + + if (!(drvdata = devm_kzalloc(&client->dev, + sizeof(struct mc24lc64t_data), GFP_KERNEL))) + return -ENOMEM; + + i2c_set_clientdata(client, drvdata); + mutex_init(&drvdata->update_lock); + + err = sysfs_create_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr); + return err; +} + +static int mc24lc64t_remove(struct i2c_client *client) +{ + struct mc24lc64t_data *drvdata = i2c_get_clientdata(client); + sysfs_remove_bin_file(&client->dev.kobj, &mc24lc64t_bit_attr); + + return 0; +} + +static const struct i2c_device_id mc24lc64t_id[] = { + { "24lc64t", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, mc24lc64t_id); + +static struct i2c_driver mc24lc64t_driver = { + .driver = { + .name = "mc24lc64t", + .owner = THIS_MODULE, + }, + .probe = mc24lc64t_probe, + .remove = mc24lc64t_remove, + .id_table = mc24lc64t_id, +}; + +module_i2c_driver(mc24lc64t_driver); + +MODULE_AUTHOR("Abhisit Sangjan "); +MODULE_DESCRIPTION("Microchip 24LC64T Driver"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/switch_cpld.c new file mode 100644 index 000000000000..72fedf1f5eb1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/switch_cpld.c @@ -0,0 +1,428 @@ +/* + * switch_cpld.c - i2c driver for Silverstone DP switchboard CPLD1/CPLD2 + * provides sysfs interfaces to access CPLD register and control port LEDs + * + * Author: Budsakol Sirirattanasakul + * + * Copyright (C) 2019 Celestica Corp. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#define CPLD1_ADDR 0x30 +#define CPLD2_ADDR 0x31 + +#define SCRATCH_ADDR 0x01 +#define LED_OPMODE 0x09 +#define LED_TEST 0x0A + +struct switch_cpld_data { + struct mutex lock; + struct i2c_client *client; + struct i2c_client *client2; + uint8_t read_addr; +}; + +static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int value; + + value = i2c_smbus_read_byte_data(client, data->read_addr); + if (value < 0) + return value; + + return sprintf(buf, "0x%.2x\n", value); +} + +static ssize_t getreg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + uint8_t value; + ssize_t status; + struct switch_cpld_data *data = dev_get_drvdata(dev); + + status = kstrtou8(buf, 0, &value); + if (status != 0) + return status; + + data->read_addr = value; + + return size; +} + +static ssize_t setreg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + uint8_t addr, value; + ssize_t status; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + char *tok; + + tok = strsep((char **)&buf, " "); + if (tok == NULL) + return -EINVAL; + status = kstrtou8(tok, 0, &addr); + if (status != 0) + return status; + + tok = strsep((char **)&buf, " "); + if (tok == NULL) + return -EINVAL; + status = kstrtou8(tok, 0, &value); + if (status != 0) + return status; + + status = i2c_smbus_write_byte_data(client, addr, value); + if (status == 0) + status = size; + return status; +} + +static ssize_t scratch_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + int value; + + value = i2c_smbus_read_byte_data(client, SCRATCH_ADDR); + if (value < 0) + return value; + + return sprintf(buf, "0x%.2x\n", value); +} + +static ssize_t scratch_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t size) +{ + uint8_t value; + ssize_t status; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->client; + + status = kstrtou8(buf, 0, &value); + if (status != 0) + return status; + status = i2c_smbus_write_byte_data(client, SCRATCH_ADDR, value); + if (status == 0) + status = size; + return status; +} + +DEVICE_ATTR_RW(getreg); +DEVICE_ATTR_WO(setreg); +DEVICE_ATTR_RW(scratch); + +static struct attribute *switch_cpld_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_setreg.attr, + &dev_attr_scratch.attr, + NULL, +}; +ATTRIBUTE_GROUPS(switch_cpld); + +static ssize_t port_led_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int led_mode_1, led_mode_2; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + led_mode_1 = i2c_smbus_read_byte_data(client1, LED_OPMODE); + if (led_mode_1 < 0) + return led_mode_1; + + led_mode_2 = i2c_smbus_read_byte_data(client2, LED_OPMODE); + if (led_mode_2 < 0) + return led_mode_2; + + return sprintf(buf, "%s %s\n", + led_mode_1 ? "test" : "normal", + led_mode_2 ? "test" : "normal"); +} + +static ssize_t port_led_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int status; + uint8_t led_mode; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + if (sysfs_streq(buf, "test")) + led_mode = 0x01; + else if (sysfs_streq(buf, "normal")) + led_mode = 0x00; + else + return -EINVAL; + + status = i2c_smbus_write_byte_data(client1, LED_OPMODE, led_mode); + if (status != 0) { + return status; + } + + status = i2c_smbus_write_byte_data(client2, LED_OPMODE, led_mode); + if (status != 0) { + return status; + } + + return size; +} + +static ssize_t port_led_color_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int led_color1, led_color2; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + led_color1 = i2c_smbus_read_byte_data(client1, LED_TEST); + if (led_color1 < 0) + return led_color1; + + led_color2 = i2c_smbus_read_byte_data(client2, LED_TEST); + if (led_color2 < 0) + return led_color2; + + return sprintf(buf, "%s %s\n", + led_color1 == 0x02 ? "green" : + led_color1 == 0x01 ? "amber" : "off", + + led_color2 == 0x07 ? "off" : + led_color2 == 0x06 ? "green" : + led_color2 == 0x05 ? "red" : + led_color2 == 0x04 ? "yellow" : + led_color2 == 0x03 ? "blue" : + led_color2 == 0x02 ? "cyan" : + led_color2 == 0x01 ? "magenta" : "white"); +} + +static ssize_t port_led_color_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + int status; + uint8_t led_color1, led_color2; + struct switch_cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client1 = data->client; + struct i2c_client *client2 = data->client2; + + if (sysfs_streq(buf, "off")) { + led_color1 = 0x07; + led_color2 = 0x07; + } else if (sysfs_streq(buf, "green")) { + led_color1 = 0x07; + led_color2 = 0x06; + } else if (sysfs_streq(buf, "red")) { + led_color1 = 0x07; + led_color2 = 0x05; + } else if (sysfs_streq(buf, "yellow")) { + led_color1 = 0x07; + led_color2 = 0x04; + } else if (sysfs_streq(buf, "blue")) { + led_color1 = 0x07; + led_color2 = 0x03; + } else if (sysfs_streq(buf, "cyan")) { + led_color1 = 0x02; + led_color2 = 0x02; + } else if (sysfs_streq(buf, "magenta")) { + led_color1 = 0x01; + led_color2 = 0x01; + } else if (sysfs_streq(buf, "white")) { + led_color1 = 0x07; + led_color2 = 0x00; + } else { + return -EINVAL; + } + + status = i2c_smbus_write_byte_data(client1, LED_TEST, led_color1); + if (status != 0) { + return status; + } + + status = i2c_smbus_write_byte_data(client2, LED_TEST, led_color2); + if (status != 0) { + return status; + } + + return size; +} + +DEVICE_ATTR_RW(port_led_mode); +DEVICE_ATTR_RW(port_led_color); + +static struct attribute *sff_led_attrs[] = { + &dev_attr_port_led_mode.attr, + &dev_attr_port_led_color.attr, + NULL, +}; + +static struct attribute_group sff_led_groups = { + .attrs = sff_led_attrs, +}; + +static int switch_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int err; + struct switch_cpld_data *drvdata1, *drvdata2; + struct device *hwmon_dev1, *hwmon_dev2; + struct i2c_client *client2; + + if (client->addr != CPLD1_ADDR) { + dev_err(&client->dev, "probe, bad i2c addr: 0x%x\n", + client->addr); + err = -EINVAL; + goto exit; + } + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EPFNOSUPPORT; + + /* CPLD1 */ + drvdata1 = devm_kzalloc(&client->dev, + sizeof(struct switch_cpld_data), GFP_KERNEL); + + if (!drvdata1) { + err = -ENOMEM; + goto exit; + } + + mutex_init(&drvdata1->lock); + drvdata1->client = client; + drvdata1->read_addr = 0x00; + i2c_set_clientdata(client, drvdata1); + hwmon_dev1 = devm_hwmon_device_register_with_groups(&client->dev, + "CPLD1", + drvdata1, + switch_cpld_groups); + + if (IS_ERR(hwmon_dev1)) { + err = PTR_ERR(hwmon_dev1); + goto exit; + } + + err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD1"); + if (err) { + goto exit; + } + + /* CPLD2 */ + drvdata2 = devm_kzalloc(&client->dev, + sizeof(struct switch_cpld_data), GFP_KERNEL); + + if (!drvdata2) { + err = -ENOMEM; + goto err_link; + } + + client2 = i2c_new_dummy(client->adapter, CPLD2_ADDR); + if (!client2) { + dev_err(&client->dev, "address 0x%02x unavailable\n", + CPLD2_ADDR); + err = -EADDRINUSE; + goto err_link; + } + + mutex_init(&drvdata2->lock); + drvdata2->read_addr = 0x00; + drvdata2->client = client2; + i2c_set_clientdata(client2, drvdata2); + + /* attach client2 to be client2 of CPLD1 + for later use on port led sysfs */ + drvdata1->client2 = client2; + + hwmon_dev2 = devm_hwmon_device_register_with_groups(&client2->dev, + "CPLD2", + drvdata2, + switch_cpld_groups); + + if (IS_ERR(hwmon_dev2)) { + err = PTR_ERR(hwmon_dev2); + goto err_client2; + } + + err = sysfs_create_link(&client->dev.kobj, &hwmon_dev2->kobj, "CPLD2"); + if (err) { + goto err_client2; + } + + //port led + err = sysfs_create_group(&client->dev.kobj, &sff_led_groups); + if (err) { + dev_err(&client->dev, + "failed to create sysfs attribute group.\n"); + goto err_link2; + } + + return 0; + +err_link2: + sysfs_remove_link(&client->dev.kobj, "CPLD2"); + +err_client2: + if (client2) + i2c_unregister_device(client2); + +err_link: + sysfs_remove_link(&client->dev.kobj, "CPLD1"); + +exit: + dev_err(&client->dev, "probe error %d\n", err); + return err; +} + +static int switch_cpld_remove(struct i2c_client *client) +{ + struct switch_cpld_data *data = i2c_get_clientdata(client); + + sysfs_remove_group(&client->dev.kobj, &sff_led_groups); + sysfs_remove_link(&data->client->dev.kobj, "CPLD2"); + sysfs_remove_link(&client->dev.kobj, "CPLD1"); + i2c_unregister_device(data->client2); + return 0; +} + +static const struct i2c_device_id switch_cpld_ids[] = { + { "switch_cpld", 0x30 }, + { } +}; + +MODULE_DEVICE_TABLE(i2c, switch_cpld_ids); + +static struct i2c_driver switch_cpld_driver = { + .driver = { + .name = "switch_cpld", + .owner = THIS_MODULE, + }, + .probe = switch_cpld_probe, + .remove = switch_cpld_remove, + .id_table = switch_cpld_ids, +}; + +module_i2c_driver(switch_cpld_driver); + +MODULE_AUTHOR("Budsakol Sirirattanasakul"); +MODULE_DESCRIPTION("Celestica Silverstone Switchboard CPLD driver"); +MODULE_VERSION("1.0.0"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.c new file mode 100644 index 000000000000..bc0da613ec8d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.c @@ -0,0 +1,520 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * xcvr-cls.c - front panel port control. + * + * Pradchaya Phucharoen + * Copyright (C) 2019 Celestica Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "xcvr-cls.h" + +/* FPGA front panel */ +#define PORT_CTRL 0 +#define PORT_STATUS 0x4 +#define PORT_INT_STATUS 0x8 +#define PORT_INT_MASK 0xC + +/* + * Port control degister + * LPMOD : active high, RW + * RST : active low, RW + * TXDIS : active high, RW +*/ +#define CTRL_LPMOD BIT(6) +#define CTRL_RST_L BIT(4) +#define CTRL_TXDIS BIT(0) + +/* + * Port status register + * IRQ : active low, RO + * PRESENT : active low, RO, for QSFP + * TXFAULT : active high, RO + * RXLOS : active high, RO + * MODABS : active high, RO, for SFP +*/ +#define STAT_IRQ_L BIT(5) +#define STAT_PRESENT_L BIT(4) +#define STAT_TXFAULT BIT(2) +#define STAT_RXLOS BIT(1) +#define STAT_MODABS BIT(0) + +/* + * NOTE: Interrupt and mask must be expose as bitfeild. + * Because the registers of interrupt flags are read-clear. + * + * Port interrupt flag resgister + * INT_N : interrupt flag, set when INT_N is assert. + * PRESENT : interrupt flag, set when QSFP module plugin/plugout. + * RXLOS : interrupt flag, set when rxlos is assert. + * MODABS : interrupt flag, set when SFP module plugin/plugout. +*/ +#define INTR_INT_N BIT(5) +#define INTR_PRESENT BIT(4) +#define INTR_TXFAULT BIT(2) +#define INTR_RXLOS BIT(1) +#define INTR_MODABS BIT(0) + +/* + * Port interrupt mask register + * INT_N : active low + * PRESENT : active low + * RXLOS_INT : active low + * MODABS : active low +*/ +#define MASK_INT_N_L BIT(5) +#define MASK_PRESENT_L BIT(4) +#define MASK_TXFAULT_L BIT(2) +#define MASK_RXLOS_L BIT(1) +#define MASK_MODABS_L BIT(0) + + +/* + * port_data - optical port data + * @xcvr: xcvr memory accessor + * @name: port name + * @index: front panel port index starting from 1 + */ +struct port_data { + struct xcvr_priv *xcvr; + const char *name; + unsigned int index; +}; + +/* + * xcvr_priv - port xcvr private data + * @dev: device for reference + * @base: virtual base address + * @num_ports: number of front panel ports + * @fp_devs: list of front panel port devices + */ +struct xcvr_priv { + struct device* dev; + void __iomem *base; + int port_reg_size; + int num_ports; + struct device **fp_devs; +}; + +static inline void port_setreg(struct xcvr_priv *xcvr, int reg, int index, u8 value) +{ + return iowrite8(value, xcvr->base + reg + (index - 1) * xcvr->port_reg_size); +} + +static inline u8 port_getreg(struct xcvr_priv *xcvr, int reg, int index) +{ + return ioread8(xcvr->base + reg + (index - 1) * xcvr->port_reg_size); +} + +static ssize_t qsfp_modprsL_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_PRESENT_L)?1:0); +} + +static ssize_t qsfp_irqL_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_IRQ_L)?1:0); +} + +static ssize_t qsfp_lpmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + return sprintf(buf, "%d\n", (data & CTRL_LPMOD)?1:0); +} + +static ssize_t qsfp_lpmode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + if (value == 0) + data &= ~CTRL_LPMOD; + else + data |= CTRL_LPMOD; + port_setreg(port_data->xcvr, PORT_CTRL, index, data); + status = size; + } + return status; +} + +static ssize_t qsfp_resetL_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + return sprintf(buf, "%d\n", (data & CTRL_RST_L)?1:0); +} + +static ssize_t qsfp_resetL_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + if (value == 0) + data &= ~CTRL_RST_L; + else + data |= CTRL_RST_L; + port_setreg(port_data->xcvr, PORT_CTRL, index, data); + status = size; + } + return status; +} + +static ssize_t sfp_modabs_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_MODABS)?1:0); +} + +static ssize_t sfp_txfault_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_TXFAULT)?1:0); +} + +static ssize_t sfp_rxlos_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_STATUS, index); + return sprintf(buf, "%d\n", (data & STAT_RXLOS)?1:0); +} + +static ssize_t sfp_txdisable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + return sprintf(buf, "%d\n", (data & CTRL_TXDIS)?1:0); +} + +static ssize_t sfp_txdisable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtol(buf, 0, &value); + if (status == 0) { + data = port_getreg(port_data->xcvr, PORT_CTRL, index); + if (value == 0) + data &= ~CTRL_TXDIS; + else + data |= CTRL_TXDIS; + port_setreg(port_data->xcvr, PORT_CTRL, index, data); + status = size; + } + return status; +} + +static ssize_t interrupt_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_INT_STATUS, index); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t interrupt_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtoul(buf, 0, &value); + if (status == 0) { + port_setreg(port_data->xcvr, PORT_INT_STATUS, index, value); + status = size; + } + return status; +} + +static ssize_t interrupt_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + u8 data; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + data = port_getreg(port_data->xcvr, PORT_INT_MASK, index); + return sprintf(buf, "0x%2.2x\n", data); +} + +static ssize_t interrupt_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t size) +{ + ssize_t status; + long value; + struct port_data *port_data = dev_get_drvdata(dev); + unsigned int index = port_data->index; + + status = kstrtoul(buf, 0, &value); + if (status == 0) { + port_setreg(port_data->xcvr, PORT_INT_MASK, index, value); + status = size; + } + return status; +} + +DEVICE_ATTR_RO(qsfp_modprsL); +DEVICE_ATTR_RO(qsfp_irqL); +DEVICE_ATTR_RW(qsfp_lpmode); +DEVICE_ATTR_RW(qsfp_resetL); + +DEVICE_ATTR_RO(sfp_modabs); +DEVICE_ATTR_RO(sfp_txfault); +DEVICE_ATTR_RO(sfp_rxlos); +DEVICE_ATTR_RW(sfp_txdisable); + +DEVICE_ATTR_RW(interrupt); +DEVICE_ATTR_RW(interrupt_mask); + +/* qsfp_attrs */ +static struct attribute *qsfp_attrs[] = { + &dev_attr_qsfp_modprsL.attr, + &dev_attr_qsfp_lpmode.attr, + &dev_attr_qsfp_resetL.attr, + &dev_attr_interrupt.attr, + &dev_attr_interrupt_mask.attr, + NULL +}; + +/* sfp_attrs */ +static struct attribute *sfp_attrs[] = { + &dev_attr_sfp_modabs.attr, + &dev_attr_sfp_txfault.attr, + &dev_attr_sfp_rxlos.attr, + &dev_attr_sfp_txdisable.attr, + &dev_attr_interrupt.attr, + &dev_attr_interrupt_mask.attr, + NULL +}; + +ATTRIBUTE_GROUPS(qsfp); +ATTRIBUTE_GROUPS(sfp); + +/* A single port device init */ +static struct device* init_port(struct device *dev, + struct xcvr_priv *xcvr, + struct port_info info, + const struct attribute_group **groups) +{ + struct port_data *new_data; + + new_data = devm_kzalloc(dev, sizeof(struct port_data), GFP_KERNEL); + if (!new_data) + return ERR_PTR(-ENOMEM); + + new_data->index = info.index; + new_data->name = info.name; + new_data->xcvr = xcvr; + + return devm_hwmon_device_register_with_groups(dev, + info.name, + new_data, + groups); +} + +static void xcvr_cleanup(struct xcvr_priv *xcvr) +{ + struct device *dev; + struct port_data *data; + int i; + + for (i = 0; i < xcvr->num_ports; i++){ + dev = xcvr->fp_devs[i]; + if (dev == NULL) + continue; + data = dev_get_drvdata(dev); + sysfs_remove_link(&xcvr->dev->kobj, data->name); + } +} + +static int cls_xcvr_probe(struct platform_device *pdev) +{ + + struct xcvr_priv *xcvr; + struct cls_xcvr_platform_data *pdata; + struct resource *res; + int ret; + int i; + + struct device **port_devs; + + xcvr = devm_kzalloc(&pdev->dev, sizeof(struct xcvr_priv), GFP_KERNEL); + if (!xcvr){ + ret = -ENOMEM; + goto err_exit; + } + + dev_set_drvdata(&pdev->dev, xcvr); + + /* mmap resource */ + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res) { + xcvr->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xcvr->base)){ + ret = PTR_ERR(xcvr->base); + goto err_exit; + } + } + + pdata = dev_get_platdata(&pdev->dev); + xcvr->dev = &pdev->dev; + + if (pdata) { + /* assign pdata */ + xcvr->num_ports = pdata->num_ports; + xcvr->port_reg_size = pdata->port_reg_size; + } + + /* alloc front panel device list */ + port_devs = devm_kzalloc(&pdev->dev, + xcvr->num_ports * sizeof(struct device*), + GFP_KERNEL); + if (!port_devs){ + ret = -ENOMEM; + goto err_exit; + } + + + if (pdata) { + /* create each device attrs group determined by type */ + for (i = 0; i < pdata->num_ports; i++) { + struct device *fp_dev; + + if (pdata->devices[i].type == SFP){ + fp_dev = init_port(&pdev->dev, + xcvr, + pdata->devices[i], + sfp_groups); + }else{ + fp_dev = init_port(&pdev->dev, + xcvr, + pdata->devices[i], + qsfp_groups); + } + if (IS_ERR(fp_dev)) { + dev_err(&pdev->dev, + "Failed to init port %s\n", + pdata->devices[i].name); + ret = PTR_ERR(fp_dev); + goto dev_clean_up; + } + + dev_info(&pdev->dev, + "Register port %s\n", + pdata->devices[i].name); + + WARN(sysfs_create_link(&pdev->dev.kobj, + &fp_dev->kobj, + pdata->devices[i].name), + "can't create symlink to %s\n", pdata->devices[i].name); + port_devs[i] = fp_dev; + fp_dev = NULL; + } + xcvr->fp_devs = port_devs; + } + + return 0; + +dev_clean_up: + xcvr_cleanup(xcvr); +err_exit: + return ret; + +} + + +static int cls_xcvr_remove(struct platform_device *pdev) +{ + struct xcvr_priv *xcvr = dev_get_drvdata(&pdev->dev); + xcvr_cleanup(xcvr); + return 0; +} + + +static struct platform_driver cls_xcvr_driver = { + .probe = cls_xcvr_probe, + .remove = cls_xcvr_remove, + .driver = { + .name = "cls-xcvr", + }, +}; + +module_platform_driver(cls_xcvr_driver); + +MODULE_AUTHOR("Pradchaya Phucharoen"); +MODULE_DESCRIPTION("Celestica xcvr control driver"); +MODULE_VERSION("0.0.1-3"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cls-xcvr"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.h b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.h new file mode 100644 index 000000000000..7659a7c0e9cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/xcvr-cls.h @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * xcvr-cls.h + * + * Pradchaya Phucharoen + * Copyright (C) 2019 Celestica Corp. + */ + +#ifndef _LINUX_I2C_CLS_H +#define _LINUX_I2C_CLS_H + +enum PORT_TYPE { + NONE = 0, + SFP, + QSFP +}; + +/* + * port_info - optical port info + * @index: front panel port index starting from 1 + * @typr: port type, see *PORT_TYPE* + */ +struct port_info { + const char *name; + unsigned int index; + enum PORT_TYPE type; +}; + +/* + * cls_xcvr_platform_data - port xcvr private data + * @port_reg_size: register range of each port + * @num_ports: number of front panel ports + * @devices: list of front panel port info + */ +struct cls_xcvr_platform_data { + unsigned int port_reg_size; + int num_ports; + struct port_info *devices; +}; + +#endif /* _LINUX_I2C_CLS_H */ \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/systemd/platform-modules-silverstone-dp.service b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/systemd/platform-modules-silverstone-dp.service new file mode 100644 index 000000000000..21d7426d1c27 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/systemd/platform-modules-silverstone-dp.service @@ -0,0 +1,13 @@ +[Unit] +Description=Celestica Silverstone DP platform modules +After=local-fs.target +Before=pmon.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/platform-modules-silverstone-dp start +ExecStop=-/etc/init.d/platform-modules-silverstone-dp stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target \ No newline at end of file From 473f23cf794ca3493df7f00507d51ebf38339d59 Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Tue, 8 Oct 2019 20:13:30 +0700 Subject: [PATCH 02/17] [device/Silverstone-dp] Add Silverstone-DP device plugins --- .../plugins/eeprom.py | 23 ++ .../plugins/psuutil.py | 94 ++++++++ .../plugins/sfputil.py | 215 ++++++++++++++++++ 3 files changed, 332 insertions(+) create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/plugins/eeprom.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/plugins/psuutil.py create mode 100755 device/celestica/x86_64-cel_silverstone_dp-r0/plugins/sfputil.py diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/eeprom.py b/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/eeprom.py new file mode 100644 index 000000000000..4dfd50e568c5 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/eeprom.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Silverstone-DP +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError, e: + raise ImportError (str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) + diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/psuutil.py new file mode 100644 index 000000000000..52070a323627 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/psuutil.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +import os.path +import subprocess +import sys +import re + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +# TODO: update ipmi command to get PSU statuses. +# user sdr entity 10 and filter psu1/psu2_status for discrete. + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + self.ipmi_raw = "docker exec -ti pmon ipmitool raw 0x4 0x2d" + self.psu1_id = "0x2f" + self.psu2_id = "0x39" + PsuBase.__init__(self) + + def run_command(self, command): + proc = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE) + (out, err) = proc.communicate() + + if proc.returncode != 0: + sys.exit(proc.returncode) + + return out + + def find_value(self, in_string): + result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string) + if result: + return result.group(1) + else: + return result + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + return 2 + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by 1-based index + :param index: An integer, 1-based index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is faulty + """ + if index is None: + return False + + psu_id = self.psu1_id if index == 1 else self.psu2_id + res_string = self.run_command(self.ipmi_raw + ' ' + psu_id) + status_byte = self.find_value(res_string) + + if status_byte is None: + return False + + failure_detected = (int(status_byte, 16) >> 1) & 1 + input_lost = (int(status_byte, 16) >> 3) & 1 + if failure_detected or input_lost: + return False + else: + return True + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by 1-based index + :param index: An integer, 1-based index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + if index is None: + return False + + psu_id = self.psu1_id if index == 1 else self.psu2_id + res_string = self.run_command(self.ipmi_raw + ' ' + psu_id) + status_byte = self.find_value(res_string) + + if status_byte is None: + return False + + presence = ( int(status_byte, 16) >> 0 ) & 1 + if presence: + return True + else: + return False \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/sfputil.py new file mode 100755 index 000000000000..d2cf7b8d6269 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/plugins/sfputil.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python +# +# Platform-specific SFP transceiver interface for SONiC +# This plugin supports QSFP-DD, QSFP. + +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""" + """ Silverstone-DP EVT does not have SFP port """ + + PORT_START = 1 + PORT_END = 30 + OSFP_PORT_START = 25 + OSFP_PORT_END = 30 + QSFP_PORT_START = 1 + QSFP_PORT_END = 24 + + PORT_INFO_PATH = '/sys/devices/platform/cls-xcvr' + + _port_name = "" + _port_to_eeprom_mapping = {} + _port_to_i2cbus_mapping = { + 1: 10, + 2: 11, + 3: 12, + 4: 13, + 5: 14, + 6: 15, + 7: 16, + 8: 17, + 9: 18, + 10: 19, + 11: 20, + 12: 21, + 13: 22, + 14: 23, + 15: 24, + 16: 25, + 17: 26, + 18: 27, + 19: 28, + 20: 29, + 21: 30, + 22: 31, + 23: 32, + 24: 33, + 25: 34, + 26: 35, + 27: 36, + 28: 37, + 29: 38, + 30: 39, + } + + @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.QSFP_PORT_START, self.QSFP_PORT_END + 1) + + @property + def osfp_ports(self): + return range(self.OSFP_PORT_START, self.OSFP_PORT_END + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + @property + def port_to_i2cbus_mapping(self): + return self._port_to_i2cbus_mapping + + def _get_port_name(self, port_num): + if port_num in self.osfp_ports: + self._port_name = "QSFPDD" + str(port_num - self.OSFP_PORT_START + 1) + else: + self._port_name = "QSFP" + str(port_num - self.QSFP_PORT_START + 1) + return self._port_name + + def get_eeprom_dom_raw(self, port_num): + if port_num in self.osfp_ports: + return None + elif port_num in self.osfp_ports: + return None + else: + # Read dom eeprom at addr 0x51 + return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256) + + def __init__(self): + # Override port_to_eeprom_mapping for class initialization + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + for k,v in self._port_to_i2cbus_mapping.items(): + self._port_to_eeprom_mapping[k] = eeprom_path.format(v) + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + # Check for invalid port_num + if port_num not in range(self.port_start, self.port_end + 1): + return False + + # Get path for access port presence status + port_name = self._get_port_name(port_num) + sysfs_filename = "qsfp_modprsL" + reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename]) + + # Read status + try: + reg_file = open(reg_path) + content = reg_file.readline().rstrip() + reg_value = int(content) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + # Module present is active low + if reg_value == 0: + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid QSFP port_num + if port_num not in self.osfp_ports and port_num not in self.qsfp_ports: + return False + + try: + port_name = self._get_port_name(port_num) + reg_file = open("/".join([self.PORT_INFO_PATH, + port_name, "qsfp_lpmode"])) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + # Read status + content = reg_file.readline().rstrip() + reg_value = int(content) + # low power mode is active high + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num not in self.osfp_ports and port_num not in self.qsfp_ports: + return False + + try: + port_name = self._get_port_name(port_num) + reg_file = open("/".join([self.PORT_INFO_PATH, + port_name, "qsfp_lpmode"]), "r+") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = hex(lpmode) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num not in self.osfp_ports and port_num not in self.qsfp_ports: + return False + + try: + port_name = self._get_port_name(port_num) + reg_file = open("/".join([self.PORT_INFO_PATH, + port_name, "qsfp_resetL"]), "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(0)) + 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( + "/".join([self.PORT_INFO_PATH, port_name, "qsfp_resetL"]), "w") + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + reg_file.seek(0) + reg_file.write(hex(1)) + reg_file.close() + + return True + + def get_transceiver_change_event(self, timeout=0): + """ + TBD + """ + raise NotImplementedError From d4331723e0214ff3a95cde55c7a8f77134adc3ef Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Tue, 8 Oct 2019 19:36:15 +0700 Subject: [PATCH 03/17] [device/Silverstone-dp] Add basic hwsku Silverstone-DP port mapping --- .../Silverstone-DP/port_config.ini | 31 +++++++++++++++++++ .../x86_64-cel_silverstone_dp-r0/default_sku | 1 + 2 files changed, 32 insertions(+) create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/Silverstone-DP/port_config.ini create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/default_sku diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/Silverstone-DP/port_config.ini b/device/celestica/x86_64-cel_silverstone_dp-r0/Silverstone-DP/port_config.ini new file mode 100644 index 000000000000..0f7199ed04ed --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/Silverstone-DP/port_config.ini @@ -0,0 +1,31 @@ +# name lanes alias index speed +Ethernet0 0,1 QSFP1 1 100000 +Ethernet4 2,3 QSFP2 2 100000 +Ethernet8 4,5 QSFP3 3 100000 +Ethernet12 6,7 QSFP4 4 100000 +Ethernet16 8,9 QSFP5 5 100000 +Ethernet20 10,11 QSFP6 6 100000 +Ethernet24 12,13 QSFP7 7 100000 +Ethernet28 14,15 QSFP8 8 100000 +Ethernet32 16,17 QSFP9 9 100000 +Ethernet36 18,19 QSFP10 10 100000 +Ethernet40 20,21 QSFP11 11 100000 +Ethernet44 22,23 QSFP12 12 100000 +Ethernet48 24,25 QSFP13 13 100000 +Ethernet52 26,27 QSFP14 14 100000 +Ethernet56 28,29 QSFP15 15 100000 +Ethernet60 30,31 QSFP16 16 100000 +Ethernet64 32,33 QSFP17 17 100000 +Ethernet68 34,35 QSFP18 18 100000 +Ethernet72 36,37 QSFP19 19 100000 +Ethernet76 38,39 QSFP20 20 100000 +Ethernet80 40,41 QSFP21 21 100000 +Ethernet84 42,43 QSFP22 22 100000 +Ethernet88 44,45 QSFP23 23 100000 +Ethernet92 46,47 QSFP24 24 100000 +Ethernet96 88,89,90,91,92,93,94,95 QSFPDD1 25 400000 +Ethernet100 80,81,82,83,84,85,86,87 QSFPDD2 26 400000 +Ethernet104 72,73,74,75,76,77,78,79 QSFPDD3 27 400000 +Ethernet108 64,65,66,67,68,69,70,71 QSFPDD4 28 400000 +Ethernet112 56,57,58,59,60,61,62,63 QSFPDD5 29 400000 +Ethernet116 48,49,50,51,52,53,54,55 QSFPDD6 30 400000 \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/default_sku b/device/celestica/x86_64-cel_silverstone_dp-r0/default_sku new file mode 100644 index 000000000000..f2293b1c7cef --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/default_sku @@ -0,0 +1 @@ +Silverstone-DP t1 \ No newline at end of file From f6d2f0171c94d934a859d47eee5485743167ce99 Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Thu, 16 Apr 2020 15:25:47 +0700 Subject: [PATCH 04/17] [platform/broadcom] update silverstone-dp kernel version to 4.9.0-11-2 *Update silverstone-dp kernel package dependency in platform package. --- platform/broadcom/sonic-platform-modules-cel/debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/control b/platform/broadcom/sonic-platform-modules-cel/debian/control index 984d320ee476..1b1471b0d88c 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/control +++ b/platform/broadcom/sonic-platform-modules-cel/debian/control @@ -28,5 +28,5 @@ Description: kernel modules for platform devices such as led, sfp. Package: platform-modules-silverstone-dp Architecture: amd64 -Depends: linux-image-4.9.0-9-2-amd64 +Depends: linux-image-4.9.0-11-2-amd64 Description: kernel modules for platform devices such as led, sfp. From 5ae98cd4ad8ddb599726102c20a2bd0b08fb75f9 Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Thu, 23 Apr 2020 13:25:58 +0700 Subject: [PATCH 05/17] [platform-module-cel] Update Silverstone-DP to use buster kernel. --- .../sonic-platform-modules-cel/debian/control | 2 +- .../silverstone-dp/modules/cls-switchboard.c | 84 +++++++++---------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/control b/platform/broadcom/sonic-platform-modules-cel/debian/control index 4a629277ca09..681adc58d33d 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/control +++ b/platform/broadcom/sonic-platform-modules-cel/debian/control @@ -28,5 +28,5 @@ Description: kernel modules for platform devices such as led, sfp. Package: platform-modules-silverstone-dp Architecture: amd64 -Depends: linux-image-4.9.0-11-2-amd64 +Depends: linux-image-4.19.0-6-amd64-unsigned Description: kernel modules for platform devices such as led, sfp. diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c index ebe5e7742a86..917f4d3572e4 100644 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include "i2c-ocores.h" #include "xcvr-cls.h" @@ -58,7 +58,7 @@ struct i2c_bus_config { struct resource *res; ssize_t num_res; struct ocores_i2c_platform_data pdata; -}; +}; /* switchbrd_priv - switchboard private data */ struct switchbrd_priv { @@ -73,27 +73,27 @@ struct switchbrd_priv { /* I2C bus speed param */ static int bus_clock_master_1 = 100; module_param(bus_clock_master_1, int, 0660); -MODULE_PARM_DESC(bus_clock_master_1, +MODULE_PARM_DESC(bus_clock_master_1, "I2C master 1 bus speed in KHz 50/80/100/200/400"); static int bus_clock_master_2 = 100; module_param(bus_clock_master_2, int, 0660); -MODULE_PARM_DESC(bus_clock_master_2, +MODULE_PARM_DESC(bus_clock_master_2, "I2C master 2 bus speed in KHz 50/80/100/200/400"); static int bus_clock_master_3 = 100; module_param(bus_clock_master_3, int, 0660); -MODULE_PARM_DESC(bus_clock_master_3, +MODULE_PARM_DESC(bus_clock_master_3, "I2C master 3 bus speed in KHz 50/80/100/200/400"); static int bus_clock_master_4 = 100; module_param(bus_clock_master_4, int, 0660); -MODULE_PARM_DESC(bus_clock_master_4, +MODULE_PARM_DESC(bus_clock_master_4, "I2C master 4 bus speed in KHz 50/80/100/200/400"); static int bus_clock_master_5 = 100; module_param(bus_clock_master_5, int, 0660); -MODULE_PARM_DESC(bus_clock_master_5, +MODULE_PARM_DESC(bus_clock_master_5, "I2C master 5 bus speed in KHz 50/80/100/200/400"); /* PCA9548 channel config on MASTER BUS 3 */ @@ -183,54 +183,54 @@ static struct i2c_board_info i2c_info_3[] = { static struct resource cls_i2c_res_1[] = { { .start = 0x800, .end = 0x81F, - .flags = IORESOURCE_MEM,}, + .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for i2c bus 2 */ static struct resource cls_i2c_res_2[] = { { .start = 0x820, .end = 0x83F, - .flags = IORESOURCE_MEM,}, + .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for i2c bus 3 */ static struct resource cls_i2c_res_3[] = { { .start = 0x840, .end = 0x85F, - .flags = IORESOURCE_MEM,}, + .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for i2c bus 4 */ static struct resource cls_i2c_res_4[] = { { .start = 0x860, .end = 0x87F, - .flags = IORESOURCE_MEM,}, + .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for i2c bus 5 */ static struct resource cls_i2c_res_5[] = { { .start = 0x880, .end = 0x89F, - .flags = IORESOURCE_MEM,}, + .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for reg access */ static struct resource reg_io_res[] = { - { + { .start = 0x00, .end = 0xFF, .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for spi flash firmware upgrade */ static struct resource spi_flash_res[] = { - { + { .start = 0x1200, .end = 0x121F, .flags = IORESOURCE_MEM,}, }; /* Resource IOMEM for front panel XCVR */ static struct resource xcvr_res[] = { - { + { .start = 0x4000, .end = 0x421F, .flags = IORESOURCE_MEM,}, }; @@ -251,9 +251,9 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 2, - .res = cls_i2c_res_2, - .num_res = ARRAY_SIZE(cls_i2c_res_2), + .id = 2, + .res = cls_i2c_res_2, + .num_res = ARRAY_SIZE(cls_i2c_res_2), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -265,9 +265,9 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 3, - .res = cls_i2c_res_3, - .num_res = ARRAY_SIZE(cls_i2c_res_3), + .id = 3, + .res = cls_i2c_res_3, + .num_res = ARRAY_SIZE(cls_i2c_res_3), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -279,9 +279,9 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 4, - .res = cls_i2c_res_4, - .num_res = ARRAY_SIZE(cls_i2c_res_4), + .id = 4, + .res = cls_i2c_res_4, + .num_res = ARRAY_SIZE(cls_i2c_res_4), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -293,9 +293,9 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 5, - .res = cls_i2c_res_5, - .num_res = ARRAY_SIZE(cls_i2c_res_5), + .id = 5, + .res = cls_i2c_res_5, + .num_res = ARRAY_SIZE(cls_i2c_res_5), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -379,10 +379,10 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) goto err_disable_device; } - dev_dbg(&dev->dev, "BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR, + dev_dbg(&dev->dev, "BAR%d res: 0x%lx-0x%llx\n", MMIO_BAR, rstart, pci_resource_end(dev, MMIO_BAR)); - priv = devm_kzalloc(&dev->dev, + priv = devm_kzalloc(&dev->dev, sizeof(struct switchbrd_priv), GFP_KERNEL); if (!priv){ err = -ENOMEM; @@ -392,8 +392,8 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_set_drvdata(dev, priv); num_i2c_bus = ARRAY_SIZE(i2c_bus_configs); i2cbuses_pdev = devm_kzalloc( - &dev->dev, - num_i2c_bus * sizeof(struct platform_device*), + &dev->dev, + num_i2c_bus * sizeof(struct platform_device*), GFP_KERNEL); reg_io_res[0].start += rstart; @@ -403,7 +403,7 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) xcvr_res[0].end += rstart; regio_pdev = platform_device_register_resndata( - &dev->dev, "cls-swbrd-io", + &dev->dev, "cls-swbrd-io", -1, reg_io_res, ARRAY_SIZE(reg_io_res), NULL, 0); @@ -415,12 +415,12 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) } xcvr_pdev = platform_device_register_resndata( - NULL, - "cls-xcvr", + NULL, + "cls-xcvr", -1, - xcvr_res, + xcvr_res, ARRAY_SIZE(xcvr_res), - &xcvr_data, + &xcvr_data, sizeof(xcvr_data)); if (IS_ERR(xcvr_pdev)) { @@ -455,20 +455,20 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) } dev_dbg(&dev->dev, "i2c-bus.%d: 0x%llx - 0x%llx\n", - i2c_bus_configs[i].id, - i2c_bus_configs[i].res[0].start, + i2c_bus_configs[i].id, + i2c_bus_configs[i].res[0].start, i2c_bus_configs[i].res[0].end); i2cbuses_pdev[i] = platform_device_register_resndata( - &dev->dev, "cls-ocores-i2c", + &dev->dev, "cls-ocores-i2c", i2c_bus_configs[i].id, - i2c_bus_configs[i].res, + i2c_bus_configs[i].res, i2c_bus_configs[i].num_res, - &i2c_bus_configs[i].pdata, + &i2c_bus_configs[i].pdata, sizeof(i2c_bus_configs[i].pdata)); if (IS_ERR(i2cbuses_pdev[i])) { - dev_err(&dev->dev, "Failed to register ocores-i2c.%d\n", + dev_err(&dev->dev, "Failed to register ocores-i2c.%d\n", i2c_bus_configs[i].id); err = PTR_ERR(i2cbuses_pdev[i]); goto err_unregister_ocore; From ae39e4baff869646003f030781fcd8ebd7f5fe05 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Thu, 23 Apr 2020 14:38:12 +0700 Subject: [PATCH 06/17] [device/celestica]: implement sonic_platform api v1.0 for silverstone_dp --- .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 262 ++++ .../sonic_platform/component.py | 121 ++ .../sonic_platform/eeprom.py | 118 ++ .../sonic_platform/fan.py | 312 ++++ .../sonic_platform/helper.py | 121 ++ .../sonic_platform/platform.py | 23 + .../sonic_platform/psu.py | 248 +++ .../sonic_platform/sfp.py | 1339 +++++++++++++++++ .../sonic_platform/thermal.py | 170 +++ .../sonic_platform/watchdog.py | 233 +++ 11 files changed, 2949 insertions(+) create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/__init__.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/component.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/eeprom.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/fan.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/platform.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/psu.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/sfp.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/thermal.py create mode 100644 device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/watchdog.py diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/__init__.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..d82f3749319c --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..ac0c822d61e2 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -0,0 +1,262 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +try: + import sys + import re + import os + import subprocess + import json + from sonic_platform_base.chassis_base import ChassisBase + from helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 7 +NUM_FAN = 2 +NUM_PSU = 2 +NUM_THERMAL = 14 +NUM_SFP = 30 +NUM_COMPONENT = 5 + +IPMI_OEM_NETFN = "0x3A" +IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06" +TLV_EEPROM_I2C_BUS = 0 +TLV_EEPROM_I2C_ADDR = 56 + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.sfp_module_initialized = False + self.__initialize_components() + + if not self._api_helper.is_host(): + self.__initialize_psu() + self.__initialize_fan() + self.__initialize_eeprom() + self.__initialize_thermals() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + for index in range(0, NUM_SFP): + sfp = Sfp(index) + self._sfp_list.append(sfp) + self.sfp_module_initialized = True + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_fan(self): + from sonic_platform.fan import 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) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Eeprom + self._eeprom = Eeprom(TLV_EEPROM_I2C_BUS, TLV_EEPROM_I2C_ADDR) + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.get_mac() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.get_eeprom() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + + status, raw_cause = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_REBOOT_CAUSE) + hx_cause = raw_cause.split()[0] if status and len( + raw_cause.split()) > 0 else 00 + reboot_cause = { + "00": self.REBOOT_CAUSE_HARDWARE_OTHER, + "11": self.REBOOT_CAUSE_POWER_LOSS, + "22": self.REBOOT_CAUSE_NON_HARDWARE, + "33": self.REBOOT_CAUSE_HARDWARE_OTHER, + "44": self.REBOOT_CAUSE_NON_HARDWARE, + "55": self.REBOOT_CAUSE_NON_HARDWARE, + "66": self.REBOOT_CAUSE_WATCHDOG, + "77": self.REBOOT_CAUSE_NON_HARDWARE + }.get(hx_cause, self.REBOOT_CAUSE_HARDWARE_OTHER) + + description = { + "00": "Unknown reason", + "11": "The last reset is Power on reset", + "22": "The last reset is soft-set CPU warm reset", + "33": "The last reset is soft-set CPU cold reset", + "44": "The last reset is CPU warm reset", + "55": "The last reset is CPU cold reset", + "66": "The last reset is watchdog reset", + "77": "The last reset is power cycle reset" + }.get(hx_cause, "Unknown reason") + + return (reboot_cause, description) + + ############################################################## + ######################## 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 (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + ############################################################## + ####################### Other methods ######################## + ############################################################## + + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + """ + if self._watchdog is None: + from sonic_platform.watchdog import Watchdog + self._watchdog = Watchdog() + + return self._watchdog + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self.get_serial_number() + + 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 True diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/component.py new file mode 100644 index 000000000000..ea76eede7279 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/component.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import json +import os.path + +try: + from sonic_platform_base.component_base import ComponentBase + from helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +COMPONENT_LIST = [ + ("BIOS", "Basic Input/Output System"), + ("BMC", "Baseboard Management Controller"), + ("SWITCH_CPLD", "Switch board CPLD"), + ("BASE_CPLD", "Base board CPLD"), + ("FPGA", "Field-programmable gate array") +] +SW_CPLD_VER_PATH = "/sys/module/switch_cpld/version" +BASE_CPLD_VER_PATH = "/sys/module/baseboard_lpc/version" +CPLD_UPGRADE_OPT = 4 +BIOS_VER_PATH = "/sys/class/dmi/id/bios_version" +BIOS__UPGRADE_OPT = 2 +BMC_VER_CMD = "ipmitool mc info | grep 'Firmware Revision'" +BMC_UPGRADE_OPT = 1 +CFUFLASH_FW_UPGRADE_CMD = "CFUFLASH -cd -d {} -mse 3 {}" +MEM_PCI_RESOURCE = "/sys/bus/pci/devices/0000:09:00.0/resource0" +FPGA_VER_MEM_OFFSET = 0 + + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index): + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + self._api_helper = APIHelper() + + def __get_bmc_ver(self): + bmc_ver = "Unknown" + status, raw_bmc_data = self._api_helper.run_command(BMC_VER_CMD) + if status: + bmc_ver_data = raw_bmc_data.split(":") + bmc_ver = bmc_ver_data[-1].strip() if len( + bmc_ver_data) > 1 else bmc_ver + return bmc_ver + + def __get_fpga_ver(self): + fpga_ver = "Unknown" + status, reg_val = self._api_helper.pci_get_value( + MEM_PCI_RESOURCE, FPGA_VER_MEM_OFFSET) + if status: + major = reg_val[0] / pow(2, 16) + minor = reg_val[0] % pow(2, 16) + fpga_ver = '{}.{}'.format(major, minor) + return fpga_ver + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = { + "BIOS": self._api_helper.read_txt_file(BIOS_VER_PATH), + "BMC": self.__get_bmc_ver(), + "FPGA": self.__get_fpga_ver(), + "SWITCH_CPLD": self._api_helper.read_txt_file(SW_CPLD_VER_PATH), + "BASE_CPLD": self._api_helper.read_txt_file(BASE_CPLD_VER_PATH), + }.get(self.name, "Unknown") + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + install_command = { + "BMC": CFUFLASH_FW_UPGRADE_CMD.format(BMC_UPGRADE_OPT, image_path), + "BIOS": CFUFLASH_FW_UPGRADE_CMD.format(BIOS__UPGRADE_OPT, image_path), + "SWITCH_CPLD": CFUFLASH_FW_UPGRADE_CMD.format(CPLD_UPGRADE_OPT, image_path), + "BASE_CPLD": CFUFLASH_FW_UPGRADE_CMD.format(CPLD_UPGRADE_OPT, image_path) + }.get(self.name, None) + + if not os.path.isfile(image_path) or install_command is None: + return False + + # print(install_command) + # status = self._api_helper.run_interactive_command(install_command) + return False diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..24701a64e5bf --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/eeprom.py @@ -0,0 +1,118 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + import glob + import os + import sys + import imp + import re + from array import array + from cStringIO import StringIO + from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self, i2c, reg): + self._eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-00{1}/eeprom".format(i2c, reg) + super(Eeprom, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except: + pass + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def get_eeprom(self): + return self._eeprom + + def get_product(self): + return self._eeprom.get('0x21', "Undefined.") + + def get_pn(self): + return self._eeprom.get('0x22', "Undefined.") + + def get_serial(self): + return self._eeprom.get('0x23', "Undefined.") + + def get_mac(self): + return self._eeprom.get('0x24', "Undefined.") diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..79d0395a9515 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/fan.py @@ -0,0 +1,312 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +import json +import math +import os.path + +try: + from sonic_platform_base.fan_base import FanBase + from helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", "FAN-3F", "FAN-3R", + "FAN-4F", "FAN-4R", "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R", "FAN-7F", "FAN-7R"] + +IPMI_OEM_NETFN = "0x3A" +IPMI_SENSOR_NETFN = "0x04" +IPMI_FAN_SPEED_CMD = "0x2D {}" +IPMI_AIR_FLOW_CMD = "0x0A {}" +IPMI_FAN_PRESENT_CMD = "0x06 0x03 {}" +IPMI_SET_FAN_LED_CMD = "0x07 {} {}" +IPMI_GET_FAN_LED_CMD = "0x08 {}" +IPMI_SET_PWM = "0x03 0x01 0x02 {} {}" + +IPMI_FRU_MODEL_KEY = "Board Part Number" +IPMI_FRU_SERIAL_KEY = "Board Serial" + +MAX_OUTLET = 24700 +MAX_INLET = 29700 +SPEED_TOLERANCE = 10 + +FAN1_FRONT_SS_ID = "0x0D" +FAN1_REAR_SS_ID = "0x45" +FAN_LED_OFF_CMD = "0x00" +FAN_LED_GREEN_CMD = "0x01" +FAN_LED_RED_CMD = "0x02" +FAN1_LED_CMD = "0x04" +FAN_PWM_REGISTER_START = 0x22 +FAN_PWM_REGISTER_STEP = 0x10 +FAN1_FRU_ID = 6 + +NUM_OF_FAN_TRAY = 7 +PSU_FAN_SPEED = { + 0: "0x33", + 1: "0x3D" +} +PSU_FAN2_FRONT_SS_ID = "0x3D" +NULL_VAL = "N/A" + + +class Fan(FanBase): + """Platform-specific Fan class""" + + 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._api_helper = APIHelper() + self.index = self.fan_tray_index * 2 + self.fan_index + + 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 + fan_direction_key = hex(self.fan_tray_index) if not self.is_psu_fan else hex( + self.psu_index + NUM_OF_FAN_TRAY) + status, raw_flow = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_AIR_FLOW_CMD.format(fan_direction_key)) + if status and raw_flow == "01": + direction = self.FAN_DIRECTION_INTAKE + + return direction + + def get_speed(self): + """ + 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: + M = 150 + Max F2B = 24700 RPM + Max B2F = 29700 RPM + """ + + max_rpm = MAX_OUTLET if self.fan_index % 2 == 0 else MAX_INLET + fan1_ss_start = FAN1_FRONT_SS_ID if self.fan_index % 2 == 0 else FAN1_REAR_SS_ID + + ss_id = hex(int(fan1_ss_start, 16) + + self.fan_tray_index) if not self.is_psu_fan else PSU_FAN_SPEED.get(self.psu_index) + + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_FAN_SPEED_CMD.format(ss_id)) + + ss_read = raw_ss_read.split()[0] + rpm_speed = int(ss_read, 16)*150 + speed = int(float(rpm_speed)/max_rpm * 100) + + return speed + + def get_target_speed(self): + """ + 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 + return target + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return SPEED_TOLERANCE + + def set_speed(self, speed): + """ + 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 + Notes: + pwm setting mode must set as Manual + manual: ipmitool raw 0x3a 0x06 0x01 0x0 + auto: ipmitool raw 0x3a 0x06 0x01 0x1 + """ + # ipmitool raw 0x3a 0x03 0x01 0x02 {register} {pwm_speed} + # register = 22 32 42 52 62 72 82 + + if self.is_psu_fan: + # TODO + return False + + speed_hex = hex(int(float(speed)/100 * 255)) + fan_register_hex = hex(FAN_PWM_REGISTER_START + + (self.fan_tray_index*FAN_PWM_REGISTER_STEP)) + + set_speed_cmd = IPMI_SET_PWM.format(fan_register_hex, speed_hex) + status, set_speed_res = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, set_speed_cmd) + + set_speed = False if not status else True + + return set_speed + + def set_status_led(self, color): + """ + 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 + + Note: + LED setting mode must set as Manual + manual: ipmitool raw 0x3A 0x09 0x02 0x00 + auto: ipmitool raw 0x3A 0x09 0x02 0x01 + """ + + if self.is_psu_fan: + # Not support + return False + + led_cmd = { + self.STATUS_LED_COLOR_GREEN: FAN_LED_GREEN_CMD, + self.STATUS_LED_COLOR_RED: FAN_LED_RED_CMD, + self.STATUS_LED_COLOR_OFF: FAN_LED_OFF_CMD + }.get(color) + + fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index) + status, set_led = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_SET_FAN_LED_CMD.format(fan_selector, led_cmd)) + set_status_led = False if not status else True + + return set_status_led + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + + Note: + STATUS_LED_COLOR_GREEN = "green" + STATUS_LED_COLOR_AMBER = "amber" + STATUS_LED_COLOR_RED = "red" + STATUS_LED_COLOR_OFF = "off" + """ + if self.is_psu_fan: + # Not support + return self.STATUS_LED_COLOR_OFF + + fan_selector = hex(int(FAN1_LED_CMD, 16) + self.fan_tray_index) + status, hx_color = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_FAN_LED_CMD.format(fan_selector)) + + status_led = { + "00": self.STATUS_LED_COLOR_OFF, + "01": self.STATUS_LED_COLOR_GREEN, + "02": self.STATUS_LED_COLOR_RED, + }.get(hx_color, self.STATUS_LED_COLOR_OFF) + + return status_led + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + 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): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + if self.is_psu_fan: + return True + + presence = False + status, raw_present = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_FAN_PRESENT_CMD.format(hex(self.index))) + if status and raw_present == "00": + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + if self.is_psu_fan: + return NULL_VAL + + model = NULL_VAL + ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_MODEL_KEY) + + fru_pn_list = raw_model.split() + if len(fru_pn_list) > 4: + model = fru_pn_list[4] + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + if self.is_psu_fan: + return NULL_VAL + + serial = NULL_VAL + ipmi_fru_idx = self.fan_tray_index + FAN1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_SERIAL_KEY) + + fru_sr_list = raw_model.split() + if len(fru_sr_list) > 3: + serial = fru_sr_list[3] + + return serial + + 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_speed() > 0 diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py new file mode 100644 index 000000000000..86fc5ea726ef --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +import os +import struct +import subprocess +from sonic_daemon_base.daemon_base import DaemonBase +from mmap import * + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = DaemonBase().get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except: + status = False + return status, result + + def run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except: + return False + return True + + 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 None + + def read_one_line_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.readline() + return data.strip() + except IOError: + pass + return None + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format( + str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except: + status = False + return status, result diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/platform.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..a632de87e742 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/platform.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + 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): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..9ff912e32b7c --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/psu.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os +import re +import math +import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from helper import APIHelper + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_NAME_LIST = ["PSU-L", "PSU-R"] +PSU_NUM_FAN = [1, 1] + +IPMI_SENSOR_NETFN = "0x04" +IPMI_OEM_NETFN = "0x3A" +IPMI_SS_READ_CMD = "0x2D {}" +IPMI_SET_PSU_LED_CMD = "0x07 0x02 {}" +IPMI_GET_PSU_LED_CMD = "0x08 0x02" +IPMI_FRU_MODEL_KEY = "Board Part Number" +IPMI_FRU_SERIAL_KEY = "Board Serial" + +PSU_LED_OFF_CMD = "0x00" +PSU_LED_GREEN_CMD = "0x01" +PSU_LED_AMBER_CMD = "0x02" + +PSU1_VOUT_SS_ID = "0x36" +PSU1_COUT_SS_ID = "0x37" +PSU1_POUT_SS_ID = "0x38" +PSU1_STATUS_REG = "0x2f" + +PSU2_VOUT_SS_ID = "0x40" +PSU2_COUT_SS_ID = "0x41" +PSU2_POUT_SS_ID = "0x42" +PSU2_STATUS_REG = "0x39" + +PSU1_FRU_ID = 3 + +SS_READ_OFFSET = 0 +NULL_VAL = "N/A" + + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index): + PsuBase.__init__(self) + self.index = psu_index + 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) + self._api_helper = APIHelper() + + def find_value(self, in_string): + result = re.search("^.+ ([0-9a-f]{2}) .+$", in_string) + return result.group(1) if result else result + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + psu_voltage = 0.0 + psu_vout_key = globals()['PSU{}_VOUT_SS_ID'.format(self.index+1)] + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_vout_key)) + ss_read = raw_ss_read.split()[SS_READ_OFFSET] + # Formula: Rx1x10^-1 + psu_voltage = int(ss_read, 16) * math.pow(10, -1) + + return psu_voltage + + 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 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 + psu_cout_key = globals()['PSU{}_COUT_SS_ID'.format(self.index+1)] + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_cout_key)) + ss_read = raw_ss_read.split()[SS_READ_OFFSET] + # Formula: Rx5x10^-1 + psu_current = int(ss_read, 16) * 5 * math.pow(10, -1) + + 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 + psu_pout_key = globals()['PSU{}_POUT_SS_ID'.format(self.index+1)] + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pout_key)) + ss_read = raw_ss_read.split()[SS_READ_OFFSET] + # Formula: Rx6x10^0 + psu_power = int(ss_read, 16) * 6 + return psu_power + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + Note + Set manual + ipmitool raw 0x3a 0x09 0x2 0x0 + """ + led_cmd = { + self.STATUS_LED_COLOR_GREEN: PSU_LED_GREEN_CMD, + self.STATUS_LED_COLOR_AMBER: PSU_LED_AMBER_CMD, + self.STATUS_LED_COLOR_OFF: PSU_LED_OFF_CMD + }.get(color) + + status, set_led = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_SET_PSU_LED_CMD.format(led_cmd)) + set_status_led = False if not status else True + + return set_status_led + + 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, hx_color = self._api_helper.ipmi_raw( + IPMI_OEM_NETFN, IPMI_GET_PSU_LED_CMD) + + status_led = { + "00": self.STATUS_LED_COLOR_OFF, + "01": self.STATUS_LED_COLOR_GREEN, + "02": self.STATUS_LED_COLOR_AMBER, + }.get(hx_color, self.STATUS_LED_COLOR_OFF) + + return status_led + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + psu_presence = False + psu_pstatus_key = globals()['PSU{}_STATUS_REG'.format(self.index+1)] + status, raw_status_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) + status_byte = self.find_value(raw_status_read) + + if status: + presence_int = (int(status_byte, 16) >> 0) & 1 + psu_presence = True if presence_int else False + + return psu_presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model = NULL_VAL + ipmi_fru_idx = self.index + PSU1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_MODEL_KEY) + + fru_pn_list = raw_model.split() + if len(fru_pn_list) > 4: + model = fru_pn_list[4] + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial = NULL_VAL + ipmi_fru_idx = self.index + PSU1_FRU_ID + status, raw_model = self._api_helper.ipmi_fru_id( + ipmi_fru_idx, IPMI_FRU_SERIAL_KEY) + + fru_sr_list = raw_model.split() + if len(fru_sr_list) > 3: + serial = fru_sr_list[3] + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + psu_status = False + psu_pstatus_key = globals()['PSU{}_STATUS_REG'.format(self.index+1)] + status, raw_status_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(psu_pstatus_key)) + status_byte = self.find_value(raw_status_read) + + if status: + failure_detected = (int(status_byte, 16) >> 1) & 1 + input_lost = (int(status_byte, 16) >> 3) & 1 + psu_status = False if (input_lost or failure_detected) else True + + return psu_status diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/sfp.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/sfp.py new file mode 100644 index 000000000000..df5d9d22faef --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/sfp.py @@ -0,0 +1,1339 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +import subprocess +import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +INFO_OFFSET = 128 +DOM_OFFSET = 0 + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +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_QSFP = 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 = 2 + +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 +OSFP_VENDOR_NAME_OFFSET = 129 +OSFP_VENDOR_PN_OFFSET = 148 +OSFP_HW_REV_OFFSET = 164 +OSFP_VENDOR_SN_OFFSET = 166 + +# 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_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +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_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 + +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_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +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') + +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') + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" + +PORT_START = 1 +PORT_END = 30 +QSFP_PORT_START = 1 +QSFP_PORT_END = 24 +OSFP_PORT_START = 25 +OSFP_PORT_END = 30 + +PORT_INFO_PATH = '/sys/devices/platform/cls-xcvr' +SFP_I2C_START = 10 + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + + def __init__(self, sfp_index): + SfpBase.__init__(self) + # Init index + self.index = sfp_index + self.port_num = self.index + 1 + self.dom_supported = False + self.sfp_type, self.port_name = self.__get_sfp_info() + self._api_helper = APIHelper() + self.platform = self._api_helper.platform + self.hwsku = self._api_helper.hwsku + + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = {} + + for x in range(PORT_START, PORT_END + 1): + self.port_to_i2c_mapping[x] = (SFP_I2C_START + x) - 1 + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + 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', 'lp_mode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + self._dom_capability_detect() + + def __get_sfp_info(self): + port_name = "Unknown" + sfp_type = "Unknown" + + if self.port_num >= QSFP_PORT_START and self.port_num <= QSFP_PORT_END: + sfp_type = QSFP_TYPE + port_name = "QSFP" + str(self.port_num - QSFP_PORT_START + 1) + elif self.port_num >= OSFP_PORT_START and self.port_num <= OSFP_PORT_END: + sfp_type = OSFP_TYPE + port_name = "QSFPDD" + str(self.port_num - OSFP_PORT_START + 1) + return sfp_type, port_name + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + 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._api_helper.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 = [] + 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) + 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 _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() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # 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_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int( + qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_qsfp_dom_capability( + qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self.__read_eeprom_specific_bytes( + QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params( + qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability[ + 'data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator( + qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + 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 + self.qsfp_page3_available = False + + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + 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 + self.dom_tx_disable_supported = ( + int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + 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 + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardwarerev |1*255VCHAR |hardware version of SFP + serialnum |1*255VCHAR |serial number of the SFP + manufacturename |1*255VCHAR |SFP vendor name + modelname |1*255VCHAR |SFP model name + Connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + if not self.get_presence(): + return transceiver_info_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 self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return None + + sfp_type_raw = self.__read_eeprom_specific_bytes( + (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( + (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( + (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( + (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( + (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 + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['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'] = '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'] = '{}' + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + + else: + if self.sfp_type == QSFP_TYPE: + 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 + 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 + + 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) + + 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) + + 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) + + 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) + + 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) + + 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'] + 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 self.sfp_type == QSFP_TYPE: + 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']) + else: + 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 + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + 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 + 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.fromkeys(self.dom_dict_keys, 'N/A') + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is 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: + 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: + 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 + + 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']) + + 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']) + + transceiver_dom_info_dict['tx1bias'] = self.__convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = self.__convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = self.__convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = self.__convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value']) + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + + 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['tx1bias'] = self.__convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value']) + transceiver_dom_info_dict['tx1power'] = self.__convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value']) + + 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. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = dict.fromkeys( + self.threshold_dict_keys, 'N/A') + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values( + dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values( + dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['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']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + 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) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + 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): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + reg_status = self._api_helper.read_one_line_file( + "/".join([PORT_INFO_PATH, self.port_name, "qsfp_resetL"])) + + return (reg_status == 0) + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + 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 + if self.sfp_type == OSFP_TYPE: + return False + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx1_los = (rx_los_data & 0x01 != 0) + rx2_los = (rx_los_data & 0x02 != 0) + rx3_los = (rx_los_data & 0x04 != 0) + rx4_los = (rx_los_data & 0x08 != 0) + rx_los = (rx1_los and rx2_los and rx3_los and rx4_los) + else: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los = (rx_los_data & 0x02 != 0) + + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + 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. + """ + tx4_fault = False + + if self.sfp_type == OSFP_TYPE or not self.dom_supported: + return False + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx1_fault = (tx_fault_data & 0x01 != 0) + tx2_fault = (tx_fault_data & 0x02 != 0) + tx3_fault = (tx_fault_data & 0x04 != 0) + tx4_fault = (tx_fault_data & 0x08 != 0) + tx4_fault = ( + tx1_fault and tx2_fault and tx3_fault and tx4_fault) + else: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx4_fault = (tx_fault_data & 0x04 != 0) + + return tx4_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + + tx_disable = False + + if self.sfp_type == OSFP_TYPE and not self.dom_supported: + return False + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx1_disable = (tx_disable_data & 0x01 != 0) + tx2_disable = (tx_disable_data & 0x02 != 0) + tx3_disable = (tx_disable_data & 0x04 != 0) + tx4_disable = (tx_disable_data & 0x08 != 0) + tx_disable = ( + tx1_disable and tx2_disable and tx3_disable and tx4_disable) + else: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable = (tx_disable_data & 0xC0 != 0) + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + tx_disable_list = [False, False, False, False] + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list[0] = (tx_disable_data & 0x01 != 0) + tx_disable_list[1] = (tx_disable_data & 0x02 != 0) + tx_disable_list[2] = (tx_disable_data & 0x04 != 0) + tx_disable_list[3] = (tx_disable_data & 0x08 != 0) + else: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list[0] = (tx_disable_data & 0xC0 != 0) + + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + reg_file = self._api_helper.read_txt_file( + "/".join([PORT_INFO_PATH, self.port_name, "qsfp_lpmode"])) + + # Read status + content = reg_file.rstrip() + reg_value = int(content) + # low power mode is active high + if reg_value == 0: + return False + + return True + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + 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 = ( + 'On' == dom_control_data['data']['PowerOverride']['value']) + return power_override + else: + return False + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + transceiver_bulk_status = self.get_transceiver_bulk_status() + return transceiver_bulk_status.get("temperature", "N/A") + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + transceiver_bulk_status = self.get_transceiver_bulk_status() + return transceiver_bulk_status.get("voltage", "N/A") + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + transceiver_bulk_status = self.get_transceiver_bulk_status() + tx1_bs = transceiver_bulk_status.get("tx1bias", "N/A") + tx2_bs = transceiver_bulk_status.get("tx2bias", "N/A") + tx3_bs = transceiver_bulk_status.get("tx3bias", "N/A") + tx4_bs = transceiver_bulk_status.get("tx4bias", "N/A") + tx_bias_list = [tx1_bs, tx2_bs, tx3_bs, tx4_bs] + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + transceiver_bulk_status = self.get_transceiver_bulk_status() + rx1_p = transceiver_bulk_status.get("rx1power", "N/A") + rx2_p = transceiver_bulk_status.get("rx2power", "N/A") + rx3_p = transceiver_bulk_status.get("rx3power", "N/A") + rx4_p = transceiver_bulk_status.get("rx4power", "N/A") + rx_power_list = [rx1_p, rx2_p, rx3_p, rx4_p] + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + transceiver_bulk_status = self.get_transceiver_bulk_status() + tx1_p = transceiver_bulk_status.get("tx1power", "N/A") + tx2_p = transceiver_bulk_status.get("tx2power", "N/A") + tx3_p = transceiver_bulk_status.get("tx3power", "N/A") + tx4_p = transceiver_bulk_status.get("tx4power", "N/A") + tx_power_list = [tx1_p, tx2_p, tx3_p, tx4_p] + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + + try: + reg_file = open( + "/".join([PORT_INFO_PATH, self.port_name, "qsfp_resetL"]), "w") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(0)) + 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( + "/".join([PORT_INFO_PATH, self.port_name, "qsfp_resetL"]), "w") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_file.seek(0) + reg_file.write(hex(1)) + reg_file.close() + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + tx_disable_ctl = 0xf if tx_disable else 0x0 + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if self.sfp_type == QSFP_TYPE: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + tx_enable_mask = [0xe, 0xd, 0xb, 0x7] + tx_disable_mask = [0x1, 0x3, 0x7, 0xf] + tx_disable_ctl = channel_state | tx_disable_mask[ + channel] if disable else channel_state & tx_enable_mask[channel] + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + try: + reg_file = open( + "/".join([PORT_INFO_PATH, self.port_name, "qsfp_lpmode"]), "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + content = hex(lpmode) + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + if self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + 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): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + sysfs_filename = "qsfp_modprsL" + reg_path = "/".join([PORT_INFO_PATH, self.port_name, sysfs_filename]) + + # Read status + try: + reg_file = open(reg_path) + content = reg_file.readline().rstrip() + reg_value = int(content) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # Module present is active low + if reg_value == 0: + return True + + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + return transceiver_dom_info_dict.get("modelname", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + 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 not self.get_reset_status() diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/thermal.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/thermal.py new file mode 100644 index 000000000000..516460ad3914 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/thermal.py @@ -0,0 +1,170 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import re +import os.path + +try: + from sonic_platform_base.thermal_base import ThermalBase + from helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +IPMI_SENSOR_NETFN = "0x04" +IPMI_SS_READ_CMD = "0x2D {}" +IPMI_SS_THRESHOLD_CMD = "0x27 {}" +IPMI_SS_STATUS = "0x2B {}" +DEFUALT_LOWER_TRESHOLD = 0.0 +HIGH_TRESHOLD_SET_KEY = "unc" +NULL_VAL = "N/A" + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + ThermalBase.__init__(self) + self._api_helper = APIHelper() + self.index = thermal_index + self.THERMAL_LIST = [ + ('TEMP_FAN_U52', 'Fan Tray Middle Temperature Sensor', '0x00'), + ('TEMP_FAN_U17', 'Fan Tray Right Temperature Sensor', '0x01'), + ('TEMP_SW_U52', 'Switchboard Left Inlet Temperature Sensor', '0x02'), + ('TEMP_SW_U16', 'Switchboard Right Inlet Temperature Sensor', '0x03'), + ('TEMP_BB_U3', 'Baseboard Temperature Sensor', '0x04'), + ('TEMP_CPU', 'CPU Internal Temperature Sensor', '0x05'), + ('PSU1_Temp1', 'PSU1 Internal Temperature Sensor', '0x34'), + ('PSU1_Temp2', 'PSU1 Internal Temperature Sensor', '0x35'), + ('PSU2_Temp1', 'PSU2 Internal Temperature Sensor', '0x3e'), + ('PSU2_Temp2', 'PSU2 Internal Temperature Sensor', '0x3f'), + ('SW_U45_Temp', 'IR35215 Chip Temperature Sensor', '0x4F'), + ('SW_U72_Temp', 'IR35215 Chip Temperature Sensor', '0x56'), + ('SW_U87_Temp', 'IR35215 Chip Temperature Sensor', '0x5D'), + ('TEMP_SW_Internal', 'ASIC Internal Temperature Sensor', '0x61') + ] + self.sensor_id = self.THERMAL_LIST[self.index][0] + self.sensor_des = self.THERMAL_LIST[self.index][1] + self.sensor_reading_addr = self.THERMAL_LIST[self.index][2] + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temperature = NULL_VAL + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_READ_CMD.format(self.sensor_reading_addr)) + if status and len(raw_ss_read.split()) > 0: + ss_read = raw_ss_read.split()[0] + temperature = float(int(ss_read, 16)) + return temperature + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + high_threshold = NULL_VAL + status, raw_up_thres_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_THRESHOLD_CMD.format(self.sensor_reading_addr)) + if status and len(raw_up_thres_read.split()) > 6: + ss_read = raw_up_thres_read.split()[4] + high_threshold = float(int(ss_read, 16)) + return high_threshold + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + Returns: + A float number, the low threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return NULL_VAL + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + status, ret_txt = self._api_helper.ipmi_set_ss_thres( + self.sensor_id, HIGH_TRESHOLD_SET_KEY, temperature) + return status + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + return False + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + return self.THERMAL_LIST[self.index][0] + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True if self.get_temperature() > 0 else False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self.sensor_des + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return NULL_VAL + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + ss_status = False + status, raw_ss_read = self._api_helper.ipmi_raw( + IPMI_SENSOR_NETFN, IPMI_SS_STATUS.format(self.sensor_reading_addr)) + if status and len(raw_ss_read.split()) > 0: + status_event_read = raw_ss_read.split() + del status_event_read[0] + ss_status = True if all( + x == '00' for x in status_event_read) else False + return ss_status diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/watchdog.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/watchdog.py new file mode 100644 index 000000000000..b539bc06f618 --- /dev/null +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/watchdog.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Watchdog contains an implementation of SONiC Platform Base API +# +############################################################################# +import ctypes +import fcntl +import os +import subprocess +import time +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +""" ioctl constants """ +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +""" Watchdog ioctl commands """ +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +""" Watchdog status constants """ +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +WDT_COMMON_ERROR = -1 +WD_MAIN_IDENTITY = "iTCO_wdt" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + + +class Watchdog(WatchdogBase): + + def __init__(self): + + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = self._gettimeout(self.timeout_path) + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WD_MAIN_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + watchdog = os.open(watchdog_device_path, os.O_RDWR) + return watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + return int(req[0]) + + def _gettimeout(self, timeout_path): + """ + Get watchdog timeout + @return watchdog timeout + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + ################################################################# + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* available + value. + Returns: + An integer specifying the *actual* number of seconds the watchdog + was armed with. On failure returns -1. + """ + + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._enable() + self.armed = True + ret = self.timeout + except IOError as e: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + Returns: + A boolean, True if watchdog is armed, False if not + """ + + return self.armed + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds remaining on + the watchdog timer + Returns: + An integer specifying the number of seconds remaining on thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + + os.close(self.watchdog) From cc23cb5ff85c3b3a5564833da783977c6ba03450 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Thu, 23 Apr 2020 14:39:03 +0700 Subject: [PATCH 07/17] [platform/cel]: add sonic_platform api installer for silverstone-dp device --- .../platform-modules-silverstone-dp.init | 4 ++- .../platform-modules-silverstone-dp.install | 4 ++- .../platform-modules-silverstone-dp.postinst | 4 ++- .../silverstone-dp/setup.py | 34 +++++++++++++++++++ 4 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/setup.py diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init index e1c831c160bf..63614353e44a 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init @@ -49,6 +49,8 @@ start) echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done + /bin/sh /usr/local/bin/platform_api_mgnt.sh init + echo "done." ;; @@ -66,4 +68,4 @@ force-reload|restart) ;; esac -exit 0 \ No newline at end of file +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install index e9b9ab4f8059..4856d1c16a82 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.install @@ -1,2 +1,4 @@ silverstone-dp/cfg/silverstone-dp-modules.conf etc/modules-load.d -silverstone-dp/systemd/platform-modules-silverstone-dp.service lib/systemd/system \ No newline at end of file +silverstone-dp/systemd/platform-modules-silverstone-dp.service lib/systemd/system +silverstone/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_silverstone_dp-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst index e72b729a03e4..5a55cb7fa998 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.postinst @@ -1,3 +1,5 @@ depmod -a systemctl enable platform-modules-silverstone-dp.service -systemctl start platform-modules-silverstone-dp.service \ No newline at end of file +systemctl start platform-modules-silverstone-dp.service + +/usr/local/bin/platform_api_mgnt.sh install diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/setup.py b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/setup.py new file mode 100644 index 000000000000..b7ac23315ba6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/setup.py @@ -0,0 +1,34 @@ +from setuptools import setup + +DEVICE_NAME = 'celestica' +HW_SKU = 'x86_64-cel_silverstone_dp-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', +) From 0aff8de5a33061a44f3a406e0434af420c54e735 Mon Sep 17 00:00:00 2001 From: pariwat Date: Thu, 23 Apr 2020 17:05:34 +0700 Subject: [PATCH 08/17] [device/celestica]: implement SONiC API chassis get_change_event. --- .../sonic_platform/chassis.py | 75 ++++++++++++++++++- .../sonic_platform/helper.py | 9 +++ 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index ac0c822d61e2..fd6cde5ffbd1 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -13,6 +13,7 @@ import re import os import subprocess + import time import json from sonic_platform_base.chassis_base import ChassisBase from helper import APIHelper @@ -23,13 +24,16 @@ NUM_FAN = 2 NUM_PSU = 2 NUM_THERMAL = 14 -NUM_SFP = 30 +NUM_QSFPDD = 6 +NUM_QSFP = 24 NUM_COMPONENT = 5 IPMI_OEM_NETFN = "0x3A" IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06" TLV_EEPROM_I2C_BUS = 0 TLV_EEPROM_I2C_ADDR = 56 +PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/QSFP{0}/interrupt_mask" +PATH_QSFPDD_SYSFS = "/sys/devices/platform/cls-xcvr/QSFPDD{0}/interrupt_mask" class Chassis(ChassisBase): @@ -46,6 +50,7 @@ def __init__(self): self.__initialize_fan() self.__initialize_eeprom() self.__initialize_thermals() + self.__initialize_interrupts() def __initialize_sfp(self): from sonic_platform.sfp import Sfp @@ -83,6 +88,13 @@ def __initialize_components(self): component = Component(index) self._component_list.append(component) + def __initialize_interrupts(self): + # Initial Interrup MASK for QSFP, QSFPDD + for i in range(NUM_QSFP): + self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(i+1), 255) + for i in range(NUM_QSFPDD): + self._api_helper.write_hex_value(PATH_QSFPDD_SYSFS.format(i+1), 255) + def get_base_mac(self): """ Retrieves the base MAC address for the chassis @@ -260,3 +272,64 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ return True + + ############################################################## + ###################### Event methods ######################## + ############################################################## + def __clear_interrupt(self, name): + PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/{0}/interrupt" + self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(name),255) + time.sleep(0.5) + self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(name),0) + return self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(name)) + + def __check_devices_status(self, name): + PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/{0}/qsfp_modprsL" + return self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(name)) + + def __compare_event_object(self, interrup_devices): + QSFP_devices = {} + QSFPDD_devices = {} + json_obj = {} + for device_name in interrup_devices: + if "QSFPDD" in device_name: + QSFPDD_devices[device_name] = 1 - int(self.__check_devices_status(device_name)) + elif "QSFP" in device_name: + QSFP_devices[device_name] = 1 - int(self.__check_devices_status(device_name)) + self.__clear_interrupt(device_name) + if len(QSFP_devices): + json_obj['qsfp'] = QSFP_devices + if len(QSFPDD_devices): + json_obj['qsfp-dd'] = QSFPDD_devices + return json.dumps(json_obj) + + def __check_all_interrupt_event(self): + interrup_device = {} + QSFP_NAME = "QSFP{0}" + QSFPDD_NAME = "QSFPDD{0}" + for i in range(NUM_QSFP): + if self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(i+1)) != '0x00': + interrup_device[QSFP_NAME.format(i+1)] = 1 + for i in range(NUM_QSFPDD): + if self._api_helper.read_txt_file(PATH_QSFPDD_SYSFS.format(i+1)) != '0x00': + interrup_device[QSFPDD_NAME.format(i+1)] = 1 + return interrup_device + + def get_change_event(self, timeout=0): + if timeout == 0 : + flag_change = True + while flag_change: + interrup_device = self.__check_all_interrupt_event() + if len(interrup_device): + flag_change = False + else: + time.sleep(0.5) + return (True , self.__compare_event_object(interrup_device)) + else: + device_list_change = {} + while timeout: + interrup_device = self.__check_all_interrupt_event() + time.sleep(1) + timeout -= 1; + device_list_change = self.__compare_event_object(interrup_device) + return (True , device_list_change) \ No newline at end of file diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py index 86fc5ea726ef..2d5025c0a72c 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/helper.py @@ -68,6 +68,15 @@ def read_one_line_file(self, file_path): except IOError: pass return None + + def write_hex_value(self, file_path,value): + try: + with open(file_path, 'wb') as fd: + data = fd.write(hex(value)) + return data + except IOError: + pass + return None def ipmi_raw(self, netfn, cmd): status = True From 0ba095800a6509bd47668f796a0128b06da54c5d Mon Sep 17 00:00:00 2001 From: pariwat Date: Thu, 23 Apr 2020 17:15:33 +0700 Subject: [PATCH 09/17] [device/celestica]: reverse NUM_SFP variable --- .../x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py | 1 + 1 file changed, 1 insertion(+) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index fd6cde5ffbd1..96a53eae194a 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -26,6 +26,7 @@ NUM_THERMAL = 14 NUM_QSFPDD = 6 NUM_QSFP = 24 +NUM_SFP = 30 NUM_COMPONENT = 5 IPMI_OEM_NETFN = "0x3A" From 0095e7fd18044b2f7999365e885e295fb6c2906e Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 24 Apr 2020 11:02:38 +0700 Subject: [PATCH 10/17] [device/celestica]: init eeprom on silverstone_dp api --- .../x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index 96a53eae194a..5c5020d11674 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -45,11 +45,11 @@ def __init__(self): self._api_helper = APIHelper() self.sfp_module_initialized = False self.__initialize_components() + self.__initialize_eeprom() if not self._api_helper.is_host(): self.__initialize_psu() self.__initialize_fan() - self.__initialize_eeprom() self.__initialize_thermals() self.__initialize_interrupts() From d7eff3b30ae0b0ad87d7ab66b45063ad20b4bf66 Mon Sep 17 00:00:00 2001 From: pariwat Date: Fri, 24 Apr 2020 15:49:13 +0700 Subject: [PATCH 11/17] [device/celestica] Fixed, sysfs path miss match. --- .../sonic_platform/chassis.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index 96a53eae194a..c0c2f2c4c0c0 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -33,8 +33,7 @@ IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06" TLV_EEPROM_I2C_BUS = 0 TLV_EEPROM_I2C_ADDR = 56 -PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/QSFP{0}/interrupt_mask" -PATH_QSFPDD_SYSFS = "/sys/devices/platform/cls-xcvr/QSFPDD{0}/interrupt_mask" + class Chassis(ChassisBase): @@ -90,7 +89,9 @@ def __initialize_components(self): self._component_list.append(component) def __initialize_interrupts(self): - # Initial Interrup MASK for QSFP, QSFPDD + # Initial Interrup MASK for QSFP, QSFPDD + PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/QSFP{0}/interrupt_mask" + PATH_QSFPDD_SYSFS = "/sys/devices/platform/cls-xcvr/QSFPDD{0}/interrupt_mask" for i in range(NUM_QSFP): self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(i+1), 255) for i in range(NUM_QSFPDD): @@ -308,6 +309,8 @@ def __check_all_interrupt_event(self): interrup_device = {} QSFP_NAME = "QSFP{0}" QSFPDD_NAME = "QSFPDD{0}" + PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/QSFP{0}/interrupt" + PATH_QSFPDD_SYSFS = "/sys/devices/platform/cls-xcvr/QSFPDD{0}/interrupt" for i in range(NUM_QSFP): if self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(i+1)) != '0x00': interrup_device[QSFP_NAME.format(i+1)] = 1 From 15d3e68d43caed097053e77928224b4fc5ee8b1d Mon Sep 17 00:00:00 2001 From: pariwat Date: Fri, 24 Apr 2020 16:07:10 +0700 Subject: [PATCH 12/17] [device/celestica] Added dummy event --- .../sonic_platform/chassis.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index c0c2f2c4c0c0..9eff2b1d3588 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -20,6 +20,8 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") +DUMMY_CHANGE_EVENT = True + NUM_FAN_TRAY = 7 NUM_FAN = 2 NUM_PSU = 2 @@ -320,6 +322,8 @@ def __check_all_interrupt_event(self): return interrup_device def get_change_event(self, timeout=0): + if DUMMY_CHANGE_EVENT: + DUMMY_TIMEOUT = 120 if timeout == 0 : flag_change = True while flag_change: @@ -328,12 +332,14 @@ def get_change_event(self, timeout=0): flag_change = False else: time.sleep(0.5) + DUMMY_TIMEOUT < 0 ? flag_change = False: DUMMY_TIMEOUT -= 1 + return (True , self.__compare_event_object(interrup_device)) else: device_list_change = {} while timeout: interrup_device = self.__check_all_interrupt_event() time.sleep(1) - timeout -= 1; + timeout -= 1 device_list_change = self.__compare_event_object(interrup_device) return (True , device_list_change) \ No newline at end of file From 784e64b83260639adbe664fde356504a7b75eddf Mon Sep 17 00:00:00 2001 From: pariwat Date: Fri, 24 Apr 2020 16:14:09 +0700 Subject: [PATCH 13/17] [device/celestica] Adde json return format. --- .../sonic_platform/chassis.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index 9eff2b1d3588..20e22318ba86 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -301,9 +301,9 @@ def __compare_event_object(self, interrup_devices): elif "QSFP" in device_name: QSFP_devices[device_name] = 1 - int(self.__check_devices_status(device_name)) self.__clear_interrupt(device_name) - if len(QSFP_devices): + # if len(QSFP_devices): json_obj['qsfp'] = QSFP_devices - if len(QSFPDD_devices): + # if len(QSFPDD_devices): json_obj['qsfp-dd'] = QSFPDD_devices return json.dumps(json_obj) @@ -332,7 +332,11 @@ def get_change_event(self, timeout=0): flag_change = False else: time.sleep(0.5) - DUMMY_TIMEOUT < 0 ? flag_change = False: DUMMY_TIMEOUT -= 1 + if DUMMY_CHANGE_EVENT: + if DUMMY_TIMEOUT < 0 : + flag_change = False + else: + DUMMY_TIMEOUT -= 1 return (True , self.__compare_event_object(interrup_device)) else: From 33995f90e82d90ba589e7259b68848cd16daba23 Mon Sep 17 00:00:00 2001 From: pariwat Date: Fri, 24 Apr 2020 16:17:09 +0700 Subject: [PATCH 14/17] [device/celestica] fixed indent --- .../x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index 20e22318ba86..10e3b4ab2c6c 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -302,9 +302,9 @@ def __compare_event_object(self, interrup_devices): QSFP_devices[device_name] = 1 - int(self.__check_devices_status(device_name)) self.__clear_interrupt(device_name) # if len(QSFP_devices): - json_obj['qsfp'] = QSFP_devices + json_obj['qsfp'] = QSFP_devices # if len(QSFPDD_devices): - json_obj['qsfp-dd'] = QSFPDD_devices + json_obj['qsfp-dd'] = QSFPDD_devices return json.dumps(json_obj) def __check_all_interrupt_event(self): From 25ed14897943ba3654c14f2f9a43b008c5505a67 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 24 Apr 2020 16:55:34 +0700 Subject: [PATCH 15/17] [device/celestica]: update silverstone_dp get_change_event api --- .../sonic_platform/chassis.py | 117 +++++++++--------- 1 file changed, 60 insertions(+), 57 deletions(-) diff --git a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py index 4189e8a04890..0a32ef92695b 100644 --- a/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_silverstone_dp-r0/sonic_platform/chassis.py @@ -20,22 +20,26 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -DUMMY_CHANGE_EVENT = True - NUM_FAN_TRAY = 7 NUM_FAN = 2 NUM_PSU = 2 NUM_THERMAL = 14 -NUM_QSFPDD = 6 -NUM_QSFP = 24 NUM_SFP = 30 NUM_COMPONENT = 5 +QSFP_PORT_START = 1 +QSFP_PORT_END = 24 +OSFP_PORT_START = 25 +OSFP_PORT_END = 30 + IPMI_OEM_NETFN = "0x3A" IPMI_GET_REBOOT_CAUSE = "0x03 0x00 0x01 0x06" TLV_EEPROM_I2C_BUS = 0 TLV_EEPROM_I2C_ADDR = 56 - +PORT_INFO_PATH = "/sys/devices/platform/cls-xcvr" +PATH_INT_SYSFS = "{0}/{1}/interrupt" +PATH_INTMASK_SYSFS = "{0}/{1}/interrupt_mask" +PATH_PRS_SYSFS = "{0}/{1}/qsfp_modprsL" class Chassis(ChassisBase): @@ -92,12 +96,28 @@ def __initialize_components(self): def __initialize_interrupts(self): # Initial Interrup MASK for QSFP, QSFPDD - PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/QSFP{0}/interrupt_mask" - PATH_QSFPDD_SYSFS = "/sys/devices/platform/cls-xcvr/QSFPDD{0}/interrupt_mask" - for i in range(NUM_QSFP): - self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(i+1), 255) - for i in range(NUM_QSFPDD): - self._api_helper.write_hex_value(PATH_QSFPDD_SYSFS.format(i+1), 255) + sfp_info_obj = {} + for index in range(NUM_SFP): + port_num = index+1 + if port_num in range(QSFP_PORT_START, QSFP_PORT_END+1): + port_name = "QSFP{}".format( + str(port_num - QSFP_PORT_START + 1)) + elif port_num in range(OSFP_PORT_START, OSFP_PORT_END+1): + port_name = "QSFPDD{}".format( + str(port_num - OSFP_PORT_START + 1)) + + sfp_info_obj[index] = {} + sfp_info_obj[index]['intmask_sysfs'] = PATH_INTMASK_SYSFS.format( + PORT_INFO_PATH, port_name) + sfp_info_obj[index]['int_sysfs'] = PATH_INT_SYSFS.format( + PORT_INFO_PATH, port_name) + sfp_info_obj[index]['prs_sysfs'] = PATH_PRS_SYSFS.format( + PORT_INFO_PATH, port_name) + + self._api_helper.write_hex_value( + sfp_info_obj[index]["intmask_sysfs"], 255) + + self.sfp_info_obj = sfp_info_obj def get_base_mac(self): """ @@ -279,52 +299,41 @@ def get_status(self): ############################################################## ###################### Event methods ######################## - ############################################################## - def __clear_interrupt(self, name): - PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/{0}/interrupt" - self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(name),255) + ############################################################## + def __clear_interrupt(self, port_idx): + int_path = self.sfp_info_obj[port_idx]["int_sysfs"] + self._api_helper.write_hex_value(int_path, 255) time.sleep(0.5) - self._api_helper.write_hex_value(PATH_QSFP_SYSFS.format(name),0) - return self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(name)) + self._api_helper.write_hex_value(int_path, 0) + return self._api_helper.read_txt_file(int_path) - def __check_devices_status(self, name): - PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/{0}/qsfp_modprsL" - return self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(name)) + def __check_devices_status(self, port_idx): + prs_path = self.sfp_info_obj[port_idx]["prs_sysfs"] + return self._api_helper.read_txt_file(prs_path) def __compare_event_object(self, interrup_devices): - QSFP_devices = {} - QSFPDD_devices = {} - json_obj = {} - for device_name in interrup_devices: - if "QSFPDD" in device_name: - QSFPDD_devices[device_name] = 1 - int(self.__check_devices_status(device_name)) - elif "QSFP" in device_name: - QSFP_devices[device_name] = 1 - int(self.__check_devices_status(device_name)) - self.__clear_interrupt(device_name) - # if len(QSFP_devices): - json_obj['qsfp'] = QSFP_devices - # if len(QSFPDD_devices): - json_obj['qsfp-dd'] = QSFPDD_devices - return json.dumps(json_obj) + devices = {} + event_obj = {} + for port_idx in interrup_devices: + devices[port_idx] = 1 - \ + int(self.__check_devices_status(port_idx)) + self.__clear_interrupt(port_idx) + + if len(devices): + event_obj['sfp'] = devices + + return json.dumps(event_obj) def __check_all_interrupt_event(self): - interrup_device = {} - QSFP_NAME = "QSFP{0}" - QSFPDD_NAME = "QSFPDD{0}" - PATH_QSFP_SYSFS = "/sys/devices/platform/cls-xcvr/QSFP{0}/interrupt" - PATH_QSFPDD_SYSFS = "/sys/devices/platform/cls-xcvr/QSFPDD{0}/interrupt" - for i in range(NUM_QSFP): - if self._api_helper.read_txt_file(PATH_QSFP_SYSFS.format(i+1)) != '0x00': - interrup_device[QSFP_NAME.format(i+1)] = 1 - for i in range(NUM_QSFPDD): - if self._api_helper.read_txt_file(PATH_QSFPDD_SYSFS.format(i+1)) != '0x00': - interrup_device[QSFPDD_NAME.format(i+1)] = 1 - return interrup_device + interrupt_device = {} + for i in range(NUM_SFP): + int_sysfs = self.sfp_info_obj[i]["int_sysfs"] + if self._api_helper.read_txt_file(int_sysfs) != '0x00': + interrupt_device[i] = 1 + return interrupt_device def get_change_event(self, timeout=0): - if DUMMY_CHANGE_EVENT: - DUMMY_TIMEOUT = 120 - if timeout == 0 : + if timeout == 0: flag_change = True while flag_change: interrup_device = self.__check_all_interrupt_event() @@ -332,13 +341,7 @@ def get_change_event(self, timeout=0): flag_change = False else: time.sleep(0.5) - if DUMMY_CHANGE_EVENT: - if DUMMY_TIMEOUT < 0 : - flag_change = False - else: - DUMMY_TIMEOUT -= 1 - - return (True , self.__compare_event_object(interrup_device)) + return (True, self.__compare_event_object(interrup_device)) else: device_list_change = {} while timeout: @@ -346,4 +349,4 @@ def get_change_event(self, timeout=0): time.sleep(1) timeout -= 1 device_list_change = self.__compare_event_object(interrup_device) - return (True , device_list_change) \ No newline at end of file + return (True, device_list_change) From 94ff9732339a2f850e95653a0880c78a6d2b9bae Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Thu, 28 May 2020 18:03:46 +0700 Subject: [PATCH 16/17] [i2c-ocores] Use I2C bus driver from kernel source tree. --- .../platform-modules-silverstone-dp.init | 4 +- .../silverstone-dp/modules/Makefile | 2 +- .../silverstone-dp/modules/cls-switchboard.c | 8 +- .../silverstone-dp/modules/i2c-ocores.c | 846 ------------------ .../silverstone-dp/modules/i2c-ocores.h | 22 - 5 files changed, 7 insertions(+), 875 deletions(-) delete mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c delete mode 100644 platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init index 63614353e44a..9bb529d0e442 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-silverstone-dp.init @@ -20,12 +20,11 @@ start) modprobe ipmi_devintf modprobe mc24lc64t modprobe baseboard-lpc - modprobe i2c-ocores modprobe cls-switchboard modprobe xcvr-cls modprobe switch_cpld - # Instantiate TLV EEPROM device on I801 bus + # Instantiate TLV EEPROM device on I801 bus devname=`cat /sys/bus/i2c/devices/i2c-0/name` if [[ $devname == 'SMBus I801 adapter at '* ]]; then echo 24lc64t 0x56 > /sys/bus/i2c/devices/i2c-0/new_device @@ -33,6 +32,7 @@ start) # Clear syseeprom cache decode-syseeprom --init 2> /dev/null & + sleep 1 # Attach switchboard CPLD i2c device echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-4/new_device diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile index 2702d08e3a31..fd9b634f94db 100644 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/Makefile @@ -1 +1 @@ -obj-m := baseboard-lpc.o mc24lc64t.o cls-switchboard.o xcvr-cls.o i2c-ocores.o switch_cpld.o \ No newline at end of file +obj-m := baseboard-lpc.o mc24lc64t.o cls-switchboard.o xcvr-cls.o switch_cpld.o \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c index 917f4d3572e4..7123fef345b0 100644 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c +++ b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/cls-switchboard.c @@ -23,10 +23,10 @@ #include #include #include -#include "i2c-ocores.h" +#include #include "xcvr-cls.h" -#define MOD_VERSION "2.1.1" +#define MOD_VERSION "2.1.2" #define DRV_NAME "cls-switchboard" #define I2C_MUX_CHANNEL(_ch, _adap_id, _deselect) \ @@ -460,7 +460,7 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) i2c_bus_configs[i].res[0].end); i2cbuses_pdev[i] = platform_device_register_resndata( - &dev->dev, "cls-ocores-i2c", + &dev->dev, "ocores-i2c", i2c_bus_configs[i].id, i2c_bus_configs[i].res, i2c_bus_configs[i].num_res, @@ -530,6 +530,6 @@ static struct pci_driver clsswbrd_pci_driver = { module_pci_driver(clsswbrd_pci_driver); MODULE_AUTHOR("Pradchaya P."); -MODULE_DESCRIPTION("Celestica Silverstone switchboard driver"); +MODULE_DESCRIPTION("Celestica Silverstone DP switchboard driver"); MODULE_VERSION(MOD_VERSION); MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c deleted file mode 100644 index 587744bcb433..000000000000 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.c +++ /dev/null @@ -1,846 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * i2c-ocores.c: I2C bus driver for OpenCores I2C controller - * (https://opencores.org/project/i2c/overview) - * - * Peter Korsgaard - * - * Support for the GRLIB port of the controller by - * Andreas Larsson - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "i2c-ocores.h" - -#define OCORES_FLAG_POLL BIT(0) - -/* - * 'process_lock' exists because ocores_process() and ocores_process_timeout() - * can't run in parallel. - */ -struct ocores_i2c { - void __iomem *base; - int iobase; - u32 reg_shift; - u32 reg_io_width; - unsigned long flags; - wait_queue_head_t wait; - struct i2c_adapter adap; - struct i2c_msg *msg; - int pos; - int nmsgs; - int state; /* see STATE_ */ - int nack_retry; - int al_count; - spinlock_t process_lock; - struct clk *clk; - int ip_clock_khz; - int bus_clock_khz; - void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value); - u8 (*getreg)(struct ocores_i2c *i2c, int reg); -}; - -/* registers */ -#define OCI2C_PRELOW 0 -#define OCI2C_PREHIGH 1 -#define OCI2C_CONTROL 2 -#define OCI2C_DATA 3 -#define OCI2C_CMD 4 /* write only */ -#define OCI2C_STATUS 4 /* read only, same address as OCI2C_CMD */ - -#define OCI2C_CTRL_IEN 0x40 -#define OCI2C_CTRL_EN 0x80 - -#define OCI2C_CMD_START 0x91 -#define OCI2C_CMD_STOP 0x41 -#define OCI2C_CMD_READ 0x21 -#define OCI2C_CMD_WRITE 0x11 -#define OCI2C_CMD_READ_ACK 0x21 -#define OCI2C_CMD_READ_NACK 0x29 -#define OCI2C_CMD_IACK 0x01 - -#define OCI2C_STAT_IF 0x01 -#define OCI2C_STAT_TIP 0x02 -#define OCI2C_STAT_ARBLOST 0x20 -#define OCI2C_STAT_BUSY 0x40 -#define OCI2C_STAT_NACK 0x80 - -#define STATE_DONE 0 -#define STATE_START 1 -#define STATE_WRITE 2 -#define STATE_READ 3 -#define STATE_ERROR 4 - -#define TYPE_OCORES 0 -#define TYPE_GRLIB 1 - -#define AL_MAX_ALLOW 10 - -static void oc_setreg_8(struct ocores_i2c *i2c, int reg, u8 value) -{ - iowrite8(value, i2c->base + (reg << i2c->reg_shift)); -} - -static void oc_setreg_16(struct ocores_i2c *i2c, int reg, u8 value) -{ - iowrite16(value, i2c->base + (reg << i2c->reg_shift)); -} - -static void oc_setreg_32(struct ocores_i2c *i2c, int reg, u8 value) -{ - iowrite32(value, i2c->base + (reg << i2c->reg_shift)); -} - -static void oc_setreg_16be(struct ocores_i2c *i2c, int reg, u8 value) -{ - iowrite16be(value, i2c->base + (reg << i2c->reg_shift)); -} - -static void oc_setreg_32be(struct ocores_i2c *i2c, int reg, u8 value) -{ - iowrite32be(value, i2c->base + (reg << i2c->reg_shift)); -} - -static inline u8 oc_getreg_8(struct ocores_i2c *i2c, int reg) -{ - return ioread8(i2c->base + (reg << i2c->reg_shift)); -} - -static inline u8 oc_getreg_16(struct ocores_i2c *i2c, int reg) -{ - return ioread16(i2c->base + (reg << i2c->reg_shift)); -} - -static inline u8 oc_getreg_32(struct ocores_i2c *i2c, int reg) -{ - return ioread32(i2c->base + (reg << i2c->reg_shift)); -} - -static inline u8 oc_getreg_16be(struct ocores_i2c *i2c, int reg) -{ - return ioread16be(i2c->base + (reg << i2c->reg_shift)); -} - -static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) -{ - return ioread32be(i2c->base + (reg << i2c->reg_shift)); -} - -static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) -{ - outb(value, i2c->iobase + reg); -} - -static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) -{ - return inb(i2c->iobase + reg); -} - -static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) -{ - i2c->setreg(i2c, reg, value); -} - -static inline u8 oc_getreg(struct ocores_i2c *i2c, int reg) -{ - return i2c->getreg(i2c, reg); -} - -static void ocores_process(struct ocores_i2c *i2c, u8 stat) -{ - struct i2c_msg *msg = i2c->msg; - unsigned long flags; - - /* - * If we spin here is because we are in timeout, so we are going - * to be in STATE_ERROR. See ocores_process_timeout() - */ - spin_lock_irqsave(&i2c->process_lock, flags); - - dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state); - - if ((i2c->state == STATE_DONE) || (i2c->state == STATE_ERROR)) { - /* stop has been sent */ - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); - wake_up(&i2c->wait); - goto out; - } - - /* error? */ - if (stat & OCI2C_STAT_ARBLOST) { - - if (i2c->al_count < AL_MAX_ALLOW){ - i2c->state = STATE_START; - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); - dev_dbg(&i2c->adap.dev, "RETRY: AL\n"); - i2c->al_count++; - } else { - i2c->state = STATE_ERROR; - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); - dev_dbg(&i2c->adap.dev, "ERR: AL\n"); - } - goto out; - } - - if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { - i2c->state = - (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; - - if (stat & OCI2C_STAT_NACK) { - dev_dbg(&i2c->adap.dev, "ERR: NACK\n"); - i2c->state = STATE_ERROR; - if (!(msg->flags & I2C_M_RD)) - i2c->nack_retry = 1; - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); - goto out; - } - } else { - msg->buf[i2c->pos++] = oc_getreg(i2c, OCI2C_DATA); - } - - /* end of msg? */ - if (i2c->pos == msg->len) { - i2c->nmsgs--; - i2c->msg++; - i2c->pos = 0; - msg = i2c->msg; - - if (i2c->nmsgs) { /* end? */ - /* send start? */ - if (!(msg->flags & I2C_M_NOSTART)) { - u8 addr = i2c_8bit_addr_from_msg(msg); - - i2c->state = STATE_START; - - oc_setreg(i2c, OCI2C_DATA, addr); - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); - goto out; - } - i2c->state = (msg->flags & I2C_M_RD) - ? STATE_READ : STATE_WRITE; - } else { - i2c->state = STATE_DONE; - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); - goto out; - } - } - - if (i2c->state == STATE_READ) { - oc_setreg(i2c, OCI2C_CMD, i2c->pos == (msg->len-1) ? - OCI2C_CMD_READ_NACK : OCI2C_CMD_READ_ACK); - } else { - oc_setreg(i2c, OCI2C_DATA, msg->buf[i2c->pos++]); - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_WRITE); - } - -out: - spin_unlock_irqrestore(&i2c->process_lock, flags); -} - -static irqreturn_t ocores_isr(int irq, void *dev_id) -{ - struct ocores_i2c *i2c = dev_id; - u8 stat = oc_getreg(i2c, OCI2C_STATUS); - - dev_dbg(&i2c->adap.dev, "STATUS: 0x%x\n", stat); - - if (!(stat & OCI2C_STAT_IF)) - return IRQ_NONE; - - ocores_process(i2c, stat); - - return IRQ_HANDLED; -} - -/** - * Process timeout event - * @i2c: ocores I2C device instance - */ -static void ocores_process_timeout(struct ocores_i2c *i2c) -{ - unsigned long flags; - - spin_lock_irqsave(&i2c->process_lock, flags); - i2c->state = STATE_ERROR; - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_STOP); - spin_unlock_irqrestore(&i2c->process_lock, flags); -} - -/** - * Wait until something change in a given register - * @i2c: ocores I2C device instance - * @reg: register to query - * @mask: bitmask to apply on register value - * @val: expected result - * @timeout: timeout in jiffies - * - * Timeout is necessary to avoid to stay here forever when the chip - * does not answer correctly. - * - * Return: 0 on success, -ETIMEDOUT on timeout - */ -static int ocores_wait(struct ocores_i2c *i2c, - int reg, u8 mask, u8 val, - const unsigned long timeout) -{ - unsigned long j; - - j = jiffies + timeout; - while (1) { - u8 status = oc_getreg(i2c, reg); - - if ((status & mask) == val) - break; - - if (time_after(jiffies, j)) - return -ETIMEDOUT; - cpu_relax(); - cond_resched(); - } - return 0; -} - -/** - * Wait until is possible to process some data - * @i2c: ocores I2C device instance - * - * Used when the device is in polling mode (interrupts disabled). - * - * Return: 0 on success, -ETIMEDOUT on timeout - */ -static int ocores_poll_wait(struct ocores_i2c *i2c) -{ - u8 mask; - int err; - - if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { - /* transfer is over */ - mask = OCI2C_STAT_BUSY; - } else { - /* on going transfer */ - mask = OCI2C_STAT_TIP; - /* - * We wait for the data to be transferred (8bit), - * then we start polling on the ACK/NACK bit - */ - udelay((8 * 1000) / i2c->bus_clock_khz); - } - - dev_dbg(&i2c->adap.dev, "Wait for: 0x%x\n", mask); - - /* - * once we are here we expect to get the expected result immediately - * so if after 1ms we timeout then something is broken. - */ - err = ocores_wait(i2c, OCI2C_STATUS, mask, 0, msecs_to_jiffies(30)); - if (err) - dev_warn(i2c->adap.dev.parent, - "%s: STATUS timeout, bit 0x%x did not clear in 30ms\n", - __func__, mask); - return err; -} - -/** - * It handles an IRQ-less transfer - * @i2c: ocores I2C device instance - * - * Even if IRQ are disabled, the I2C OpenCore IP behavior is exactly the same - * (only that IRQ are not produced). This means that we can re-use entirely - * ocores_isr(), we just add our polling code around it. - * - * It can run in atomic context - */ -static void ocores_process_polling(struct ocores_i2c *i2c) -{ - while (1) { - irqreturn_t ret; - int err; - - err = ocores_poll_wait(i2c); - if (err) { - i2c->state = STATE_ERROR; - break; /* timeout */ - } - - ret = ocores_isr(-1, i2c); - if (ret == IRQ_NONE) - break; /* all messages have been transferred */ - } -} - -static int ocores_xfer_core(struct ocores_i2c *i2c, - struct i2c_msg *msgs, int num, - bool polling) -{ - int ret; - u8 ctrl; - - ctrl = oc_getreg(i2c, OCI2C_CONTROL); - if (polling) - oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~OCI2C_CTRL_IEN); - else - oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN); - - i2c->msg = msgs; - i2c->pos = 0; - i2c->nmsgs = num; - i2c->state = STATE_START; - i2c->al_count = 0; - - dev_dbg(&i2c->adap.dev, "STATE: %d\n", i2c->state); - - oc_setreg(i2c, OCI2C_DATA, i2c_8bit_addr_from_msg(i2c->msg)); - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); - - if (polling) { - ocores_process_polling(i2c); - } else { - ret = wait_event_timeout(i2c->wait, - (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ); - if (ret == 0) { - ocores_process_timeout(i2c); - return -ETIMEDOUT; - } - } - - return (i2c->state == STATE_DONE) ? num : -EIO; -} - -static int ocores_xfer_polling(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - return ocores_xfer_core(i2c_get_adapdata(adap), msgs, num, true); -} - -static int ocores_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - int ret; - int retry = 0; - int max_retry = 0; - struct ocores_i2c *i2c = i2c_get_adapdata(adap); - - i2c->nack_retry = 0; - - if (i2c->flags & OCORES_FLAG_POLL) { - ret = ocores_xfer_polling(adap, msgs, num); - if (num == 1) - max_retry = 5; - else - max_retry = 5; - - while ((i2c->nack_retry == 1) && (retry < max_retry)) - { - retry++; - i2c->nack_retry = 0; - ret = ocores_xfer_polling(adap, msgs, num); - } - i2c->nack_retry = 0; - return ret; - } - return ocores_xfer_core(i2c, msgs, num, false); -} - -static int ocores_init(struct device *dev, struct ocores_i2c *i2c) -{ - int prescale; - int diff; - u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); - - /* make sure the device is disabled */ - ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); - oc_setreg(i2c, OCI2C_CONTROL, ctrl); - - prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1; - prescale = clamp(prescale, 0, 0xffff); - - diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz; - if (abs(diff) > i2c->bus_clock_khz / 10) { - dev_err(dev, - "Unsupported clock settings: core: %d KHz, bus: %d KHz\n", - i2c->ip_clock_khz, i2c->bus_clock_khz); - return -EINVAL; - } - - oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff); - oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); - - dev_info(dev, "Set bus speed to %d KHz\n", i2c->bus_clock_khz); - dev_info(dev, "Prescale: %d\n", prescale); - - /* Init the device */ - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); - oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); - - return 0; -} - - -static u32 ocores_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; -} - -static const struct i2c_algorithm ocores_algorithm = { - .master_xfer = ocores_xfer, - .functionality = ocores_func, -}; - -static const struct i2c_adapter ocores_adapter = { - .owner = THIS_MODULE, - .name = "cls-i2c-ocores", - .class = I2C_CLASS_DEPRECATED, - .algo = &ocores_algorithm, -}; - -static const struct of_device_id ocores_i2c_match[] = { - { - .compatible = "opencores,i2c-ocores", - .data = (void *)TYPE_OCORES, - }, - { - .compatible = "aeroflexgaisler,i2cmst", - .data = (void *)TYPE_GRLIB, - }, - {}, -}; -MODULE_DEVICE_TABLE(of, ocores_i2c_match); - -#ifdef CONFIG_OF -/* - * Read and write functions for the GRLIB port of the controller. Registers are - * 32-bit big endian and the PRELOW and PREHIGH registers are merged into one - * register. The subsequent registers have their offsets decreased accordingly. - */ -static u8 oc_getreg_grlib(struct ocores_i2c *i2c, int reg) -{ - u32 rd; - int rreg = reg; - - if (reg != OCI2C_PRELOW) - rreg--; - rd = ioread32be(i2c->base + (rreg << i2c->reg_shift)); - if (reg == OCI2C_PREHIGH) - return (u8)(rd >> 8); - else - return (u8)rd; -} - -static void oc_setreg_grlib(struct ocores_i2c *i2c, int reg, u8 value) -{ - u32 curr, wr; - int rreg = reg; - - if (reg != OCI2C_PRELOW) - rreg--; - if (reg == OCI2C_PRELOW || reg == OCI2C_PREHIGH) { - curr = ioread32be(i2c->base + (rreg << i2c->reg_shift)); - if (reg == OCI2C_PRELOW) - wr = (curr & 0xff00) | value; - else - wr = (((u32)value) << 8) | (curr & 0xff); - } else { - wr = value; - } - iowrite32be(wr, i2c->base + (rreg << i2c->reg_shift)); -} - -static int ocores_i2c_of_probe(struct platform_device *pdev, - struct ocores_i2c *i2c) -{ - struct device_node *np = pdev->dev.of_node; - const struct of_device_id *match; - u32 val; - u32 clock_frequency; - bool clock_frequency_present; - - if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) { - /* no 'reg-shift', check for deprecated 'regstep' */ - if (!of_property_read_u32(np, "regstep", &val)) { - if (!is_power_of_2(val)) { - dev_err(&pdev->dev, "invalid regstep %d\n", - val); - return -EINVAL; - } - i2c->reg_shift = ilog2(val); - dev_warn(&pdev->dev, - "regstep property deprecated, use reg-shift\n"); - } - } - - clock_frequency_present = !of_property_read_u32(np, "clock-frequency", - &clock_frequency); - i2c->bus_clock_khz = 100; - - i2c->clk = devm_clk_get(&pdev->dev, NULL); - - if (!IS_ERR(i2c->clk)) { - int ret = clk_prepare_enable(i2c->clk); - - if (ret) { - dev_err(&pdev->dev, - "clk_prepare_enable failed: %d\n", ret); - return ret; - } - i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; - if (clock_frequency_present) - i2c->bus_clock_khz = clock_frequency / 1000; - } - - if (i2c->ip_clock_khz == 0) { - if (of_property_read_u32(np, "opencores,ip-clock-frequency", - &val)) { - if (!clock_frequency_present) { - dev_err(&pdev->dev, - "Missing required parameter 'opencores,ip-clock-frequency'\n"); - clk_disable_unprepare(i2c->clk); - return -ENODEV; - } - i2c->ip_clock_khz = clock_frequency / 1000; - dev_warn(&pdev->dev, - "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n"); - } else { - i2c->ip_clock_khz = val / 1000; - if (clock_frequency_present) - i2c->bus_clock_khz = clock_frequency / 1000; - } - } - - of_property_read_u32(pdev->dev.of_node, "reg-io-width", - &i2c->reg_io_width); - - match = of_match_node(ocores_i2c_match, pdev->dev.of_node); - if (match && (long)match->data == TYPE_GRLIB) { - dev_dbg(&pdev->dev, "GRLIB variant of i2c-ocores\n"); - i2c->setreg = oc_setreg_grlib; - i2c->getreg = oc_getreg_grlib; - } - - return 0; -} -#else -#define ocores_i2c_of_probe(pdev, i2c) -ENODEV -#endif - -static int ocores_i2c_probe(struct platform_device *pdev) -{ - struct ocores_i2c *i2c; - struct ocores_i2c_platform_data *pdata; - struct resource *res; - int irq; - int ret; - int i; - - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) - return -ENOMEM; - - spin_lock_init(&i2c->process_lock); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (res) { - i2c->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(i2c->base)) - return PTR_ERR(i2c->base); - } else { - res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!res) - return -EINVAL; - i2c->iobase = res->start; - if (!devm_request_region(&pdev->dev, res->start, - resource_size(res), - pdev->name)) { - dev_err(&pdev->dev, "Can't get I/O resource.\n"); - return -EBUSY; - } - i2c->setreg = oc_setreg_io_8; - i2c->getreg = oc_getreg_io_8; - } - - pdata = dev_get_platdata(&pdev->dev); - if (pdata) { - i2c->reg_shift = pdata->reg_shift; - i2c->reg_io_width = pdata->reg_io_width; - i2c->ip_clock_khz = pdata->clock_khz; - if (pdata->bus_khz) - i2c->bus_clock_khz = pdata->bus_khz; - else - i2c->bus_clock_khz = 100; - } else { - ret = ocores_i2c_of_probe(pdev, i2c); - if (ret) - return ret; - } - - if (i2c->reg_io_width == 0) - i2c->reg_io_width = 1; /* Set to default value */ - - if (!i2c->setreg || !i2c->getreg) { - bool be = pdata ? pdata->big_endian : - of_device_is_big_endian(pdev->dev.of_node); - - switch (i2c->reg_io_width) { - case 1: - i2c->setreg = oc_setreg_8; - i2c->getreg = oc_getreg_8; - break; - - case 2: - i2c->setreg = be ? oc_setreg_16be : oc_setreg_16; - i2c->getreg = be ? oc_getreg_16be : oc_getreg_16; - break; - - case 4: - i2c->setreg = be ? oc_setreg_32be : oc_setreg_32; - i2c->getreg = be ? oc_getreg_32be : oc_getreg_32; - break; - - default: - dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", - i2c->reg_io_width); - ret = -EINVAL; - goto err_clk; - } - } - - init_waitqueue_head(&i2c->wait); - - irq = platform_get_irq(pdev, 0); - if (irq == -ENXIO) { - i2c->flags |= OCORES_FLAG_POLL; - } else { - if (irq < 0) - return irq; - } - - if (!(i2c->flags & OCORES_FLAG_POLL)) { - ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0, - pdev->name, i2c); - if (ret) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_clk; - } - } - - ret = ocores_init(&pdev->dev, i2c); - if (ret) - goto err_clk; - - /* hook up driver to tree */ - platform_set_drvdata(pdev, i2c); - i2c->adap = ocores_adapter; - i2c_set_adapdata(&i2c->adap, i2c); - i2c->adap.dev.parent = &pdev->dev; - i2c->adap.dev.of_node = pdev->dev.of_node; - - /* add i2c adapter to i2c tree */ - ret = i2c_add_adapter(&i2c->adap); - if (ret) - goto err_clk; - - /* add in known devices to the bus */ - if (pdata) { - for (i = 0; i < pdata->num_devices; i++) - i2c_new_device(&i2c->adap, pdata->devices + i); - } - - return 0; - -err_clk: - clk_disable_unprepare(i2c->clk); - return ret; -} - -static int ocores_i2c_remove(struct platform_device *pdev) -{ - struct ocores_i2c *i2c = platform_get_drvdata(pdev); - u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); - - /* disable i2c logic */ - ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); - oc_setreg(i2c, OCI2C_CONTROL, ctrl); - - /* remove adapter & data */ - i2c_del_adapter(&i2c->adap); - - if (!IS_ERR(i2c->clk)) - clk_disable_unprepare(i2c->clk); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int ocores_i2c_suspend(struct device *dev) -{ - struct ocores_i2c *i2c = dev_get_drvdata(dev); - u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); - - /* make sure the device is disabled */ - ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); - oc_setreg(i2c, OCI2C_CONTROL, ctrl); - - if (!IS_ERR(i2c->clk)) - clk_disable_unprepare(i2c->clk); - return 0; -} - -static int ocores_i2c_resume(struct device *dev) -{ - struct ocores_i2c *i2c = dev_get_drvdata(dev); - - if (!IS_ERR(i2c->clk)) { - unsigned long rate; - int ret = clk_prepare_enable(i2c->clk); - - if (ret) { - dev_err(dev, - "clk_prepare_enable failed: %d\n", ret); - return ret; - } - rate = clk_get_rate(i2c->clk) / 1000; - if (rate) - i2c->ip_clock_khz = rate; - } - return ocores_init(dev, i2c); -} - -static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); -#define OCORES_I2C_PM (&ocores_i2c_pm) -#else -#define OCORES_I2C_PM NULL -#endif - -static struct platform_driver ocores_i2c_driver = { - .probe = ocores_i2c_probe, - .remove = ocores_i2c_remove, - .driver = { - .name = "cls-ocores-i2c", - .of_match_table = ocores_i2c_match, - .pm = OCORES_I2C_PM, - }, -}; - -module_platform_driver(ocores_i2c_driver); - -MODULE_AUTHOR("Peter Korsgaard "); -MODULE_AUTHOR("Pradchaya P "); -MODULE_AUTHOR("Saranpong C "); -MODULE_DESCRIPTION("OpenCores I2C bus driver"); -MODULE_VERSION("1.0.1"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:cls-ocores-i2c"); diff --git a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h b/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h deleted file mode 100644 index 25926b385255..000000000000 --- a/platform/broadcom/sonic-platform-modules-cel/silverstone-dp/modules/i2c-ocores.h +++ /dev/null @@ -1,22 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * i2c-ocores.h - definitions for the i2c-ocores interface - * - * Peter Korsgaard - */ - -#ifndef _LINUX_I2C_OCORES_H -#define _LINUX_I2C_OCORES_H - -struct ocores_i2c_platform_data { - u32 reg_shift; /* register offset shift value */ - u32 reg_io_width; /* register io read/write width */ - u32 clock_khz; /* input clock in kHz */ - u32 bus_khz; /* bus clock in kHz */ - bool big_endian; /* registers are big endian */ - u8 num_devices; /* number of devices in the devices list */ - struct i2c_board_info const *devices; /* devices connected to the bus */ -}; - -#endif /* _LINUX_I2C_OCORES_H */ - From 9a12780d93fe7dac390356493acdf5f6d1576df9 Mon Sep 17 00:00:00 2001 From: Pradchaya P Date: Thu, 28 May 2020 19:15:34 +0700 Subject: [PATCH 17/17] [platform/broadcom] Remove stretch debs from celestica platform makefile --- platform/broadcom/platform-modules-cel.mk | 2 -- 1 file changed, 2 deletions(-) diff --git a/platform/broadcom/platform-modules-cel.mk b/platform/broadcom/platform-modules-cel.mk index 650f0600fb81..c65d958ab52f 100644 --- a/platform/broadcom/platform-modules-cel.mk +++ b/platform/broadcom/platform-modules-cel.mk @@ -33,5 +33,3 @@ $(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE_P CEL_SILVERSTONE-DP_PLATFORM_MODULE = platform-modules-silverstone-dp_$(CEL_SILVERSTONE-DP_PLATFORM_MODULE_VERSION)_amd64.deb $(CEL_SILVERSTONE-DP_PLATFORM_MODULE)_PLATFORM = x86_64-cel_silverstone_dp-r0 $(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_SILVERSTONE-DP_PLATFORM_MODULE))) - -SONIC_STRETCH_DEBS += $(CEL_DX010_PLATFORM_MODULE)