From a3213856b2cacb382b6de1bbe3783f7b96e91276 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 14 Sep 2021 12:52:57 +0700 Subject: [PATCH 01/32] [platform/cel]: add blackstone device --- platform/broadcom/one-image.mk | 1 + platform/broadcom/platform-modules-cel.mk | 5 + .../blackstone/cfg/blackstone-modules.conf | 15 + .../blackstone/modules/Makefile | 1 + .../blackstone/modules/baseboard-lpc.c | 442 ++++++++ .../blackstone/modules/cls-fpga.c | 943 ++++++++++++++++++ .../blackstone/modules/cls-i2c-ocores.c | 846 ++++++++++++++++ .../blackstone/modules/i2c-ocores.h | 22 + .../blackstone/modules/mc24lc64t.c | 174 ++++ .../blackstone/modules/switch_cpld.c | 428 ++++++++ .../blackstone/modules/xcvr-cls.c | 520 ++++++++++ .../blackstone/modules/xcvr-cls.h | 41 + .../blackstone/scripts/platform_sensors.py | 175 ++++ .../blackstone/scripts/sensors | 11 + .../blackstone/setup.py | 35 + .../platform-modules-blackstone.service | 14 + .../sonic-platform-modules-cel/debian/control | 5 + .../sonic-platform-modules-cel/debian/rules | 2 +- 18 files changed, 3679 insertions(+), 1 deletion(-) create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/cfg/blackstone-modules.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/baseboard-lpc.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-i2c-ocores.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/i2c-ocores.h create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/mc24lc64t.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/xcvr-cls.c create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/modules/xcvr-cls.h create mode 100755 platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py create mode 100755 platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/sensors create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-cel/blackstone/systemd/platform-modules-blackstone.service diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 1d14d56f70ab..ce62c8141499 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -66,6 +66,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(JUNIPER_QFX5210_PLATFORM_MODULE) \ $(CEL_SILVERSTONE_PLATFORM_MODULE) \ $(JUNIPER_QFX5200_PLATFORM_MODULE) \ + $(CEL_BLACKSTONE_PLATFORM_MODULE) \ $(DELTA_AGC032_PLATFORM_MODULE) ifeq ($(INSTALL_DEBUG_TOOLS),y) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) diff --git a/platform/broadcom/platform-modules-cel.mk b/platform/broadcom/platform-modules-cel.mk index de021df7e4db..947ab2efba17 100644 --- a/platform/broadcom/platform-modules-cel.mk +++ b/platform/broadcom/platform-modules-cel.mk @@ -4,11 +4,13 @@ CEL_DX010_PLATFORM_MODULE_VERSION = 0.9 CEL_HALIBURTON_PLATFORM_MODULE_VERSION = 0.9 CEL_SEASTONE2_PLATFORM_MODULE_VERSION = 0.9 CEL_SILVERSTONE_PLATFORM_MODULE_VERSION = 0.9 +CEL_BLACKSTONE_PLATFORM_MODULE_VERSION = 0.9 export CEL_DX010_PLATFORM_MODULE_VERSION export CEL_HALIBURTON_PLATFORM_MODULE_VERSION export CEL_SEASTONE2_PLATFORM_MODULE_VERSION export CEL_SILVERSTONE_PLATFORM_MODULE_VERSION +export CEL_BLACKSTONE_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 @@ -28,3 +30,6 @@ 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_BLACKSTONE_PLATFORM_MODULE = platform-modules-blackstone_$(CEL_BLACKSTONE_PLATFORM_MODULE_VERSION)_amd64.deb +$(CEL_BLACKSTONE_PLATFORM_MODULE)_PLATFORM = x86_64-cel_blackstone-r0 +$(eval $(call add_extra_package,$(CEL_DX010_PLATFORM_MODULE),$(CEL_BLACKSTONE_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/cfg/blackstone-modules.conf b/platform/broadcom/sonic-platform-modules-cel/blackstone/cfg/blackstone-modules.conf new file mode 100644 index 000000000000..52f5c600ac8b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/cfg/blackstone-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-ismt +i2c-isch +i2c-dev +i2c-mux +i2c-smbus + +ipmi_devintf +ipmi_si + diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile new file mode 100644 index 000000000000..0bdf369fd721 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile @@ -0,0 +1 @@ +obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o switch_cpld.o diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/baseboard-lpc.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/baseboard-lpc.c new file mode 100644 index 000000000000..0d47b1f4c4f1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/baseboard-lpc.c @@ -0,0 +1,442 @@ +/* + * baseboard-lpc.c - The CPLD driver for the Base Board of Blackstone + * The driver implement sysfs to access CPLD register on the baseboard of Blackstone via LPC bus. + * Copyright (C) 2021 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 "sys_cpld" +/** + * CPLD register address for read and write. + */ +#define START_ADDR 0xA100 +#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 REGISTER_SIZE 0xA3 + +#define LED_OFF_STR "off" +#define LED_ON_STR "on" +#define LED_4HZ_STR "4hz" +#define LED_1HZ_STR "1hz" +#define LED_YELLOW_STR "yellow" +#define LED_GREEN_STR "green" +#define LED_BOTH_STR "both" + +/* 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(START_ADDR + off); + off++; + msleep(1); + goto begin; + } + status = count; + + mutex_unlock(&cpld_data->cpld_lock); + return status; +} +static BIN_ATTR_RO(dump, 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 ? LED_OFF_STR : data == 0x02 ? LED_4HZ_STR : data ==0x01 ? LED_1HZ_STR : LED_ON_STR); +} + +/** + * 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, LED_OFF_STR)){ + led_status = 0x03; + }else if(sysfs_streq(buf, LED_4HZ_STR)){ + led_status = 0x02; + }else if(sysfs_streq(buf, LED_1HZ_STR)){ + led_status = 0x01; + }else if(sysfs_streq(buf, LED_ON_STR)){ + 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 ? LED_OFF_STR : data == 0x02 ? LED_YELLOW_STR : data ==0x01 ? LED_GREEN_STR : LED_BOTH_STR); +} + +/** + * 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, LED_OFF_STR)){ + led_status = 0x03; + }else if(sysfs_streq(buf, LED_YELLOW_STR)){ + led_status = 0x02; + }else if(sysfs_streq(buf, LED_GREEN_STR)){ + led_status = 0x01; + }else if(sysfs_streq(buf, LED_BOTH_STR)){ + 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 = START_ADDR, + .end = START_ADDR + REGISTER_SIZE - 1, + .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 Blackstone CPLD baseboard driver"); +MODULE_VERSION("0.2.0"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c new file mode 100644 index 000000000000..be6b4170fd73 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c @@ -0,0 +1,943 @@ +/* + * cls-fpga.c - PCI device driver for Blackstone FPGA. + * + * Copyright (C) 2021 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 "i2c-ocores.h" +#include "xcvr-cls.h" + +#define MOD_VERSION "1.0.0" +#define DRV_NAME "cls-fpga" + +#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 +/* Reserve some bus numbers for CPU or FPGA */ +#define I2C_BUS_OFS 14 + +/* 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 + +#define SILVERSTONE2_BSP 1 + +/* 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; +}; + +/* fpga_priv - fpga private data */ +struct fpga_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; +}; + +/* Switchboard FPGA attributes */ +static int fpga_pci_probe(struct pci_dev *pdev); +static void fpga_pci_remove(void); + + +/* MISC */ +#define FPGA_VERSION 0x0000 +#define FPGA_VERSION_MJ_MSK 0xff00 +#define FPGA_VERSION_MN_MSK 0x00ff +#define FPGA_SCRATCH 0x0004 +#define FPGA_PORT_XCVR_READY 0x000c + +/* FPGA FRONT PANEL PORT MGMT */ +#define SFF_PORT_CTRL_BASE 0x4000 + +#define PORT_XCVR_REGISTER_SIZE 0x1000 + + + +static struct class* fpgafwclass = NULL; // < The device-driver class struct pointer +static struct kobject *swfpga = NULL; + + + +#define FPGA_PCI_DEVICE_ID 0x7021 +#define FPGA_PCI_BAR_NUM 0 + +#define CLASS_NAME "cls_fpga" + + +struct fpga_device { + /* data mmio region */ + void __iomem *data_base_addr; + resource_size_t data_mmio_start; + resource_size_t data_mmio_len; +}; + +static struct fpga_device fpga_dev = { + .data_base_addr = 0, + .data_mmio_start = 0, + .data_mmio_len = 0, +}; + +struct silverstone_fpga_data { + struct mutex fpga_lock; // For FPGA internal lock + void __iomem * fpga_read_addr; +}; + +struct silverstone_fpga_data *fpga_data; + + + +/** + * Show the value of the register set by 'set_fpga_reg_address' + * If the address is not set by 'set_fpga_reg_address' first, + * The version register is selected by default. + * @param buf register value in hextring + * @return number of bytes read, or an error code + */ +static ssize_t get_fpga_reg_value(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + // read data from the address + uint32_t data; + data = ioread32(fpga_data->fpga_read_addr); + return sprintf(buf, "0x%8.8x\n", data); +} +/** + * Store the register address + * @param buf address wanted to be read value of + * @return number of bytes stored, or an error code + */ +static ssize_t set_fpga_reg_address(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint32_t addr; + char *last; + + addr = (uint32_t)strtoul(buf, &last, 16); + if (addr == 0 && buf == last) { + return -EINVAL; + } + fpga_data->fpga_read_addr = fpga_dev.data_base_addr + addr; + return count; +} +/** + * Show value of fpga scratch register + * @param buf register value in hexstring + * @return number of bytes read, or an error code + */ +static ssize_t get_fpga_scratch(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + return sprintf(buf, "0x%8.8x\n", ioread32(fpga_dev.data_base_addr + FPGA_SCRATCH) & 0xffffffff); +} +/** + * Store value of fpga scratch register + * @param buf scratch register value passing from user space + * @return number of bytes stored, or an error code + */ +static ssize_t set_fpga_scratch(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint32_t data; + char *last; + data = (uint32_t)strtoul(buf, &last, 16); + if (data == 0 && buf == last) { + return -EINVAL; + } + iowrite32(data, fpga_dev.data_base_addr + FPGA_SCRATCH); + return count; +} +/** + * Store a value in a specific register address + * @param buf the value and address in format '0xhhhh 0xhhhhhhhh' + * @return number of bytes sent by user space, or an error code + */ +static ssize_t set_fpga_reg_value(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + // register are 4 bytes + uint32_t addr; + uint32_t value; + uint32_t mode = 8; + char *tok; + char clone[count+1]; + char *pclone = clone; + char *last; + + strcpy(clone, buf); + + mutex_lock(&fpga_data->fpga_lock); + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + addr = (uint32_t)strtoul(tok, &last, 16); + if (addr == 0 && tok == last) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + value = (uint32_t)strtoul(tok, &last, 16); + if (value == 0 && tok == last) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + tok = strsep((char**)&pclone, " "); + if (tok == NULL) { + mode = 32; + } else { + mode = (uint32_t)strtoul(tok, &last, 10); + if (mode == 0 && tok == last) { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + } + if (mode == 32) { + iowrite32(value, fpga_dev.data_base_addr + addr); + } else if (mode == 8) { + iowrite8(value, fpga_dev.data_base_addr + addr); + } else { + mutex_unlock(&fpga_data->fpga_lock); + return -EINVAL; + } + mutex_unlock(&fpga_data->fpga_lock); + return count; +} + +/** + * Read all FPGA XCVR register in binary mode. + * @param buf Raw transceivers port startus and control register values + * @return number of bytes read, or an error code + */ +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; + u8 read_reg; + + if ( off + count > PORT_XCVR_REGISTER_SIZE ) { + return -EINVAL; + } + mutex_lock(&fpga_data->fpga_lock); + while (i < count) { + read_reg = ioread8(fpga_dev.data_base_addr + SFF_PORT_CTRL_BASE + off + i); + buf[i++] = read_reg; + } + status = count; + mutex_unlock(&fpga_data->fpga_lock); + return status; +} + +/** + * Show FPGA port XCVR ready status + * @param buf 1 if the functin is ready, 0 if not. + * @return number of bytes read, or an error code + */ +static ssize_t ready_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + u32 data; + unsigned int REGISTER = FPGA_PORT_XCVR_READY; + + mutex_lock(&fpga_data->fpga_lock); + data = ioread32(fpga_dev.data_base_addr + REGISTER); + mutex_unlock(&fpga_data->fpga_lock); + return sprintf(buf, "%d\n", (data >> 0) & 1U); +} + + + +static DEVICE_ATTR( getreg, 0600, get_fpga_reg_value, set_fpga_reg_address); +static DEVICE_ATTR( scratch, 0600, get_fpga_scratch, set_fpga_scratch); +static DEVICE_ATTR( setreg, 0200, NULL , set_fpga_reg_value); +static DEVICE_ATTR_RO(ready); +static BIN_ATTR_RO( dump, PORT_XCVR_REGISTER_SIZE); + +static struct bin_attribute *fpga_bin_attrs[] = { + &bin_attr_dump, + NULL, +}; + +static struct attribute *fpga_attrs[] = { + &dev_attr_getreg.attr, + &dev_attr_scratch.attr, + &dev_attr_setreg.attr, + &dev_attr_ready.attr, + NULL, +}; + +static struct attribute_group fpga_attr_grp = { + .attrs = fpga_attrs, + .bin_attrs = fpga_bin_attrs, +}; + + + +/* move this on top of platform_probe() */ +static int fpga_pci_probe(struct pci_dev *pdev) +{ + int err; + struct device *dev = &pdev->dev; + uint32_t fpga_version; + + /* Skip the reqions request and mmap the resource */ + /* bar0: data mmio region */ + fpga_dev.data_mmio_start = pci_resource_start(pdev, FPGA_PCI_BAR_NUM); + fpga_dev.data_mmio_len = pci_resource_len(pdev, FPGA_PCI_BAR_NUM); + fpga_dev.data_base_addr = ioremap_nocache(fpga_dev.data_mmio_start, + fpga_dev.data_mmio_len); + if (!fpga_dev.data_base_addr) { + dev_err(dev, "cannot iomap region of size %lu\n", + (unsigned long)fpga_dev.data_mmio_len); + err = PTR_ERR(fpga_dev.data_base_addr); + goto err_exit; + } + dev_info(dev, "data_mmio iomap base = 0x%lx \n", + (unsigned long)fpga_dev.data_base_addr); + dev_info(dev, "data_mmio_start = 0x%lx data_mmio_len = %lu\n", + (unsigned long)fpga_dev.data_mmio_start, + (unsigned long)fpga_dev.data_mmio_len); + + printk(KERN_INFO "FPGA PCIe driver probe OK.\n"); + printk(KERN_INFO "FPGA ioremap registers of size %lu\n", + (unsigned long)fpga_dev.data_mmio_len); + printk(KERN_INFO "FPGA Virtual BAR %d at %8.8lx - %8.8lx\n", + FPGA_PCI_BAR_NUM, + (unsigned long)fpga_dev.data_base_addr, + (unsigned long)(fpga_dev.data_base_addr + fpga_dev.data_mmio_len)); + printk(KERN_INFO ""); + fpga_version = ioread32(fpga_dev.data_base_addr); + printk(KERN_INFO "FPGA VERSION : %8.8x\n", fpga_version); + + fpgafwclass = class_create(THIS_MODULE, CLASS_NAME); + if (IS_ERR(fpgafwclass)) { + printk(KERN_ALERT "Failed to register device class\n"); + err = PTR_ERR(fpgafwclass); + goto mem_unmap; + } + return 0; + +mem_unmap: + iounmap(fpga_dev.data_base_addr); +err_exit: + return err; +} + +static void fpga_pci_remove(void) +{ + iounmap(fpga_dev.data_base_addr); +// class_unregister(fpgafwclass); + class_destroy(fpgafwclass); +}; +/* end FPGA */ + +/* 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"); + +static int bus_clock_master_6 = 100; +module_param(bus_clock_master_6, int, 0660); +MODULE_PARM_DESC(bus_clock_master_6, + "I2C master 6 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_7 = 100; +module_param(bus_clock_master_7, int, 0660); +MODULE_PARM_DESC(bus_clock_master_7, + "I2C master 7 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_8 = 100; +module_param(bus_clock_master_8, int, 0660); +MODULE_PARM_DESC(bus_clock_master_8, + "I2C master 8 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_9 = 100; +module_param(bus_clock_master_9, int, 0660); +MODULE_PARM_DESC(bus_clock_master_9, + "I2C master 9 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_10 = 100; +module_param(bus_clock_master_10, int, 0660); +MODULE_PARM_DESC(bus_clock_master_10, + "I2C master 10 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_11 = 100; +module_param(bus_clock_master_11, int, 0660); +MODULE_PARM_DESC(bus_clock_master_11, + "I2C master 11 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_12 = 100; +module_param(bus_clock_master_12, int, 0660); +MODULE_PARM_DESC(bus_clock_master_12, + "I2C master 12 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_13 = 100; +module_param(bus_clock_master_13, int, 0660); +MODULE_PARM_DESC(bus_clock_master_13, + "I2C master 13 bus speed in KHz 50/80/100/200/400"); + +/* RESOURCE SEPERATES BY FUNCTION */ +/* Resource IOMEM for i2c bus 1 for SFP1*/ +static struct resource cls_i2c_res_1[] = { + { + .start = 0x800, .end = 0x81F, + .flags = IORESOURCE_MEM,}, +}; +/* Resource IOMEM for i2c bus 2 for SFP2*/ +static struct resource cls_i2c_res_2[] = { + { + .start = 0x820, .end = 0x83F, + .flags = IORESOURCE_MEM,}, +}; +/* Resource IOMEM for i2c bus 3 for PCA9548*/ +static struct resource cls_i2c_res_3[] = { + { + .start = 0x840, .end = 0x85F, + .flags = IORESOURCE_MEM,}, +}; +/* Resource IOMEM for i2c bus 4 for MISC CPLD1/CPLD2*/ +static struct resource cls_i2c_res_4[] = { + { + .start = 0x860, .end = 0x87F, + .flags = IORESOURCE_MEM,}, +}; +/* Resource IOMEM for i2c bus 5 for SYS CPLD*/ +static struct resource cls_i2c_res_5[] = { + { + .start = 0x880, .end = 0x89F, + .flags = IORESOURCE_MEM,}, +}; +/* Resource IOMEM for i2c bus 6 for PCA9548*/ +static struct resource cls_i2c_res_6[] = { + { + .start = 0x8A0, .end = 0x8BF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 7 for PSU*/ +static struct resource cls_i2c_res_7[] = { + { + .start = 0x8C0, .end = 0x8DF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 8 for FAN*/ +static struct resource cls_i2c_res_8[] = { + { + .start = 0x8E0, .end = 0x8FF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 9 for PCA9548*/ +static struct resource cls_i2c_res_9[] = { + { + .start = 0x900, .end = 0x91F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 10 for LM75B*/ +static struct resource cls_i2c_res_10[] = { + { + .start = 0x920, .end = 0x93F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 11 for si5395B*/ +static struct resource cls_i2c_res_11[] = { + { + .start = 0x940, .end = 0x95F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 12 for EEPROM, PCIE CLK BUF*/ +static struct resource cls_i2c_res_12[] = { + { + .start = 0x960, .end = 0x97F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 13 for VDDCORE_12V_DCDC*/ +static struct resource cls_i2c_res_13[] = { + { + .start = 0x980, .end = 0x99F, + .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,}, +}; + +/* if have i2c-mux pca9548, .num_devices=ARRAY_SIZE(i2c_info_X); .devices = i2c_info_X. + * if not, .num_devices = 0; .devices = NULL + * + * Notes: Some FPGA_I2C_Master buses are shared with BMC, + * these buses need to be uninitialized because it interfere the BMC activity + */ +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 = 0, + .devices = NULL, + }, + }, + { + .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 = 6, + .res = cls_i2c_res_6, + .num_res = ARRAY_SIZE(cls_i2c_res_6), + .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 = 11, + .res = cls_i2c_res_11, + .num_res = ARRAY_SIZE(cls_i2c_res_11), + .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[] = { + {"QSFPDD1", 1, QSFP}, + {"QSFPDD2", 2, QSFP}, + {"QSFPDD3", 3, QSFP}, + {"QSFPDD4", 4, QSFP}, + {"QSFPDD5", 5, QSFP}, + {"QSFPDD6", 6, QSFP}, + {"QSFPDD7", 7, QSFP}, + {"QSFPDD8", 8, QSFP}, + {"QSFPDD9", 9, QSFP}, + {"QSFPDD10", 10, QSFP}, + {"QSFPDD11", 11, QSFP}, + {"QSFPDD12", 12, QSFP}, + {"QSFPDD13", 13, QSFP}, + {"QSFPDD14", 14, QSFP}, + {"QSFPDD15", 15, QSFP}, + {"QSFPDD16", 16, QSFP}, + {"QSFPDD17", 17, QSFP}, + {"QSFPDD18", 18, QSFP}, + {"QSFPDD19", 19, QSFP}, + {"QSFPDD20", 20, QSFP}, + {"QSFPDD21", 21, QSFP}, + {"QSFPDD22", 22, QSFP}, + {"QSFPDD23", 23, QSFP}, + {"QSFPDD24", 24, QSFP}, + {"QSFPDD25", 25, QSFP}, + {"QSFPDD26", 26, QSFP}, + {"QSFPDD27", 27, QSFP}, + {"QSFPDD28", 28, QSFP}, + {"QSFPDD29", 29, QSFP}, + {"QSFPDD30", 30, QSFP}, + {"QSFPDD31", 31, QSFP}, + {"QSFPDD32", 32, QSFP}, + {"SFP+1", 33, SFP}, + {"SFP+2", 34, SFP}, + /* 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) +{ + + int ret = 0; + struct fpga_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; + } + + if (dev){ + err = fpga_pci_probe(dev); +// pci_dev_put(dev); + } else { + ret = -ENODEV; + goto err_exit; + } + if(0 != err){ + dev_err(&dev->dev, "Failed to do fpga pci probe\n"); + goto err_disable_device; + } + + fpga_data = devm_kzalloc(&dev->dev, sizeof(struct silverstone_fpga_data), + GFP_KERNEL); + if (!fpga_data){ + ret = -ENOMEM; + goto err_disable_device; + } + + /* 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 fpga_priv), GFP_KERNEL); + if (!priv){ + err = -ENOMEM; + goto err_disable_device; + } + + pci_set_drvdata(dev, priv); + + swfpga = kobject_create_and_add("FPGA4SW", &dev->dev.kobj); + if (!swfpga) { + ret = -ENOMEM; + goto err_disable_device; + } + + ret = sysfs_create_group(swfpga, &fpga_attr_grp); + if (ret != 0) { + printk(KERN_ERR "Cannot create FPGA sysfs attributes\n"); + goto err_remove_fpga; + } + + 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_remove_grp_fpga; + } + + 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; + + printk("start %x ... end %x\n",i2c_bus_configs[i].res[0].start,i2c_bus_configs[i].res[0].end); + + switch (i2c_bus_configs[i].id) { + 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; + case 6: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_6; + break; + case 7: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_7; + break; + case 8: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_8; + break; + case 9: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_9; + break; + case 10: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_10; + break; + case 11: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_11; + break; + case 12: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_12; + break; + case 13: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_13; + 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, "ocores-i2c", //"i2c-ocores","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; + + // Set default read address to VERSION + fpga_data->fpga_read_addr = fpga_dev.data_base_addr + FPGA_VERSION; + mutex_init(&fpga_data->fpga_lock); + + 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_remove_grp_fpga: + sysfs_remove_group(swfpga, &fpga_attr_grp); +err_remove_fpga: + kobject_put(swfpga); + fpga_pci_remove(); +err_disable_device: + pci_disable_device(dev); +err_exit: + return err; +} + +static void cls_fpga_remove(struct pci_dev *dev) +{ + int i; + struct fpga_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); + sysfs_remove_group(swfpga, &fpga_attr_grp); + kobject_put(swfpga); + fpga_pci_remove(); + pci_disable_device(dev); + + return; +}; + +static const struct pci_device_id pci_fpga[] = { + { PCI_VDEVICE(XILINX, FPGA_PCIE_DEVICE_ID) }, + {0, } +}; + +MODULE_DEVICE_TABLE(pci, pci_fpga); + +static struct pci_driver cls_fpga_pci_driver = { + .name = DRV_NAME, + .id_table = pci_fpga, + .probe = cls_fpga_probe, + .remove = cls_fpga_remove, +}; + +module_pci_driver(cls_fpga_pci_driver); + +MODULE_AUTHOR("CLS"); +MODULE_DESCRIPTION("Celestica Blackstone fpga driver"); +MODULE_VERSION(MOD_VERSION); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-i2c-ocores.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-i2c-ocores.c new file mode 100644 index 000000000000..6620cf2945d8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-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/blackstone/modules/i2c-ocores.h b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/i2c-ocores.h new file mode 100644 index 000000000000..25926b385255 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/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/blackstone/modules/mc24lc64t.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/mc24lc64t.c new file mode 100644 index 000000000000..7a621e7ac9a2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/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"); diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c new file mode 100644 index 000000000000..3a1b7669547f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c @@ -0,0 +1,428 @@ +/* + * switch_cpld.c - i2c driver for Blackstone DP switchboard CPLD1/CPLD2 + * provides sysfs interfaces to access CPLD register and control port LEDs + * + * Author: Budsakol Sirirattanasakul + * + * Copyright (C) 2021 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 Blackstone Switchboard CPLD driver"); +MODULE_VERSION("1.0.0"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/xcvr-cls.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/xcvr-cls.c new file mode 100644 index 000000000000..bc0da613ec8d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/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/blackstone/modules/xcvr-cls.h b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/xcvr-cls.h new file mode 100644 index 000000000000..7659a7c0e9cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/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/blackstone/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py new file mode 100755 index 000000000000..38193c255f31 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py @@ -0,0 +1,175 @@ +#!/usr/bin/python +# +# Blackstone platform sensors. This script get the sensor data from BMC +# using ipmitool and display them in lm-sensor alike format. +# +# The following data is support: +# 1. Temperature sensors +# 2. PSUs +# 3. Fan trays + +import sys +import logging +import subprocess + +IPMI_SDR_CMD = "ipmitool sdr elist" +MAX_NUM_FANS = 7 +MAX_NUM_PSUS = 2 + + +def ipmi_sensor_dump(cmd): + ''' Execute ipmitool command return dump output + exit if any error occur. + ''' + sensor_dump = '' + try: + sensor_dump = subprocess.check_output(cmd, shell=True) + except subprocess.CalledProcessError as e: + logging.error('Error! Failed to execute: {}'.format(cmd)) + sys.exit(1) + return sensor_dump + +def get_reading_by_name(sensor_name, sdr_elist_dump): + ''' + Search for the match sensor name, return sensor + reading value and unit, return object epmtry string + if search not match. + + The output of sensor dump: + TEMP_FAN_U52 | 00h | ok | 7.1 | 31 degrees C + TEMP_FAN_U17 | 01h | ok | 7.1 | 27 degrees C + TEMP_SW_U52 | 02h | ok | 7.1 | 30 degrees C + Fan2_Status | 07h | ok | 29.2 | Present + Fan2_Front | 0Eh | ok | 29.2 | 12000 RPM + Fan2_Rear | 46h | ok | 29.2 | 14700 RPM + PSU2_Status | 39h | ok | 10.2 | Presence detected + PSU2_Fan | 3Dh | ok | 10.2 | 16000 RPM + PSU2_VIn | 3Ah | ok | 10.2 | 234.30 Volts + PSU2_CIn | 3Bh | ok | 10.2 | 0.80 Amps + ''' + found = '' + + for line in sdr_elist_dump.split("\n"): + if sensor_name in line: + found = line.strip() + break + + if not found: + logging.error('Cannot find sensor name:' + sensor_name) + + else: + try: + found = found.split('|')[4] + except IndexError: + logging.error('Cannot get sensor data of:' + sensor_name) + + logging.basicConfig(level=logging.DEBUG) + return found + + +def read_temperature_sensors(ipmi_sdr_elist): + + sensor_list = [ + ('TEMP_FAN_U52', 'Fan Tray Middle Temp'), + ('TEMP_FAN_U17', 'Fan Tray Right Temp'), + ('TEMP_SW_U1_1', 'Switchboard Left Inlet Temp'), + ('TEMP_SW_U1_2', 'Switchboard Right Inlet Temp'), + ('TEMP_SW_U1_3', 'Switchboard Right Inlet Temp'), + ('TEMP_BB_U3', 'Baseboard Temp'), + ('TEMP_CPU', 'CPU Internal Temp'), + ('TEMP_SW_Internal', 'ASIC Internal Temp'), + ('SW_U104_Temp1', 'IR3595 Chip Left Temp'), + ('SW_U121_Temp1', 'IR3595 Chip Right Temp'), + ('SW_U128_Temp1', 'IR3584 Chip Temp'), + ('SW_U130_Temp1', 'IR3584 Chip Temp'), + ] + + output = '' + sensor_format = '{0:{width}}{1}\n' + # Find max length of sensor calling name + max_name_width = max(len(sensor[1]) for sensor in sensor_list) + + output += "Temperature Sensors\n" + output += "Adapter: IPMI adapter\n" + for sensor in sensor_list: + reading = get_reading_by_name(sensor[0],ipmi_sdr_elist) + output += sensor_format.format('{}:'.format(sensor[1]), + reading, + width=str(max_name_width+1)) + output += '\n' + return output + + +def read_fan_sensors(num_fans, ipmi_sdr_elist): + + sensor_list = [ + ('Fan{}_Status', 'Status'), + ('Fan{}_Front', 'Fan {} front'), + ('Fan{}_Rear', 'Fan {} rear'), + ] + + output = '' + sensor_format = '{0:{width}}{1}\n' + # Find max length of sensor calling name + max_name_width = max(len(sensor[1]) for sensor in sensor_list) + + output += "Fan Trays\n" + output += "Adapter: IPMI adapter\n" + for fan_num in range(1, num_fans+1): + for sensor in sensor_list: + ipmi_sensor_name = sensor[0].format(fan_num) + display_sensor_name = sensor[1].format(fan_num) + reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist) + output += sensor_format.format('{}:'.format(display_sensor_name), + reading, + width=str(max_name_width+1)) + output += '\n' + return output + + +def read_psu_sensors(num_psus, ipmi_sdr_elist): + + sensor_list = [ + ('PSU{}_Status', 'PSU {} Status'), + ('PSU{}_Fan', 'PSU {} Fan'), + ('PSU{}_VIn', 'PSU {} Input Voltag'), + ('PSU{}_CIn', 'PSU {} Input Current'), + ('PSU{}_PIn', 'PSU {} Input Power'), + ('PSU{}_Temp1', 'PSU {} Temp1'), + ('PSU{}_Temp2', 'PSU {} Temp2'), + ('PSU{}_VOut', 'PSU {} Output Voltag'), + ('PSU{}_COut', 'PSU {} Output Current'), + ('PSU{}_POut', 'PSU {} Output Power'), + ] + + output = '' + sensor_format = '{0:{width}}{1}\n' + # Find max length of sensor calling name + max_name_width = max(len(sensor[1]) for sensor in sensor_list) + + output += "PSU\n" + output += "Adapter: IPMI adapter\n" + for psu_num in range(1, num_psus+1): + for sensor in sensor_list: + ipmi_sensor_name = sensor[0].format(psu_num) + display_sensor_name = sensor[1].format(psu_num) + reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist) + output += sensor_format.format('{}:'.format(display_sensor_name), + reading, + width=str(max_name_width+1)) + output += '\n' + return output + + +def main(): + output_string = '' + + ipmi_sdr_elist = ipmi_sensor_dump(IPMI_SDR_CMD) + output_string += read_temperature_sensors(ipmi_sdr_elist) + output_string += read_psu_sensors(MAX_NUM_PSUS, ipmi_sdr_elist) + output_string += read_fan_sensors(MAX_NUM_FANS, ipmi_sdr_elist) + print(output_string) + + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/sensors b/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/sensors new file mode 100755 index 000000000000..405d92c2b3cc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/sensors @@ -0,0 +1,11 @@ +#!/bin/bash + +DOCKER_EXEC_FLAGS="i" + +# Determine whether stdout is on a terminal +if [ -t 1 ] ; then + DOCKER_EXEC_FLAGS+="t" +fi + +docker exec -$DOCKER_EXEC_FLAGS pmon sensors "$@" +docker exec -$DOCKER_EXEC_FLAGS pmon platform_sensors.py "$@" diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py b/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py new file mode 100644 index 000000000000..30d1e6445d81 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py @@ -0,0 +1,35 @@ +from setuptools import setup + +DEVICE_NAME = 'celestica' +HW_SKU = 'x86_64-cel_blackstone-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='Larry Ming', + maintainer_email='laming@celestica.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../device/sonic_platform'}, + 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', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/systemd/platform-modules-blackstone.service b/platform/broadcom/sonic-platform-modules-cel/blackstone/systemd/platform-modules-blackstone.service new file mode 100644 index 000000000000..4935fc4cb310 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/systemd/platform-modules-blackstone.service @@ -0,0 +1,14 @@ +[Unit] +Description=Celestica Blackstone platform modules +After=local-fs.target +Before=pmon.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/platform-modules-blackstone start +ExecStop=-/etc/init.d/platform-modules-blackstone stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target + diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/control b/platform/broadcom/sonic-platform-modules-cel/debian/control index a41f92ab54e9..3fa8387eb40c 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/control +++ b/platform/broadcom/sonic-platform-modules-cel/debian/control @@ -25,3 +25,8 @@ Package: platform-modules-silverstone Architecture: amd64 Depends: linux-image-4.19.0-12-2-amd64-unsigned Description: kernel modules for platform devices such as led, sfp. + +Package: platform-modules-blackstone +Architecture: amd64 +Depends: linux-image-4.19.0-12-2-amd64-unsigned +Description: kernel modules for platform devices such as fan, led, sfp. diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/rules b/platform/broadcom/sonic-platform-modules-cel/debian/rules index efb5aa47b437..b792a33cc7c4 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 seastone2 +MODULE_DIRS:= dx010 haliburton silverstone seastone2 blackstone %: dh $@ From 09dd00e3349372f3f5b525a8a6facf789457cc1f Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 14 Sep 2021 12:53:27 +0700 Subject: [PATCH 02/32] [device/celestica]: add blackstone device cel_blackstone-r0 --- .../Blackstone/port_config.ini | 33 + .../x86_64-cel_blackstone-r0/default_sku | 1 + .../x86_64-cel_blackstone-r0/installer.conf | 1 + .../platform_components.json | 13 + .../plugins/eeprom.py | 22 + .../plugins/helper.py | 70 + .../plugins/platform.py | 23 + .../plugins/psuutil.py | 100 + .../plugins/sfputil.py | 235 ++ .../pmon_daemon_control.json | 4 + .../x86_64-cel_blackstone-r0/sensors.conf | 1 + .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 352 +++ .../sonic_platform/component.py | 188 ++ .../sonic_platform/eeprom.py | 141 ++ .../sonic_platform/event.py | 52 + .../sonic_platform/fan.py | 383 +++ .../sonic_platform/fan_drawer.py | 108 + .../sonic_platform/helper.py | 133 + .../sonic_platform/platform.py | 21 + .../sonic_platform/psu.py | 391 +++ .../sonic_platform/sfp.py | 2204 +++++++++++++++++ .../sonic_platform/thermal.py | 264 ++ .../sonic_platform/thermal_actions.py | 78 + .../sonic_platform/thermal_conditions.py | 77 + .../sonic_platform/thermal_infos.py | 165 ++ .../sonic_platform/thermal_manager.py | 46 + .../sonic_platform/watchdog.py | 194 ++ 28 files changed, 5302 insertions(+) create mode 100644 device/celestica/x86_64-cel_blackstone-r0/Blackstone/port_config.ini create mode 100644 device/celestica/x86_64-cel_blackstone-r0/default_sku create mode 100644 device/celestica/x86_64-cel_blackstone-r0/installer.conf create mode 100644 device/celestica/x86_64-cel_blackstone-r0/platform_components.json create mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/eeprom.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sensors.conf create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/__init__.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/component.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/event.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan_drawer.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/helper.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/platform.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/psu.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/sfp.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_actions.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_conditions.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_infos.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_manager.py create mode 100644 device/celestica/x86_64-cel_blackstone-r0/sonic_platform/watchdog.py diff --git a/device/celestica/x86_64-cel_blackstone-r0/Blackstone/port_config.ini b/device/celestica/x86_64-cel_blackstone-r0/Blackstone/port_config.ini new file mode 100644 index 000000000000..650c22281c6f --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/Blackstone/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed +Ethernet0 1,2,3,4,5,6,7,8 OSFP1 1 400000 +Ethernet8 9,10,11,12,13,14,15,16 OSFP2 2 400000 +Ethernet16 17,18,19,20,21,22,23,24 OSFP3 3 400000 +Ethernet24 25,26,27,28,29,30,31,32 OSFP4 4 400000 +Ethernet32 33,34,35,36,37,38,39,40 OSFP5 5 400000 +Ethernet40 41,42,43,44,45,46,47,48 OSFP6 6 400000 +Ethernet48 49,50,51,52,53,54,55,56 OSFP7 7 400000 +Ethernet56 57,58,59,60,61,62,63,64 OSFP8 8 400000 +Ethernet64 65,66,67,68,69,70,71,72 OSFP9 9 400000 +Ethernet72 73,74,75,76,77,78,79,80 OSFP10 10 400000 +Ethernet80 81,82,83,84,85,86,87,88 OSFP11 11 400000 +Ethernet88 89,90,91,92,93,94,95,96 OSFP12 12 400000 +Ethernet96 97,98,99,100,101,102,103,104 OSFP13 13 400000 +Ethernet104 105,106,107,108,109,110,111,112 OSFP14 14 400000 +Ethernet112 113,114,115,116,117,118,119,120 OSFP15 15 400000 +Ethernet120 121,122,123,124,125,126,127,128 OSFP16 16 400000 +Ethernet128 129,130,131,132,133,134,135,136 OSFP17 17 400000 +Ethernet136 137,138,139,140,141,142,143,144 OSFP18 18 400000 +Ethernet144 145,146,147,148,149,150,151,152 OSFP19 19 400000 +Ethernet152 153,154,155,156,157,158,159,160 OSFP20 20 400000 +Ethernet160 161,162,163,164,165,166,167,168 OSFP21 21 400000 +Ethernet168 169,170,171,172,173,174,175,176 OSFP22 22 400000 +Ethernet176 177,178,179,180,181,182,183,184 OSFP23 23 400000 +Ethernet184 185,186,187,188,189,190,191,192 OSFP24 24 400000 +Ethernet192 193,194,195,196,197,198,199,200 OSFP25 25 400000 +Ethernet200 201,202,203,204,205,206,207,208 OSFP26 26 400000 +Ethernet208 209,210,211,212,213,214,215,216 OSFP27 27 400000 +Ethernet216 217,218,219,220,221,222,223,224 OSFP28 28 400000 +Ethernet224 225,226,227,228,229,230,231,232 OSFP29 29 400000 +Ethernet232 233,234,235,236,237,238,239,240 OSFP30 30 400000 +Ethernet240 241,242,243,244,245,246,247,248 OSFP31 31 400000 +Ethernet248 249,250,251,252,253,254,255,256 OSFP32 32 400000 diff --git a/device/celestica/x86_64-cel_blackstone-r0/default_sku b/device/celestica/x86_64-cel_blackstone-r0/default_sku new file mode 100644 index 000000000000..87635c70e832 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/default_sku @@ -0,0 +1 @@ +Blackstone t1 diff --git a/device/celestica/x86_64-cel_blackstone-r0/installer.conf b/device/celestica/x86_64-cel_blackstone-r0/installer.conf new file mode 100644 index 000000000000..5e62742c11bf --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/installer.conf @@ -0,0 +1 @@ +CONSOLE_SPEED=115200 diff --git a/device/celestica/x86_64-cel_blackstone-r0/platform_components.json b/device/celestica/x86_64-cel_blackstone-r0/platform_components.json new file mode 100644 index 000000000000..374d904a92f6 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/platform_components.json @@ -0,0 +1,13 @@ +{ + "chassis": { + "Blackstone": { + "component": { + "BIOS": { }, + "CPLD1": { }, + "CPLD2": { }, + "CPLD3": { }, + "CPLD4": { } + } + } + } +} diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/eeprom.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/eeprom.py new file mode 100644 index 000000000000..736fc7d3143e --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/eeprom.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Blackstone +# +# 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 as 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_blackstone-r0/plugins/helper.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py new file mode 100644 index 000000000000..9377fa85b69f --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py @@ -0,0 +1,70 @@ +#!/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 diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py new file mode 100644 index 000000000000..a632de87e742 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/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_blackstone-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py new file mode 100644 index 000000000000..bca8076c4512 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Blackstone +# +# Platform and model specific psu subclass, inherits from the base class, +# and provides the followings: +# - psuutil numpsus +# - psuutil status +############################################################################# + +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") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + def __init__(self): + self.ipmi_raw = "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, universal_newlines=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 diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py new file mode 100644 index 000000000000..08a66786d680 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py @@ -0,0 +1,235 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica Blackstone +# +# Platform and model specific sfp subclass, inherits from the base class, +# and provides the followings: +# - sfputil show presence +############################################################################# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as 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) + +try: + import time + from sonic_sfp.sfputilbase import SfpUtilBase +except ImportError as e: + raise ImportError("%s - required module not found" % str(e)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 1 + PORT_END = 33 + QSFP_PORT_START = 1 + QSFP_PORT_END = 32 + + EEPROM_OFFSET = 1 + PORT_INFO_PATH = '/sys/devices/platform/cls-xcvr' + + _port_name = "" + _port_to_eeprom_mapping = {} + _port_to_i2cbus_mapping = { + 1: 17, + 2: 18, + 3: 15, + 4: 16, + 5: 21, + 6: 20, + 7: 38, + 8: 19, + 9: 35, + 10: 34, + 11: 37, + 12: 33, + 13: 32, + 14: 36, + 15: 22, + 16: 31, + 17: 24, + 18: 30, + 19: 27, + 20: 23, + 21: 28, + 22: 25, + 23: 12, + 24: 29, + 25: 26, + 26: 13, + 27: 7, + 28: 14, + 29: 9, + 30: 11, + 31: 10, + 32: 8, + 33: 1, + 34: 2 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return [] + + @property + def osfp_ports(self): + return list(range(self.QSFP_PORT_START, self.QSFP_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.QSFP_PORT_START + 1) + else: + self._port_name = "SFP" + str(port_num) + return self._port_name + + # def get_eeprom_dom_raw(self, port_num): + # if port_num in self.osfp_ports: + # # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw + # 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 x in range(self.PORT_START, self.PORT_END+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format(self.port_to_i2cbus_mapping[x]) + SfpUtilBase.__init__(self) + + def get_presence(self, port_num): + + # Check for invalid port_num + if port_num not in list(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" if port_num in self.osfp_ports else "sfp_modabs" + 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: + 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 + + # Read status + content = reg_file.readline().rstrip() + reg_value = int(content, 16) + # ModPrsL is active low + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid QSFP port_num + if port_num not in self.osfp_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 QSFP port_num + if port_num not in self.osfp_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: When the feature request. + """ + raise NotImplementedError diff --git a/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json b/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..82a04d00747b --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true, + "skip_psud": true +} diff --git a/device/celestica/x86_64-cel_blackstone-r0/sensors.conf b/device/celestica/x86_64-cel_blackstone-r0/sensors.conf new file mode 100644 index 000000000000..d3be47f4b0dd --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sensors.conf @@ -0,0 +1 @@ +# libsensors configuration file for Celestica Blackstone. diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/__init__.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..db1748e44d2c --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +from . import chassis +from . import platform diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..8a9ed17139df --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py @@ -0,0 +1,352 @@ +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +try: + import sys + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from sonic_py_common import device_info + from .event import SfpEvent + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 5 +NUM_PSU = 2 +NUM_THERMAL = 5 +NUM_SFP = 32 +NUM_COMPONENT = 5 +RESET_REGISTER = "0x103" +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" +HOST_CHK_CMD = "docker > /dev/null 2>&1" +STATUS_LED_PATH = "/sys/devices/platform/leds_dx010/leds/dx010:green:stat/brightness" + + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.sfp_module_initialized = False + self.__initialize_eeprom() + self.is_host = self._api_helper.is_host() + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + + def __initialize_sfp(self): + sfputil_helper = SfpUtilHelper() + port_config_file_path = device_info.get_path_to_port_config_file() + sfputil_helper.read_porttab_mappings(port_config_file_path, 0) + + from sonic_platform.sfp import Sfp + for index in range(0, NUM_SFP): + sfp = Sfp(index, sfputil_helper.logical[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_drawer import FanDrawer + for i in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(i) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + airflow = self.__get_air_flow() + for index in range(0, NUM_THERMAL): + thermal = Thermal(index, airflow) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + 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_air_flow(self): + air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format( + self._api_helper.platform) \ + if self.is_host else '/usr/share/sonic/platform/fan_airflow' + air_flow = self._api_helper.read_one_line_file(air_flow_path) + return air_flow or 'B2F' + + 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_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. + + REBOOT_CAUSE_POWER_LOSS = "Power Loss" + REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload: CPU" + REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload: ASIC" + REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload: Other" + REBOOT_CAUSE_INSUFFICIENT_FAN_SPEED = "Insufficient Fan Speed" + REBOOT_CAUSE_WATCHDOG = "Watchdog" + REBOOT_CAUSE_HARDWARE_OTHER = "Hardware - Other" + REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware" + + """ + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + hw_reboot_cause = self._api_helper.get_cpld_reg_value( + GETREG_PATH, RESET_REGISTER) + + prev_reboot_cause = { + '0x11': (self.REBOOT_CAUSE_POWER_LOSS, 'Power on reset'), + '0x22': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPLD_WD_RESET'), + '0x33': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by CPU'), + '0x44': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by reset button'), + '0x55': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, ''), + '0x66': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, ''), + '0x77': (self.REBOOT_CAUSE_WATCHDOG, '') + }.get(hw_reboot_cause, (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Unknown reason')) + + if sw_reboot_cause != 'Unknown' and hw_reboot_cause == '0x11': + prev_reboot_cause = ( + self.REBOOT_CAUSE_NON_HARDWARE, sw_reboot_cause) + + return prev_reboot_cause + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + Args: + timeout: Timeout in milliseconds (optional). If timeout == 0, + this method will block until a change is detected. + Returns: + (bool, dict): + - True if call successful, False if not; + - A nested dictionary where key is a device type, + value is a dictionary with key:value pairs in the format of + {'device_id':'device_event'}, + where device_id is the device ID for this device and + device_event, + status='1' represents device inserted, + status='0' represents device removed. + Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + indicates that fan 0 has been removed, fan 2 + has been inserted and sfp 11 has been removed. + """ + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + if sfp_event: + return True, {'sfp': sfp_event} + + return False, {'sfp': {}} + + ############################################################## + ######################## 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 + + def get_thermal_manager(self): + from .thermal_manager import ThermalManager + return ThermalManager + + ############################################################## + ###################### 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 Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the 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._eeprom.get_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 True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + 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 + """ + + set_status_str = { + self.STATUS_LED_COLOR_GREEN: '1', + self.STATUS_LED_COLOR_OFF: '0' + }.get(color, None) + + if not set_status_str: + return False + + return self._api_helper.write_txt_file(STATUS_LED_PATH, set_status_str) + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status = self._api_helper.read_txt_file(STATUS_LED_PATH) + status_str = { + '255': self.STATUS_LED_COLOR_GREEN, + '0': self.STATUS_LED_COLOR_OFF + }.get(status, None) + + return status_str diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/component.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/component.py new file mode 100644 index 000000000000..2db8418e18a9 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/component.py @@ -0,0 +1,188 @@ +############################################################################# +# Celestica +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import os.path +import shutil +import subprocess + +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") + +CPLD_ADDR_MAPPING = { + "CPLD1": "0x100", + "CPLD2": "0x200", + "CPLD3": "0x280", + "CPLD4": "0x300", + "CPLD5": "0x380" +} +GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_NAME_LIST = ["CPLD1", "CPLD2", "CPLD3", "CPLD4", "BIOS"] +COMPONENT_DES_LIST = ["Used for managing the CPU", + "Used for managing QSFP+ ports (1-10)", "Used for managing QSFP+ ports (11-20)", "Used for managing QSFP+ ports (22-32)", "Basic Input/Output System"] + + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index): + ComponentBase.__init__(self) + self.index = component_index + self._api_helper = APIHelper() + self.name = self.get_name() + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def get_register_value(self, register): + # Retrieves the cpld register value + cmd = "echo {1} > {0}; cat {0}".format(GETREG_PATH, register) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err is not '': + return None + return raw_data.strip() + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + for cpld_name in CPLD_ADDR_MAPPING: + try: + cpld_addr = CPLD_ADDR_MAPPING[cpld_name] + cpld_version_raw = self.get_register_value(cpld_addr) + cpld_version_str = "{}.{}".format(int(cpld_version_raw[2], 16), int( + cpld_version_raw[3], 16)) if cpld_version_raw is not None else 'None' + cpld_version[cpld_name] = cpld_version_str + except Exception as e: + cpld_version[cpld_name] = 'None' + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_NAME_LIST[self.index] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_DES_LIST[self.index] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + 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 + """ + if not os.path.isfile(image_path): + return False + + if "CPLD" in self.name: + img_name = os.path.basename(image_path) + root, ext = os.path.splitext(img_name) + ext = ".vme" if ext == "" else ext + new_image_path = os.path.join("/tmp", (root.lower() + ext)) + shutil.copy(image_path, new_image_path) + install_command = "ispvm %s" % new_image_path + # elif self.name == "BIOS": + # install_command = "afulnx_64 %s /p /b /n /x /r" % image_path + + return self.__run_command(install_command) + + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN 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 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return '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 True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..b0d37d57beac --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py @@ -0,0 +1,141 @@ +############################################################################# +# Celestica Seastone-DX010 +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + import os + import sys + import re + + if sys.version_info.major == 3: + from io import StringIO + else: + from cStringIO import StringIO + + 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' +NULL = 'N/A' + + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/class/i2c-adapter/i2c-12/12-0050/eeprom" + super(Tlv, 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 BaseException: + pass + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except BaseException: + 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 BaseException: + 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 BaseException: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except BaseException: + 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 _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/event.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/event.py new file mode 100644 index 000000000000..351b2a5ac087 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/event.py @@ -0,0 +1,52 @@ +try: + import select + from .helper import APIHelper + from sonic_py_common.logger import Logger +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + QSFP_MODPRS_IRQ = '/sys/devices/platform/dx010_cpld/qsfp_modprs_irq' + GPIO_SUS6 = "/sys/devices/platform/slx-ich.0/sci_int_gpio_sus6" + + def __init__(self, sfp_list): + self._api_helper = APIHelper() + self._sfp_list = sfp_list + self._logger = Logger() + + def get_sfp_event(self, timeout): + epoll = select.epoll() + port_dict = {} + timeout_sec = timeout/1000 + + try: + # We get notified when there is an SCI interrupt from GPIO SUS6 + fd = open(self.GPIO_SUS6, "r") + fd.read() + + epoll.register(fd.fileno(), select.EPOLLIN & select.EPOLLET) + events = epoll.poll(timeout=timeout_sec if timeout != 0 else -1) + if events: + # Read the QSFP ABS interrupt & status registers + port_changes = self._api_helper.read_one_line_file( + self.QSFP_MODPRS_IRQ) + changes = int(port_changes, 16) + for sfp in self._sfp_list: + change = (changes >> sfp.port_num-1) & 1 + if change == 1: + port_dict[str(sfp.port_num)] = str( + int(sfp.get_presence())) + + return port_dict + except Exception as e: + self._logger.log_error("Failed to detect SfpEvent - " + repr(e)) + return False + + finally: + fd.close() + epoll.close() + + return False diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..586efbfbb1f5 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan.py @@ -0,0 +1,383 @@ +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +from __future__ import division +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") + +EMC2305_PATH = "/sys/bus/i2c/drivers/emc2305/" +GPIO_DIR = "/sys/class/gpio" +GPIO_LABEL = "pca9505" +EMC2305_MAX_PWM = 255 +EMC2305_FAN_PWM = "pwm{}" +EMC2305_FAN_TARGET = "fan{}_target" +EMC2305_FAN_INPUT = "pwm{}" +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", "FAN-5F", "FAN-5R"] +FAN_SPEED_TOLERANCE = 10 +PSU_FAN_MAX_RPM = 11000 +PSU_HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" +PSU_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "5a" + }, + 1: { + "num": 11, + "addr": "5b" + }, +} +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): + FanBase.__init__(self) + self.fan_index = fan_index + self._api_helper = APIHelper() + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_I2C_MAPPING[self.psu_index]["num"] + self.psu_i2c_addr = PSU_I2C_MAPPING[self.psu_index]["addr"] + self.psu_hwmon_path = PSU_HWMON_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + # dx010 fan attributes + # Two EMC2305s located at i2c-13-4d and i2c-13-2e + # to control a dual-fan module. + self.emc2305_chip_mapping = [ + { + 'device': "13-002e", + 'index_map': [2, 1, 4, 5, 3] + }, + { + 'device': "13-004d", + 'index_map': [2, 4, 5, 3, 1] + } + ] + self.dx010_fan_gpio = [ + {'base': self.__get_gpio_base()}, + {'prs': 11, 'dir': 16, 'color': {'red': 31, 'green': 32}}, # 1 + {'prs': 10, 'dir': 15, 'color': {'red': 29, 'green': 30}}, # 2 + {'prs': 13, 'dir': 18, 'color': {'red': 35, 'green': 36}}, # 3 + {'prs': 14, 'dir': 19, 'color': {'red': 37, 'green': 38}}, # 4 + {'prs': 12, 'dir': 17, 'color': {'red': 33, 'green': 34}}, # 5 + ] + + def __write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except Exception: + return False + return True + + def __search_file_by_name(self, directory, file_name): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name in file_name: + return file_path + return None + + def __get_gpio_base(self): + for r in os.listdir(GPIO_DIR): + label_path = os.path.join(GPIO_DIR, r, "label") + if "gpiochip" in r and GPIO_LABEL in \ + self._api_helper.read_txt_file(label_path): + return int(r[8:], 10) + return 216 # Reserve + + def __get_gpio_value(self, pinnum): + gpio_base = self.dx010_fan_gpio[0]['base'] + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) + gpio_file = gpio_dir + "/value" + retval = self._api_helper.read_txt_file(gpio_file) + return retval.rstrip('\r\n') + + def __set_gpio_value(self, pinnum, value=0): + gpio_base = self.dx010_fan_gpio[0]['base'] + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base+pinnum) + gpio_file = gpio_dir + "/value" + return self.__write_txt_file(gpio_file, value) + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = self.FAN_DIRECTION_EXHAUST + if not self.is_psu_fan: + raw = self.__get_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['dir']) + + direction = self.FAN_DIRECTION_INTAKE if int( + raw, 10) == 0 else self.FAN_DIRECTION_EXHAUST + + 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: + speed = pwm_in/255*100 + """ + speed = 0 + if self.is_psu_fan: + fan_speed_sysfs_name = "fan{}_input".format(self.fan_index+1) + fan_speed_sysfs_path = self.__search_file_by_name( + self.psu_hwmon_path, fan_speed_sysfs_name) + fan_speed_rpm = self._api_helper.read_txt_file( + fan_speed_sysfs_path) or 0 + speed = math.ceil(float(fan_speed_rpm) * 100 / PSU_FAN_MAX_RPM) + elif self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] + device = chip['device'] + fan_index = chip['index_map'] + sysfs_path = "%s%s/%s" % ( + EMC2305_PATH, device, EMC2305_FAN_INPUT) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + raw = self._api_helper.read_txt_file(sysfs_path).strip('\r\n') + pwm = int(raw, 10) if raw else 0 + speed = math.ceil(float(pwm * 100 / EMC2305_MAX_PWM)) + + return int(speed) + + def get_target_speed(self): + """ + 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 = NULL_VAL + + if not self.is_psu_fan: + chip = self.emc2305_chip_mapping[self.fan_index] + device = chip['device'] + fan_index = chip['index_map'] + sysfs_path = "%s%s/%s" % ( + EMC2305_PATH, device, EMC2305_FAN_PWM) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + pwm = self._api_helper.read_txt_file(sysfs_path) + target = round(int(pwm) / 255 * 100.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 FAN_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 + + Note: + Depends on pwm or target mode is selected: + 1) pwm = speed_pc * 255 <-- Currently use this mode. + 2) target_pwm = speed_pc * 100 / 255 + 2.1) set pwm{}_enable to 3 + + """ + pwm = speed * 255 / 100 + if not self.is_psu_fan and self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] + device = chip['device'] + fan_index = chip['index_map'] + sysfs_path = "%s%s/%s" % ( + EMC2305_PATH, device, EMC2305_FAN_PWM) + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + return self.__write_txt_file(sysfs_path, int(pwm)) + + return False + + 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 + """ + set_status_led = False + + s1_gpio = self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red'] + s2_gpio = self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green'] + + if not self.is_psu_fan: + try: + if color == self.STATUS_LED_COLOR_GREEN: + s1 = self.__set_gpio_value(s1_gpio, 1) + s2 = self.__set_gpio_value(s2_gpio, 0) + + elif color == self.STATUS_LED_COLOR_RED: + s1 = self.__set_gpio_value(s1_gpio, 0) + s2 = self.__set_gpio_value(s2_gpio, 1) + + elif color == self.STATUS_LED_COLOR_OFF: + s1 = self.__set_gpio_value(s1_gpio, 1) + s2 = self.__set_gpio_value(s2_gpio, 1) + + elif color == self.STATUS_LED_COLOR_AMBER: + s1 = self.__set_gpio_value(s1_gpio, 0) + s2 = self.__set_gpio_value(s2_gpio, 0) + else: + s1, s2 = True, True + + set_status_led = s1 and s2 + + except IOError: + return False + + 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 + """ + s1 = self.__get_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['red']) + s2 = self.__get_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['color']['green']) + + return { + '10': self.STATUS_LED_COLOR_GREEN, + '01': self.STATUS_LED_COLOR_RED, + '00': self.STATUS_LED_COLOR_AMBER + }.get(s1+s2, self.STATUS_LED_COLOR_OFF) + + ############################################################## + ###################### 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 + """ + present_str = self.__get_gpio_value( + self.dx010_fan_gpio[self.fan_tray_index+1]['prs']) + + return int(present_str, 10) == 0 if not self.is_psu_fan else True + + 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 + 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 + 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 + """ + status = 1 + if self.is_psu_fan: + fan_fault_sysfs_name = "fan1_fault" + fan_fault_sysfs_path = self.__search_file_by_name( + self.psu_hwmon_path, fan_fault_sysfs_name) + status = self._api_helper.read_one_line_file(fan_fault_sysfs_path) + + elif self.get_presence(): + chip = self.emc2305_chip_mapping[self.fan_index] + device = chip['device'] + fan_index = chip['index_map'] + sysfs_path = "%s%s/%s" % ( + EMC2305_PATH, device, 'fan{}_fault') + sysfs_path = sysfs_path.format(fan_index[self.fan_tray_index]) + status = self._api_helper.read_one_line_file(sysfs_path) + + return False if int(status) != 0 else True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_tray_index*2 + self.fan_index + 1) \ + if not self.is_psu_fan else (self.fan_index+1) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True if not self.is_psu_fan else False diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan_drawer.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..e35ecf65195a --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the the Fan-Drawers' information available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN = 2 + + +class FanDrawer(FanDrawerBase): + def __init__(self, fantray_index): + FanDrawerBase.__init__(self) + self._index = fantray_index + 1 + self._init_fan(fantray_index) + + def _init_fan(self, fantray_index): + from sonic_platform.fan import Fan + for index in range(NUM_FAN): + fan = Fan(fantray_index, index) + self._fan_list.append(fan) + + def set_status_led(self, color): + """ + Sets the state of the fan drawer status LED + Args: + color: A string representing the color with which to set the + fan drawer status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return self._fan_list[0].set_status_led(color) + + def get_status_led(self, color=None): + """ + Gets the state of the fan drawer LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return self._fan_list[0].get_status_led() + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return "Drawer{}".format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_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._fan_list[0].get_status() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device + Returns: + integer: The 1-based relative physical position in parent device + """ + return self._index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/helper.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/helper.py new file mode 100644 index 000000000000..140c62c08666 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/helper.py @@ -0,0 +1,133 @@ +import os +import struct +import subprocess +from mmap import * + +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.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, universal_newlines=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 write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except Exception: + return False + return True + + def get_cpld_reg_value(self, getreg_path, register): + cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register) + status, result = self.run_command(cmd) + return result if status else 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, universal_newlines=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, universal_newlines=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, universal_newlines=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_blackstone-r0/sonic_platform/platform.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..7d98ec9f7cdf --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# 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_blackstone-r0/sonic_platform/psu.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..8bc95fa4f081 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/psu.py @@ -0,0 +1,391 @@ +############################################################################# +# Celestica +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +TLV_ATTR_TYPE_MODEL = 2 +TLV_ATTR_TYPE_SERIAL = 5 +PSU_EEPROM_PATH = "/sys/bus/i2c/devices/{}-00{}/eeprom" +GREEN_LED_PATH = "/sys/devices/platform/leds_dx010/leds/dx010:green:p-{}/brightness" +HWMON_PATH = "/sys/bus/i2c/devices/i2c-{0}/{0}-00{1}/hwmon" +GPIO_DIR = "/sys/class/gpio" +GPIO_LABEL = "pca9505" +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] +PSU_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "5a", + "eeprom_addr": "52" + }, + 1: { + "num": 11, + "addr": "5b", + "eeprom_addr": "53" + }, +} + + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index): + PsuBase.__init__(self) + self.index = psu_index + self._api_helper = APIHelper() + self.green_led_path = GREEN_LED_PATH.format(self.index + 1) + self.dx010_psu_gpio = [ + {'base': self.__get_gpio_base()}, + {'prs': 27, 'status': 22}, + {'prs': 28, 'status': 25} + ] + self.i2c_num = PSU_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = HWMON_PATH.format(self.i2c_num, self.i2c_addr) + self.eeprom_addr = PSU_EEPROM_PATH.format(self.i2c_num, PSU_I2C_MAPPING[self.index]["eeprom_addr"]) + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + def __search_file_by_contain(self, directory, search_str, file_start): + for dirpath, dirnames, files in os.walk(directory): + for name in files: + file_path = os.path.join(dirpath, name) + if name.startswith(file_start) and search_str in self._api_helper.read_txt_file(file_path): + return file_path + return None + + def __get_gpio_base(self): + for r in os.listdir(GPIO_DIR): + label_path = os.path.join(GPIO_DIR, r, "label") + if "gpiochip" in r and GPIO_LABEL in self._api_helper.read_txt_file(label_path): + return int(r[8:], 10) + return 216 # Reserve + + def __get_gpio_value(self, pinnum): + gpio_base = self.dx010_psu_gpio[0]['base'] + gpio_dir = GPIO_DIR + '/gpio' + str(gpio_base + pinnum) + gpio_file = gpio_dir + "/value" + retval = self._api_helper.read_txt_file(gpio_file) + return retval.rstrip('\r\n') + + def read_fru(self, path, attr_type): + content = [] + attr_idx = 0 + attr_length = 0 + + if(os.path.exists(path)): + with open(path, 'r', encoding='unicode_escape') as f: + content = f.read() + target_offset = ord(content[4]) + target_offset *= 8 # spec defined: offset are in multiples of 8 bytes + + attr_idx = target_offset + 3 + for i in range(1, attr_type): + if attr_idx > len(content): + raise SyntaxError + attr_length = (ord(content[attr_idx])) & (0x3f) + attr_idx += (attr_length + 1) + + attr_length = (ord(content[attr_idx])) & (0x3f) + attr_idx += 1 + else: + print("[PSU] Can't find path to eeprom : %s" % path) + return SyntaxError + + return content[attr_idx:attr_idx + attr_length] + + 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 + voltage_name = "in{}_input" + voltage_label = "vout1" + + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, voltage_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = ''.join(list(filter(str.isdigit, basename))) + vout_path = os.path.join( + dir_name, voltage_name.format(in_num)) + vout_val = self._api_helper.read_txt_file(vout_path) + psu_voltage = float(vout_val) / 1000 + + return psu_voltage + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + psu_current = 0.0 + current_name = "curr{}_input" + current_label = "iout1" + + curr_label_path = self.__search_file_by_contain( + self.hwmon_path, current_label, "cur") + if curr_label_path: + dir_name = os.path.dirname(curr_label_path) + basename = os.path.basename(curr_label_path) + cur_num = ''.join(list(filter(str.isdigit, basename))) + cur_path = os.path.join( + dir_name, current_name.format(cur_num)) + cur_val = self._api_helper.read_txt_file(cur_path) + psu_current = float(cur_val) / 1000 + + return psu_current + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + psu_power = 0.0 + current_name = "power{}_input" + current_label = "pout1" + + pw_label_path = self.__search_file_by_contain( + self.hwmon_path, current_label, "power") + if pw_label_path: + dir_name = os.path.dirname(pw_label_path) + basename = os.path.basename(pw_label_path) + pw_num = ''.join(list(filter(str.isdigit, basename))) + pw_path = os.path.join( + dir_name, current_name.format(pw_num)) + pw_val = self._api_helper.read_txt_file(pw_path) + psu_power = float(pw_val) / 1000000 + + return psu_power + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() + + def set_status_led(self, color): + """ + 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 + """ + + set_status_str = { + self.STATUS_LED_COLOR_GREEN: '1', + self.STATUS_LED_COLOR_OFF: '0' + }.get(color, None) + + if not set_status_str: + return False + + try: + with open(self.green_led_path, 'w') as file: + file.write(set_status_str) + except IOError: + return False + + return True + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + status = self._api_helper.read_txt_file(self.green_led_path) + status_str = { + '255': self.STATUS_LED_COLOR_GREEN, + '0': self.STATUS_LED_COLOR_OFF + }.get(status, None) + + return status_str + + def get_name(self): + """ + Retrieves the name of the device + 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 + """ + raw = self.__get_gpio_value(self.dx010_psu_gpio[self.index + 1]['prs']) + return int(raw, 10) == 0 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + raw = self.__get_gpio_value( + self.dx010_psu_gpio[self.index + 1]['status']) + return int(raw, 10) == 1 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model = self.read_fru(self.eeprom_addr, TLV_ATTR_TYPE_MODEL) + if not model: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial = self.read_fru(self.eeprom_addr, TLV_ATTR_TYPE_SERIAL) + if not serial: + return "N/A" + return serial + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + there are three temp sensors , we choose one of them + """ + psu_temperature = None + temperature_name = "temp{}_input" + temperature_label = "vout1" + + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, temperature_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = ''.join(list(filter(str.isdigit, basename))) + temp_path = os.path.join( + dir_name, temperature_name.format(in_num)) + vout_val = self._api_helper.read_txt_file(temp_path) + psu_temperature = float(vout_val) / 1000 + + return psu_temperature + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + there are three temp sensors , we choose one of them + """ + psu_temperature = None + temperature_name = "temp{}_max" + temperature_label = "vout1" + + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, temperature_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = ''.join(list(filter(str.isdigit, basename))) + temp_path = os.path.join( + dir_name, temperature_name.format(in_num)) + vout_val = self._api_helper.read_txt_file(temp_path) + psu_temperature = float(vout_val) / 1000 + + return psu_temperature + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + psu_voltage = 0.0 + voltage_name = "in{}_crit" + voltage_label = "vout1" + + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, voltage_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = ''.join(list(filter(str.isdigit, basename))) + vout_path = os.path.join( + dir_name, voltage_name.format(in_num)) + vout_val = self._api_helper.read_txt_file(vout_path) + psu_voltage = float(vout_val) / 1000 + + return psu_voltage + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + psu_voltage = 0.0 + voltage_name = "in{}_lcrit" + voltage_label = "vout1" + + vout_label_path = self.__search_file_by_contain( + self.hwmon_path, voltage_label, "in") + if vout_label_path: + dir_name = os.path.dirname(vout_label_path) + basename = os.path.basename(vout_label_path) + in_num = ''.join(list(filter(str.isdigit, basename))) + vout_path = os.path.join( + dir_name, voltage_name.format(in_num)) + vout_val = self._api_helper.read_txt_file(vout_path) + psu_voltage = float(vout_val) / 1000 + + return psu_voltage diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/sfp.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/sfp.py new file mode 100644 index 000000000000..c1423ed8dc7d --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/sfp.py @@ -0,0 +1,2204 @@ +#!/usr/bin/env python + +############################################################################# +# Celestica +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp status which are available in the platform +# +############################################################################# + +import time +import struct + +try: + from sonic_platform_base.sfp_base import SfpBase + 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.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + 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") + +# 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_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +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 +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# 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 + +# definitions of the offset for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# 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_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + + +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' +) + +info_dict_keys = [ + 'type', 'hardware_rev', 'serial', 'manufacturer', + 'model', 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', + 'vendor_oui', 'application_advertisement', 'type_abbrv_name' +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +dom_info_dict_keys = [ + 'rx_los', 'tx_fault', 'reset_status', 'lp_mode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', + 'rx5power', 'rx6power', 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', 'tx3power', 'tx4power', + 'tx5power', 'tx6power', 'tx7power', 'tx8power'] + +threshold_dict_keys = [ + 'temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning'] + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +NULL_VAL = 'N/A' + +PORT_START = 1 +PORT_END = 56 +QSFP_PORT_START = 1 +QSFP_PORT_END = 32 + +SFP_I2C_START = 26 +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + RESET_PATH = "/sys/devices/platform/dx010_cpld/qsfp_reset" + LP_PATH = "/sys/devices/platform/dx010_cpld/qsfp_lpmode" + PRS_PATH = "/sys/devices/platform/dx010_cpld/qsfp_modprs" + + def __init__(self, sfp_index=0, sfp_name=None): + SfpBase.__init__(self) + + self._index = sfp_index + self._port_num = self._index + 1 + self._api_helper = APIHelper() + self._name = sfp_name + + self._read_porttab_mappings() + self._dom_capability_detect() + self._eeprom_path = self._get_eeprom_path() + + def _read_porttab_mappings(self): + self._sfputil_helper = SfpUtilHelper() + self._sfputil_helper.read_porttab_mappings( + self._get_path_to_port_config_file()) + + def _get_path_to_port_config_file(self): + host_platform_root_path = '/usr/share/sonic/device' + docker_hwsku_path = '/usr/share/sonic/hwsku' + + host_platform_path = "/".join([host_platform_root_path, + self._api_helper.platform]) + hwsku_path = "/".join([host_platform_path, self._api_helper.hwsku]) \ + if self._api_helper.is_host() else docker_hwsku_path + + return "/".join([hwsku_path, "port_config.ini"]) + + 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 _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfs_sfp_i2c_client_eeprom_path = self._get_eeprom_path() + eeprom_raw = [] + try: + eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, + mode="rb", buffering=0) + except IOError: + return None + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + try: + eeprom.seek(offset) + raw = eeprom.read(num_bytes) + except IOError: + eeprom.close() + return None + + try: + if isinstance(raw, str): + for n in range(0, num_bytes): + eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) + else: + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + + except BaseException: + eeprom.close() + return None + + eeprom.close() + return eeprom_raw + + def _detect_sfp_type(self): + sfp_type = QSFP_TYPE + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def _get_eeprom_path(self): + port_to_i2c_mapping = SFP_I2C_START + self._index + port_eeprom_path = I2C_EEPROM_PATH.format(port_to_i2c_mapping) + return port_eeprom_path + + 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 + + self._detect_sfp_type() + + if self.sfp_type == QSFP_TYPE: + 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_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 == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + # currently set to False becasue Page 11h is not supported by FW + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + 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.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + 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 + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |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 + application_advertisement |1*255VCHAR |supported applications advertisement + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys( + info_dict_keys, NULL_VAL) + transceiver_info_dict["specification_compliance"] = '{}' + + # 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 transceiver_info_dict + + 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 transceiver_info_dict + + 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 transceiver_info_dict + + 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 transceiver_info_dict + + 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 transceiver_info_dict + + 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 transceiver_info_dict + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + sfp_type_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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 transceiver_info_dict + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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 transceiver_info_dict + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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 transceiver_info_dict + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( + sfp_vendor_rev_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_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 transceiver_info_dict + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( + sfp_vendor_oui_raw, 0) + else: + return transceiver_info_dict + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date( + sfp_vendor_date_raw, 0) + else: + return transceiver_info_dict + + sfp_connector_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector( + sfp_connector_raw, 0) + else: + return transceiver_info_dict + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden( + sfp_ext_identifier_raw, 0) + else: + return transceiver_info_dict + + sfp_cable_len_raw = self._read_eeprom_specific_bytes( + (offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len( + sfp_cable_len_raw, 0) + else: + return transceiver_info_dict + + sfp_media_type_raw = self._read_eeprom_specific_bytes( + XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type( + sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return transceiver_info_dict + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes( + (XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes( + (XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + \ + sfp_application_type_second_list + else: + return transceiver_info_dict + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return transceiver_info_dict + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application( + sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + \ + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return transceiver_info_dict + + transceiver_info_dict['type'] = str( + sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str( + sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str( + sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str( + sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str( + sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str( + sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str( + sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str( + sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str( + sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str( + sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + if self.sfp_type != QSFP_DD_TYPE: + 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 transceiver_info_dict + + 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['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = 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'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes( + offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance( + sfp_ext_specification_compliance_raw[0: 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data[ + 'data']['Extended Specification compliance']['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( + dom_info_dict_keys, NULL_VAL) + + 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 = 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 = 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'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature( + dom_data_raw[start: end], 0) + temp = dom_temperature_data['data']['Temperature']['value'] + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage( + dom_data_raw[start: end], 0) + volt = dom_voltage_data['data']['Vcc']['value'] + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + dom_data_raw = self._read_eeprom_specific_bytes( + (QSFP_DD_CHANNL_MON_OFFSET), QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str( + dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = str( + dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = str( + dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = str( + dom_channel_monitor_data['data']['TX4Power']['value']) + transceiver_dom_info_dict['tx5power'] = str( + dom_channel_monitor_data['data']['TX5Power']['value']) + transceiver_dom_info_dict['tx6power'] = str( + dom_channel_monitor_data['data']['TX6Power']['value']) + transceiver_dom_info_dict['tx7power'] = str( + dom_channel_monitor_data['data']['TX7Power']['value']) + transceiver_dom_info_dict['tx8power'] = str( + dom_channel_monitor_data['data']['TX8Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str( + dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = str( + dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = str( + dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = str( + dom_channel_monitor_data['data']['RX4Power']['value']) + transceiver_dom_info_dict['rx5power'] = str( + dom_channel_monitor_data['data']['RX5Power']['value']) + transceiver_dom_info_dict['rx6power'] = str( + dom_channel_monitor_data['data']['RX6Power']['value']) + transceiver_dom_info_dict['rx7power'] = str( + dom_channel_monitor_data['data']['RX7Power']['value']) + transceiver_dom_info_dict['rx8power'] = str( + dom_channel_monitor_data['data']['RX8Power']['value']) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str( + dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str( + dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str( + dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str( + dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str( + dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str( + dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str( + dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str( + dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + 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'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disabled_channel'] = self.get_tx_disable_channel( + ) + + for key in transceiver_dom_info_dict: + val = transceiver_dom_info_dict[key] + transceiver_dom_info_dict[key] = self._convert_string_to_num( + val) if type(val) is str else val + + 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( + threshold_dict_keys, NULL_VAL) + + 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'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_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) + + # 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_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_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 + """ + reset_status_raw = self._api_helper.read_txt_file( + self.RESET_PATH).rstrip() + if not reset_status_raw: + return False + + reg_value = int(reset_status_raw, 16) + bin_format = bin(reg_value)[2:].zfill(32) + return bin_format[::-1][self._index] == '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_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + 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) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), + QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + rx_los_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + else: + return [False] * 8 + 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_list.append(rx_los_data & 0x02 != 0) + else: + return [False] + return rx_los_list + + 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. + """ + tx_fault_list = [] + + if self.sfp_type == OSFP_TYPE: + return None + 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) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + else: + return [False] * 4 + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), + QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 8) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + tx_fault_list.append(tx_fault_data & 0x10 != 0) + tx_fault_list.append(tx_fault_data & 0x20 != 0) + tx_fault_list.append(tx_fault_data & 0x40 != 0) + tx_fault_list.append(tx_fault_data & 0x80 != 0) + else: + return [False] * 8 + 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) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A list of boolean values, representing the TX disable status + of each available channel, value is True if SFP channel + is TX disabled, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + """ + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + 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.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + else: + return [False] * 4 + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), + QSFP_DD_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.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + else: + return [False] * 8 + 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.append(tx_disable_data & 0xC0 != 0) + else: + return [False] + return tx_disable_list + + 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 = self.get_tx_disable() + if tx_disable_list is None: + return 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 + """ + try: + reg_file = open(self.LP_PATH, "r") + content = reg_file.readline().rstrip() + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Determind if port_num start from 1 or 0 + bit_index = self._index + + # Mask off the bit corresponding to our port + mask = (1 << bit_index) + + # LPMode is active high + if reg_value & mask == 0: + return False + + return True + + def get_power_override(self): + """ + 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( + (offset + QSFP_CONTROL_OFFSET), QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes( + dom_control_raw, 0) + return ('On' == dom_control_data['data']['PowerOverride']) + else: + return False + else: + return NotImplementedError + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + default = 0.0 + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self._read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + + return default + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + default = 0.0 + + if not self.dom_supported: + return default + + if self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage( + dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self._read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + + return default + + 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'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias( + dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_tx_bias_data['data']['TX8Bias']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return default + else: + return default + + 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 = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power( + dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_rx_power_data['data']['RX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return default + else: + return default + 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 = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return tx_power_list + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + default = [0.0] * 4 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_power_list + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return default + else: + return default + + elif self.sfp_type == QSFP_DD_TYPE: + default = [0.0] * 8 + + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 128 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return default + + if self.dom_tx_power_supported: + dom_tx_power_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_DD_TX_POWER_OFFSET), + QSFP_DD_TX_POWER_WIDTH) + if dom_tx_power_raw is not None: + dom_tx_power_data = sfpd_obj.parse_dom_tx_power( + dom_tx_power_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX4Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX5Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX6Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX7Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_tx_power_data['data']['TX8Power']['value'])) + else: + return default + else: + return default + + else: + offset = 256 + default = [0.0] + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return default + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return default + else: + return default + 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 + """ + # Check for invalid port_num + + try: + reg_file = open(self.RESET_PATH, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + content = reg_file.readline().rstrip() + + # File content is a string containing the hex representation of the + # register + reg_value = int(content, 16) + + # Determind if port_num start from 1 or 0 + bit_index = self._index + + # Mask off the bit corresponding to our port + mask = (1 << bit_index) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + reg_file.seek(0) + reg_file.write(hex(reg_value).rstrip('L')) + 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(self.RESET_PATH, "w") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_value | mask + reg_file.seek(0) + reg_file.write(hex(reg_value).rstrip('L')) + 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_value = 0xf if tx_disable else 0x0 + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + 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: + current_state = self.get_tx_disable_channel() + tx_disable_value = (current_state | channel) if \ + disable else (current_state & (~channel)) + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', tx_disable_value)) + except IOError: + 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(self.LP_PATH, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + content = reg_file.readline().rstrip() + + # content is a string containing the hex representation of the register + reg_value = int(content, 16) + + # Determind if port_num start from 1 or 0 + bit_index = self._index + + # Mask off the bit corresponding to our port + mask = (1 << bit_index) + # LPMode is active high; set or clear the bit accordingly + reg_value = reg_value | mask if lpmode else reg_value & ~mask + + # Convert our register value back to a hex string and write back + content = hex(reg_value).strip('L') + + reg_file.seek(0) + reg_file.write(content) + reg_file.close() + + return True + + def set_power_override(self, power_override, power_set): + """ + 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 + """ + sysfsfile_eeprom = None + if self.sfp_type == QSFP_TYPE and self.get_presence(): + try: + power_override_bit = 0x1 if power_override else 0 + power_set_bit = 0x2 if power_set else 0 + value = power_override_bit | power_set_bit + + # Write to eeprom + sysfsfile_eeprom = open(self._eeprom_path, "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(struct.pack('B', value)) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + 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 + """ + return self._name + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_status_raw = self._api_helper.read_txt_file( + self.PRS_PATH).rstrip() + if not presence_status_raw: + return False + + content = presence_status_raw.rstrip() + reg_value = int(content, 16) + + # Determind if port_num start from 1 or 0 + bit_index = self._index + + # Mask off the bit corresponding to our port + mask = (1 << bit_index) + + # ModPrsL is active low + if reg_value & mask == 0: + return True + + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + transceiver_dom_info_dict = self.get_transceiver_info() + return transceiver_dom_info_dict.get("model", "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("serial", "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() + + def get_position_in_parent(self): + """ + Returns: + Temp return 0 + """ + return 0 + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal.py new file mode 100644 index 000000000000..ce2a45f0c5bb --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal.py @@ -0,0 +1,264 @@ +############################################################################# +# 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 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") + +THERMAL_INFO = { + 0: { + "F2B_max": 50, + "F2B_max_crit": 75, + "B2F_max": 55, + "B2F_max_crit": 75, + "postion": "asic", + "name": "Front-panel temp sensor 1", + "i2c_path": "i2c-5/5-0048/hwmon/hwmon1", # u4 system-inlet + }, + 1: { + "F2B_max": 50, + "F2B_max_crit": 75, + "B2F_max": 55, + "B2F_max_crit": 75, + "postion": "asic", + "name": "Front-panel temp sensor 2", + "i2c_path": "i2c-6/6-0049/hwmon/hwmon2", # u2 system-inlet + }, + 2: { + "F2B_max": 70, + "F2B_max_crit": 75, + "B2F_max": 60, + "B2F_max_crit": 65, + "postion": "asic", + "name": "ASIC temp sensor", + "i2c_path": "i2c-7/7-004a/hwmon/hwmon3", # u44 bmc56960-on-board + }, + 3: { + "F2B_max": 70, + "F2B_max_crit": 75, + "B2F_max": 70, + "B2F_max_crit": 75, + "postion": "cpu", + "name": "Rear-panel temp sensor 1", + "i2c_path": "i2c-14/14-0048/hwmon/hwmon4", # u9200 cpu-on-board + }, + 4: { + "F2B_max": 70, + "F2B_max_crit": 75, + "B2F_max": 55, + "B2F_max_crit": 75, + "postion": "cpu", + "name": "Rear-panel temp sensor 2", + "i2c_path": "i2c-15/15-004e/hwmon/hwmon5" # u9201 system-outlet + } +} +NULL_VAL = "N/A" +I2C_ADAPTER_PATH = "/sys/class/i2c-adapter" + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + SS_CONFIG_PATH = "/usr/share/sonic/device/x86_64-cel_seastone-r0/sensors.conf" + + def __init__(self, thermal_index, airflow): + ThermalBase.__init__(self) + self.index = thermal_index + self._api_helper = APIHelper() + self._airflow = airflow + self._thermal_info = THERMAL_INFO[self.index] + self._hwmon_path = "{}/{}".format(I2C_ADAPTER_PATH, self._thermal_info["i2c_path"]) + self.name = self.get_name() + self.postion = self._thermal_info["postion"] + self.ss_index = 1 + + def __get_temp(self, temp_file): + temp_file_path = os.path.join(self._hwmon_path, temp_file) + raw_temp = self._api_helper.read_txt_file(temp_file_path) + temp = float(raw_temp)/1000 + return float("{:.3f}".format(temp)) + + def __set_threshold(self, file_name, temperature): + temp_file_path = os.path.join(self._hwmon_path, file_name) + try: + with open(temp_file_path, 'w') as fd: + fd.write(str(temperature)) + return True + except IOError: + return False + + 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 + """ + temp_file = "temp{}_input".format(self.ss_index) + return self.__get_temp(temp_file) + + 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 + """ + temp_file = "temp{}_max".format(self.ss_index) + temp = float(self.__get_temp(temp_file)) + return temp + + 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 0.001 + + 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 + """ + temp_file = "temp{}_max".format(self.ss_index) + is_set = self.__set_threshold(temp_file, int(temperature*1000)) + file_set = True + if self._api_helper.is_host(): + file_set = False + if is_set: + try: + with open(self.SS_CONFIG_PATH, 'r+') as f: + content = f.readlines() + f.seek(0) + ss_found = False + for idx, val in enumerate(content): + if self.name in val: + ss_found = True + elif ss_found and temp_file in val: + content[idx] = " set {} {}\n".format( + temp_file, temperature) + f.writelines(content) + file_set = True + break + except IOError as err: + file_set = False + + return is_set & file_set + + 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 + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + max_crit_key = '{}_max_crit'.format(self._airflow) + max_crit_threshold = self._thermal_info.get(max_crit_key, None) + if max_crit_threshold is not None: + max_crit_threshold = float(max_crit_threshold) + return max_crit_threshold + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + Returns: + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return 0.001 + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + return self._thermal_info["name"] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self._hwmon_path, temp_file) + return os.path.isfile(temp_file_path) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return NULL_VAL + + 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 + """ + if not self.get_presence(): + return False + + fault_file = "temp{}_fault".format(self.ss_index) + fault_file_path = os.path.join(self._hwmon_path, fault_file) + if not os.path.isfile(fault_file_path): + return True + + raw_txt = self.__read_txt_file(fault_file_path) + return int(raw_txt) == 0 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_position_in_parent(self): + """ + Retrieves the thermal position information + Returns: + A int value, 0 represent ASIC thermal, 1 represent CPU thermal info + """ + if self.postion == "cpu": + return 1 + return 0 diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_actions.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_actions.py new file mode 100644 index 000000000000..545db861f683 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_actions.py @@ -0,0 +1,78 @@ + +from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase +from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +from .thermal_infos import ChassisInfo +from .helper import APIHelper + + +@thermal_json_object('thermal_control.control') +class ControlThermalAlgoAction(ThermalPolicyActionBase): + """ + Action to control the thermal control algorithm + """ + # JSON field definition + JSON_FIELD_STATUS = 'status' + + def __init__(self): + self.status = True + + def load_from_json(self, json_obj): + """ + Construct ControlThermalAlgoAction via JSON. JSON example: + { + "type": "thermal_control.control" + "status": "true" + } + :param json_obj: A JSON object representing a ControlThermalAlgoAction action. + :return: + """ + if ControlThermalAlgoAction.JSON_FIELD_STATUS in json_obj: + status_str = json_obj[ControlThermalAlgoAction.JSON_FIELD_STATUS].lower() + if status_str == 'true': + self.status = True + elif status_str == 'false': + self.status = False + else: + raise ValueError('Invalid {} field value, please specify true of false'. + format(ControlThermalAlgoAction.JSON_FIELD_STATUS)) + else: + raise ValueError('ControlThermalAlgoAction ' + 'missing mandatory field {} in JSON policy file'. + format(ControlThermalAlgoAction.JSON_FIELD_STATUS)) + + def execute(self, thermal_info_dict): + """ + Disable thermal control algorithm + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + if ChassisInfo.INFO_NAME in thermal_info_dict: + chassis_info_obj = thermal_info_dict[ChassisInfo.INFO_NAME] + chassis = chassis_info_obj.get_chassis() + thermal_manager = chassis.get_thermal_manager() + if self.status: + thermal_manager.start_thermal_control_algorithm() + else: + thermal_manager.stop_thermal_control_algorithm() + + +@thermal_json_object('switch.power_cycling') +class SwitchPolicyAction(ThermalPolicyActionBase): + """ + Base class for thermal action. Once all thermal conditions in a thermal policy are matched, + all predefined thermal action will be executed. + """ + + def execute(self, thermal_info_dict): + """ + Take action when thermal condition matches. For example, power cycle the switch. + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + thermal_overload_position_path = '/tmp/thermal_overload_position' + thermal_overload_position = APIHelper().read_one_line_file( + thermal_overload_position_path) + + cmd = 'bash /usr/share/sonic/platform/thermal_overload_control.sh {}'.format( + thermal_overload_position) + APIHelper().run_command(cmd) diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_conditions.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_conditions.py new file mode 100644 index 000000000000..1eee8ea91ab5 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_conditions.py @@ -0,0 +1,77 @@ +from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase +from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object + + +class FanCondition(ThermalPolicyConditionBase): + def get_fan_info(self, thermal_info_dict): + from .thermal_infos import FanInfo + if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): + return thermal_info_dict[FanInfo.INFO_NAME] + else: + return None + + +@thermal_json_object('fan.any.absence') +class AnyFanAbsenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False + + +@thermal_json_object('fan.any.fault') +class AnyFanFaultCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_fault_fans()) > 0 if fan_info_obj else False + + +@thermal_json_object('fan.all.presence') +class AllFanPresenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False + + +@thermal_json_object('fan.all.good') +class AllFanGoodCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_fault_fans()) == 0 if fan_info_obj else False + + +class ThermalCondition(ThermalPolicyConditionBase): + def get_thermal_info(self, thermal_info_dict): + from .thermal_infos import ThermalInfo + if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): + return thermal_info_dict[ThermalInfo.INFO_NAME] + else: + return None + + +@thermal_json_object('thermal.over.high_threshold') +class ThermalOverHighCriticalCondition(ThermalCondition): + def is_match(self, thermal_info_dict): + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + return thermal_info_obj.is_over_high_threshold() + else: + return False + + +@thermal_json_object('thermal.over.high_critical_threshold') +class ThermalOverHighCriticalCondition(ThermalCondition): + def is_match(self, thermal_info_dict): + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + return thermal_info_obj.is_over_high_critical_threshold() + else: + return False + +@thermal_json_object('thermal.all.good') +class ThermalGoodCondition(ThermalCondition): + def is_match(self, thermal_info_dict): + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + return not thermal_info_obj.is_over_threshold() + else: + return False diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_infos.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_infos.py new file mode 100644 index 000000000000..a680b31b634f --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_infos.py @@ -0,0 +1,165 @@ +from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase +from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +from .helper import APIHelper +import time + + +@thermal_json_object('fan_info') +class FanInfo(ThermalPolicyInfoBase): + """ + Fan information needed by thermal policy + """ + + # Fan information name + INFO_NAME = 'fan_info' + + def __init__(self): + self._absence_fans = set() + self._presence_fans = set() + self._fault_fans = set() + self._status_changed = False + + def collect(self, chassis): + """ + Collect absence and presence fans. + :param chassis: The chassis object + :return: + """ + self._status_changed = False + for fan in chassis.get_all_fans(): + presence = fan.get_presence() + status = fan.get_status() + if presence and fan not in self._presence_fans: + self._presence_fans.add(fan) + self._status_changed = True + if fan in self._absence_fans: + self._absence_fans.remove(fan) + elif not presence and fan not in self._absence_fans: + self._absence_fans.add(fan) + self._status_changed = True + if fan in self._presence_fans: + self._presence_fans.remove(fan) + + if not status and fan not in self._fault_fans: + self._fault_fans.add(fan) + self._status_changed = True + + elif status and fan in self._fault_fans: + self._fault_fans.remove(fan) + self._status_changed = True + + def get_absence_fans(self): + """ + Retrieves absence fans + :return: A set of absence fans + """ + return self._absence_fans + + def get_presence_fans(self): + """ + Retrieves presence fans + :return: A set of presence fans + """ + return self._presence_fans + + def get_fault_fans(self): + """ + Retrieves fault fans + :return: A set of fault fans + """ + return self._fault_fans + + def is_status_changed(self): + """ + Retrieves if the status of fan information changed + :return: True if status changed else False + """ + return self._status_changed + + +@thermal_json_object('thermal_info') +class ThermalInfo(ThermalPolicyInfoBase): + """ + Thermal information needed by thermal policy + """ + + # Fan information name + INFO_NAME = 'thermal_info' + + def collect(self, chassis): + """ + Collect thermal sensor temperature change status + :param chassis: The chassis object + :return: + """ + self._over_high_threshold = False + self._over_high_critical_threshold = False + self._thermal_overload_position = 'cpu' + + # Calculate average temp within the device + temp = 0 + num_of_thermals = chassis.get_num_thermals() + for index in range(num_of_thermals): + thermal = chassis.get_thermal(index) + temp = thermal.get_temperature() + high_threshold = thermal.get_high_threshold() + high_critical_threshold = thermal.get_high_critical_threshold() + + if high_threshold and temp > high_threshold: + self._over_high_threshold = True + + if high_critical_threshold and temp > high_critical_threshold: + self._thermal_overload_position = thermal.postion + self._over_high_critical_threshold = True + + def is_over_threshold(self): + """ + Retrieves if the temperature is over any threshold + :return: True if the temperature is over any threshold else False + """ + return self._over_high_threshold or self._over_high_critical_threshold + + def is_over_high_critical_threshold(self): + """ + Retrieves if the temperature is over high critical threshold + :return: True if the temperature is over high critical threshold else False + """ + thermal_overload_position_path = '/tmp/thermal_overload_position' + if self._over_high_critical_threshold: + APIHelper().write_txt_file(thermal_overload_position_path, + self._thermal_overload_position) + time.sleep(1) + return self._over_high_critical_threshold + + def is_over_high_threshold(self): + """ + Retrieves if the temperature is over high threshold + :return: True if the temperature is over high threshold else False + """ + return self._over_high_threshold + + +@thermal_json_object('chassis_info') +class ChassisInfo(ThermalPolicyInfoBase): + """ + Chassis information needed by thermal policy + """ + INFO_NAME = 'chassis_info' + + def __init__(self): + self._chassis = None + + def collect(self, chassis): + """ + Collect platform chassis. + :param chassis: The chassis object + :return: + """ + self._chassis = chassis + + def get_chassis(self): + """ + Retrieves platform chassis object + :return: A platform chassis object. + """ + return self._chassis diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_manager.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_manager.py new file mode 100644 index 000000000000..9f057cf1f37f --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/thermal_manager.py @@ -0,0 +1,46 @@ +from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase +from .helper import APIHelper +from .thermal_actions import * +from .thermal_conditions import * +from .thermal_infos import * + +class ThermalManager(ThermalManagerBase): + FSC_ALGORITHM_CMD = 'service fancontrol {}' + + @classmethod + def start_thermal_control_algorithm(cls): + """ + Start vendor specific thermal control algorithm. The default behavior of this function is a no-op. + :return: + """ + return cls._enable_fancontrol_service(True) + + @classmethod + def stop_thermal_control_algorithm(cls): + """ + Stop thermal control algorithm + Returns: + bool: True if set success, False if fail. + """ + return cls._enable_fancontrol_service(False) + + @classmethod + def deinitialize(cls): + """ + Destroy thermal manager, including any vendor specific cleanup. The default behavior of this function + is a no-op. + :return: + """ + return cls._enable_fancontrol_service(True) + + @classmethod + def _enable_fancontrol_service(cls, enable): + """ + Control thermal by fcs algorithm + Args: + enable: Bool, indicate enable the algorithm or not + Returns: + bool: True if set success, False if fail. + """ + cmd = 'start' if enable else 'stop' + return APIHelper().run_command(cls.FSC_ALGORITHM_CMD.format(cmd)) diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/watchdog.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/watchdog.py new file mode 100644 index 000000000000..122b5d90ddb6 --- /dev/null +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/watchdog.py @@ -0,0 +1,194 @@ +############################################################################# +# Celestica +# +# Watchdog contains an implementation of SONiC Platform Base API +# +############################################################################# +import ctypes +import os +import subprocess +import time + +try: + from sonic_platform_base.watchdog_base import WatchdogBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PLATFORM_CPLD_PATH = '/sys/devices/platform/dx010_cpld' +GETREG_FILE = 'getreg' +SETREG_FILE = 'setreg' +WDT_ENABLE_REG = '0x141' +WDT_TIMER_L_BIT_REG = '0x142' +WDT_TIMER_M_BIT_REG = '0x143' +WDT_TIMER_H_BIT_REG = '0x144' +WDT_KEEP_ALVIVE_REG = '0x145' +ENABLE_CMD = '0x1' +DISABLE_CMD = '0x0' +WDT_COMMON_ERROR = -1 + + +class Watchdog(WatchdogBase): + + def __init__(self): + WatchdogBase.__init__(self) + + # Init helper + self._api_helper = APIHelper() + + # Init cpld reg path + self.setreg_path = os.path.join(PLATFORM_CPLD_PATH, SETREG_FILE) + self.getreg_path = os.path.join(PLATFORM_CPLD_PATH, GETREG_FILE) + + # Set default value + self._disable() + self.armed = False + self.timeout = self._gettimeout() + + def _enable(self): + """ + Turn on the watchdog timer + """ + # echo 0x141 0x1 > /sys/devices/platform/dx010_cpld/setreg + enable_val = '{} {}'.format(WDT_ENABLE_REG, ENABLE_CMD) + return self._api_helper.write_txt_file(self.setreg_path, enable_val) + + def _disable(self): + """ + Turn off the watchdog timer + """ + # echo 0x141 0x0 > /sys/devices/platform/dx010_cpld/setreg + disable_val = '{} {}'.format(WDT_ENABLE_REG, DISABLE_CMD) + return self._api_helper.write_txt_file(self.setreg_path, disable_val) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + # echo 0x145 0x1 > /sys/devices/platform/dx010_cpld/setreg + enable_val = '{} {}'.format(WDT_KEEP_ALVIVE_REG, ENABLE_CMD) + return self._api_helper.write_txt_file(self.setreg_path, enable_val) + + def _get_level_hex(self, sub_hex): + sub_hex_str = sub_hex.replace("x", "0") + return hex(int(sub_hex_str, 16)) + + def _seconds_to_lmh_hex(self, seconds): + ms = seconds*1000 # calculate timeout in ms format + hex_str = hex(ms) + l = self._get_level_hex(hex_str[-2:]) + m = self._get_level_hex(hex_str[-4:-2]) + h = self._get_level_hex(hex_str[-6:-4]) + return (l, m, h) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + # max = 0xffffff = 16777.215 seconds + + (l, m, h) = self._seconds_to_lmh_hex(seconds) + set_h_val = '{} {}'.format(WDT_TIMER_H_BIT_REG, h) + set_m_val = '{} {}'.format(WDT_TIMER_M_BIT_REG, m) + set_l_val = '{} {}'.format(WDT_TIMER_L_BIT_REG, l) + + self._api_helper.write_txt_file(self.setreg_path, set_h_val) + self._api_helper.write_txt_file(self.setreg_path, set_m_val) + self._api_helper.write_txt_file(self.setreg_path, set_l_val) + + return seconds + + def _gettimeout(self): + """ + Get watchdog timeout + @return watchdog timeout + """ + + h_bit = self._api_helper.get_cpld_reg_value( + self.getreg_path, WDT_TIMER_H_BIT_REG) + m_bit = self._api_helper.get_cpld_reg_value( + self.getreg_path, WDT_TIMER_M_BIT_REG) + l_bit = self._api_helper.get_cpld_reg_value( + self.getreg_path, WDT_TIMER_L_BIT_REG) + + hex_time = '0x{}{}{}'.format(h_bit[2:], m_bit[2:], l_bit[2:]) + ms = int(hex_time, 16) + return int(float(ms)/1000) + + ################################################################# + + 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 + if seconds > 16779: + 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 + self.arm_timestamp = time.time() + 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. + """ + + return int(self.timeout - (time.time() - self.arm_timestamp)) if self.armed else WDT_COMMON_ERROR From 545b41ee21f0a0a0ec0dce61cac3171482025498 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 14 Sep 2021 12:59:17 +0700 Subject: [PATCH 03/32] [device/celestica-blackstone]: disable services in pmon --- .../x86_64-cel_blackstone-r0/pmon_daemon_control.json | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json b/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json index 82a04d00747b..1bf19bb80fa1 100644 --- a/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json +++ b/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json @@ -1,4 +1,9 @@ { + "skip_fancontrol": true, "skip_ledd": true, - "skip_psud": true -} + "skip_pcied": true, + "skip_psud": true, + "skip_syseepromd": true, + "skip_thermalctld": true, + "skip_xcvrd": true +} \ No newline at end of file From e05d0dd6a4681fb6b9febbef1abb0d17c7956d53 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 15 Sep 2021 11:28:57 +0700 Subject: [PATCH 04/32] [platform/cel-blackstone]: fix sonic_platform package_dir --- .../broadcom/sonic-platform-modules-cel/blackstone/setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py b/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py index 30d1e6445d81..a4e010cebde5 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/setup.py @@ -11,13 +11,13 @@ author='SONiC Team', author_email='linuxnetdev@microsoft.com', url='https://github.com/Azure/sonic-buildimage', - maintainer='Larry Ming', - maintainer_email='laming@celestica.com', + maintainer='Wirut Getbamrung', + maintainer_email='wgetbumr@celestica.com', packages=[ 'sonic_platform', ], package_dir={ - 'sonic_platform': '../device/sonic_platform'}, + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, classifiers=[ 'Development Status :: 3 - Alpha', 'Environment :: Plugins', From de61c7a3bb1769e02696471847d769a4ab6e7306 Mon Sep 17 00:00:00 2001 From: LuiSzee Date: Wed, 28 Apr 2021 16:30:47 +0800 Subject: [PATCH 05/32] [build]: fix bug for compile sonic-platform-common caused by enable pytest (#7431) Co-authored-by: Shi Lei --- rules/sonic-platform-common.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rules/sonic-platform-common.mk b/rules/sonic-platform-common.mk index b3dd0155d59e..25ab5ff839fa 100644 --- a/rules/sonic-platform-common.mk +++ b/rules/sonic-platform-common.mk @@ -4,6 +4,7 @@ SONIC_PLATFORM_COMMON_PY2 = sonic_platform_common-1.0-py2-none-any.whl $(SONIC_PLATFORM_COMMON_PY2)_SRC_PATH = $(SRC_PATH)/sonic-platform-common $(SONIC_PLATFORM_COMMON_PY2)_PYTHON_VERSION = 2 $(SONIC_PLATFORM_COMMON_PY2)_DEPENDS += $(SONIC_PY_COMMON_PY2) $(SONIC_CONFIG_ENGINE_PY2) +$(SONIC_PLATFORM_COMMON_PY2)_DEBS_DEPENDS += $(PYTHON_SWSSCOMMON) SONIC_PYTHON_WHEELS += $(SONIC_PLATFORM_COMMON_PY2) # Als build sonic-platform-common into python3 wheel, so we can use PSU code in SNMP docker @@ -11,6 +12,7 @@ SONIC_PLATFORM_COMMON_PY3 = sonic_platform_common-1.0-py3-none-any.whl $(SONIC_PLATFORM_COMMON_PY3)_SRC_PATH = $(SRC_PATH)/sonic-platform-common $(SONIC_PLATFORM_COMMON_PY3)_PYTHON_VERSION = 3 $(SONIC_PLATFORM_COMMON_PY3)_DEPENDS += $(SONIC_PY_COMMON_PY3) $(SONIC_CONFIG_ENGINE_PY3) +$(SONIC_PLATFORM_COMMON_PY3)_DEBS_DEPENDS += $(PYTHON3_SWSSCOMMON) # Synthetic dependency just to avoid race condition $(SONIC_PLATFORM_COMMON_PY3)_DEPENDS += $(SONIC_PLATFORM_COMMON_PY2) SONIC_PYTHON_WHEELS += $(SONIC_PLATFORM_COMMON_PY3) From e1bd6ebcd34b6db3b5ce4c7f9675a4d2de2b1bbf Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 15 Sep 2021 21:43:14 +0700 Subject: [PATCH 06/32] [platform/cel-blackstone]: fix missing debain files --- .../x86_64-cel_blackstone-r0/sensors.conf | 1 - .../debian/platform-modules-blackstone.init | 169 ++++++++++++++++++ .../platform-modules-blackstone.install | 4 + .../platform-modules-blackstone.postinst | 5 + 4 files changed, 178 insertions(+), 1 deletion(-) delete mode 100644 device/celestica/x86_64-cel_blackstone-r0/sensors.conf create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install create mode 100644 platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst diff --git a/device/celestica/x86_64-cel_blackstone-r0/sensors.conf b/device/celestica/x86_64-cel_blackstone-r0/sensors.conf deleted file mode 100644 index d3be47f4b0dd..000000000000 --- a/device/celestica/x86_64-cel_blackstone-r0/sensors.conf +++ /dev/null @@ -1 +0,0 @@ -# libsensors configuration file for Celestica Blackstone. diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init new file mode 100644 index 000000000000..8ee3d4465588 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -0,0 +1,169 @@ +#!/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 DX010 board. +### END INIT INFO + +function export_gpio { +label=$3 +gpio_dir=$2 +gpio_num=$1 +gpio_base=`( cat /sys/class/gpio/gpiochip*/base | head -1 ) 2>/dev/null` +gpio_label=`( cat /sys/class/gpio/gpiochip*/label | head -1 ) 2>/dev/null` +if [[ "X$gpio_base" == "X" ]] || +( [[ "X$label" != "X" ]] && [[ "$label" != "$gpio_label" ]] ); then + echo "Platform driver error: No gpiochip found!" + exit 1; +fi +ionum=$((gpio_base+gpio_num)) +echo $ionum > /sys/class/gpio/export +if [ $? -ne 0 ]; then + echo "Platform driver error: Cannot export gpio$ionum!" + exit 1; +fi +if [[ "X$gpio_dir" != "X" ]]; then + echo $gpio_dir > /sys/class/gpio/gpio${ionum}/direction + if [ $? -ne 0 ]; then + echo "Platform driver error: Cannot set direction of gpio$ionum!" + exit 1; + fi +fi +} + +case "$1" in +start) + echo -n "Setting up board... " + + modprobe i2c-dev + modprobe i2c-mux-pca954x force-deselect-on-exit=1 + modprobe dx010_wdt + modprobe leds-dx010 + modprobe lm75 + modprobe slx_gpio_ich + + found=0 + for devnum in 0 1; do + devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name` + # iSMT adapter can be at either dffd0000 or dfff0000 + if [[ $devname == 'SMBus iSMT adapter at '* ]]; then + found=1 + break + fi + done + + [ $found -eq 0 ] && echo "cannot find iSMT" && exit 1 + + i2cset -y ${devnum} 0x70 0x10 0x00 0x01 i + sleep 1 + + # Attach PCA9548 0x71 Channel Extender for Main Board + echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-${devnum}/new_device + sleep 1 + + # Attach PCA9548 0x73 Channel Extender for CPU Board + echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-${devnum}/new_device + sleep 1 + + # Attach PCA9548 0x77 Channel Extender for Fan's EEPROMs + echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-${devnum}/new_device + sleep 1 + + # Attach syseeprom + echo 24lc64t 0x50 > /sys/bus/i2c/devices/i2c-12/new_device + + # Attach temperature sensors + echo lm75b 0x48 > /sys/bus/i2c/devices/i2c-5/new_device + echo lm75b 0x49 > /sys/bus/i2c/devices/i2c-6/new_device + echo lm75b 0x4a > /sys/bus/i2c/devices/i2c-7/new_device + echo lm75b 0x48 > /sys/bus/i2c/devices/i2c-14/new_device + echo lm75b 0x4e > /sys/bus/i2c/devices/i2c-15/new_device + + # Attach fans + echo emc2305 0x2e > /sys/bus/i2c/devices/i2c-13/new_device + echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-13/new_device + + echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-18/new_device + echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-19/new_device + echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-20/new_device + echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-21/new_device + echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-22/new_device + + # Attach PSUs + echo dps460 0x5a > /sys/bus/i2c/devices/i2c-10/new_device + echo dps460 0x5b > /sys/bus/i2c/devices/i2c-11/new_device + + echo 24c02 0x52 > /sys/bus/i2c/devices/i2c-10/new_device + echo 24c02 0x53 > /sys/bus/i2c/devices/i2c-11/new_device + + # Attach PCA9506 GPIO expander for 40 pins + echo pca9505 0x20 > /sys/bus/i2c/devices/i2c-17/new_device + + modprobe dx010_cpld + sleep 2 + + # Export platform gpio sysfs + export_gpio 10 "in" # Fan 1 present + export_gpio 11 "in" # Fan 2 present + export_gpio 12 "in" # Fan 3 present + export_gpio 13 "in" # Fan 4 present + export_gpio 14 "in" # Fan 5 present + + export_gpio 15 "in" # Fan 1 direction + export_gpio 16 "in" # Fan 2 direction + export_gpio 17 "in" # Fan 3 direction + export_gpio 18 "in" # Fan 4 direction + export_gpio 19 "in" # Fan 5 direction + + export_gpio 22 "in" # PSU L PWOK + export_gpio 25 "in" # PSU R PWOK + export_gpio 27 "in" # PSU L ABS + export_gpio 28 "in" # PSU R ABS + + export_gpio 29 "out" # Fan 2 LED: Red + export_gpio 30 "out" # Fan 2 LED: Green + export_gpio 31 "out" # Fan 1 LED: Red + export_gpio 32 "out" # Fan 1 LED: Green + export_gpio 33 "out" # Fan 5 LED: Red + export_gpio 34 "out" # Fan 5 LED: Green + export_gpio 35 "out" # Fan 3 LED: Red + export_gpio 36 "out" # Fan 3 LED: Green + export_gpio 37 "out" # Fan 4 LED: Red + export_gpio 38 "out" # Fan 4 LED: Green + + # Turn off/down lpmod by defult (0 - Normal, 1 - Low Pow) + echo 0x00000000 > /sys/devices/platform/dx010_cpld/qsfp_lpmode + + # Attach 32 instances of EEPROM driver QSFP ports + for ((n=26;n<=58;n++)); + do + echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$n/new_device + sleep 0.1 + done + + /bin/sh /usr/local/bin/platform_api_mgnt.sh init + + echo "done." + ;; + +stop) + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/platform-modules-dx010.init {start|stop}" + exit 1 + ;; +esac + +exit 0 diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install new file mode 100644 index 000000000000..352cccdc37e8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install @@ -0,0 +1,4 @@ +blackstone/scripts/sensors usr/bin +blackstone/scripts/platform_sensors.py usr/local/bin +blackstone/cfg/blackstone-modules.conf etc/modules-load.d +blackstone/systemd/platform-modules-blackstone.service lib/systemd/system diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst new file mode 100644 index 000000000000..5c2c96e6b9de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst @@ -0,0 +1,5 @@ +depmod -a +systemctl enable platform-modules-blackstone.service +systemctl start platform-modules-blackstone.service + + From f607f616354090805d6e9194ee6e9ec0d513649e Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 15 Sep 2021 23:11:38 +0700 Subject: [PATCH 07/32] [platform/cel-blackstone]: fix invalid init file --- .../debian/platform-modules-blackstone.init | 167 ++++-------------- 1 file changed, 39 insertions(+), 128 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index 8ee3d4465588..399ac390f690 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -8,146 +8,57 @@ # Should-Stop: # Default-Start: S # Default-Stop: 0 6 -# Short-Description: Setup DX010 board. +# Short-Description: Setup Blackstone board. ### END INIT INFO -function export_gpio { -label=$3 -gpio_dir=$2 -gpio_num=$1 -gpio_base=`( cat /sys/class/gpio/gpiochip*/base | head -1 ) 2>/dev/null` -gpio_label=`( cat /sys/class/gpio/gpiochip*/label | head -1 ) 2>/dev/null` -if [[ "X$gpio_base" == "X" ]] || -( [[ "X$label" != "X" ]] && [[ "$label" != "$gpio_label" ]] ); then - echo "Platform driver error: No gpiochip found!" - exit 1; -fi -ionum=$((gpio_base+gpio_num)) -echo $ionum > /sys/class/gpio/export -if [ $? -ne 0 ]; then - echo "Platform driver error: Cannot export gpio$ionum!" - exit 1; -fi -if [[ "X$gpio_dir" != "X" ]]; then - echo $gpio_dir > /sys/class/gpio/gpio${ionum}/direction - if [ $? -ne 0 ]; then - echo "Platform driver error: Cannot set direction of gpio$ionum!" - exit 1; - fi -fi -} case "$1" in start) echo -n "Setting up board... " + depmod -a modprobe i2c-dev - modprobe i2c-mux-pca954x force-deselect-on-exit=1 - modprobe dx010_wdt - modprobe leds-dx010 - modprobe lm75 - modprobe slx_gpio_ich - - found=0 - for devnum in 0 1; do - devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name` - # iSMT adapter can be at either dffd0000 or dfff0000 - if [[ $devname == 'SMBus iSMT adapter at '* ]]; then - found=1 - break - fi + modprobe ipmi_devintf + modprobe mc24lc64t + modprobe baseboard-lpc + modprobe cls-i2c-ocores + modprobe cls-fpga + modprobe xcvr-cls + modprobe switch_cpld + modprobe i2c-mux-pca954x force_deselect_on_exit=1 + + # 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 optoe2 for SFP+. + for i in {1..2} + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done - [ $found -eq 0 ] && echo "cannot find iSMT" && exit 1 - - i2cset -y ${devnum} 0x70 0x10 0x00 0x01 i - sleep 1 - - # Attach PCA9548 0x71 Channel Extender for Main Board - echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-${devnum}/new_device - sleep 1 - - # Attach PCA9548 0x73 Channel Extender for CPU Board - echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-${devnum}/new_device - sleep 1 - - # Attach PCA9548 0x77 Channel Extender for Fan's EEPROMs - echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-${devnum}/new_device - sleep 1 - - # Attach syseeprom - echo 24lc64t 0x50 > /sys/bus/i2c/devices/i2c-12/new_device - - # Attach temperature sensors - echo lm75b 0x48 > /sys/bus/i2c/devices/i2c-5/new_device - echo lm75b 0x49 > /sys/bus/i2c/devices/i2c-6/new_device - echo lm75b 0x4a > /sys/bus/i2c/devices/i2c-7/new_device - echo lm75b 0x48 > /sys/bus/i2c/devices/i2c-14/new_device - echo lm75b 0x4e > /sys/bus/i2c/devices/i2c-15/new_device - - # Attach fans - echo emc2305 0x2e > /sys/bus/i2c/devices/i2c-13/new_device - echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-13/new_device - - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-18/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-19/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-20/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-21/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-22/new_device - - # Attach PSUs - echo dps460 0x5a > /sys/bus/i2c/devices/i2c-10/new_device - echo dps460 0x5b > /sys/bus/i2c/devices/i2c-11/new_device - - echo 24c02 0x52 > /sys/bus/i2c/devices/i2c-10/new_device - echo 24c02 0x53 > /sys/bus/i2c/devices/i2c-11/new_device - - # Attach PCA9506 GPIO expander for 40 pins - echo pca9505 0x20 > /sys/bus/i2c/devices/i2c-17/new_device - - modprobe dx010_cpld - sleep 2 - - # Export platform gpio sysfs - export_gpio 10 "in" # Fan 1 present - export_gpio 11 "in" # Fan 2 present - export_gpio 12 "in" # Fan 3 present - export_gpio 13 "in" # Fan 4 present - export_gpio 14 "in" # Fan 5 present - - export_gpio 15 "in" # Fan 1 direction - export_gpio 16 "in" # Fan 2 direction - export_gpio 17 "in" # Fan 3 direction - export_gpio 18 "in" # Fan 4 direction - export_gpio 19 "in" # Fan 5 direction - - export_gpio 22 "in" # PSU L PWOK - export_gpio 25 "in" # PSU R PWOK - export_gpio 27 "in" # PSU L ABS - export_gpio 28 "in" # PSU R ABS - - export_gpio 29 "out" # Fan 2 LED: Red - export_gpio 30 "out" # Fan 2 LED: Green - export_gpio 31 "out" # Fan 1 LED: Red - export_gpio 32 "out" # Fan 1 LED: Green - export_gpio 33 "out" # Fan 5 LED: Red - export_gpio 34 "out" # Fan 5 LED: Green - export_gpio 35 "out" # Fan 3 LED: Red - export_gpio 36 "out" # Fan 3 LED: Green - export_gpio 37 "out" # Fan 4 LED: Red - export_gpio 38 "out" # Fan 4 LED: Green - - # Turn off/down lpmod by defult (0 - Normal, 1 - Low Pow) - echo 0x00000000 > /sys/devices/platform/dx010_cpld/qsfp_lpmode - - # Attach 32 instances of EEPROM driver QSFP ports - for ((n=26;n<=58;n++)); + # Attach QSFP-DD i2c devices + echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-3/new_device + echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-3/new_device + echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-6/new_device + echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-6/new_device + + # use optoe3 for QSFP-DD. + for i in {7..38} do - echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$n/new_device - sleep 0.1 + echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done - /bin/sh /usr/local/bin/platform_api_mgnt.sh init + /bin/sh /usr/local/bin/platform_api_mgnt.sh init echo "done." ;; @@ -161,7 +72,7 @@ force-reload|restart) ;; *) - echo "Usage: /etc/init.d/platform-modules-dx010.init {start|stop}" +Usage: /etc/init.d/platform-modules-blackstone.init {start|stop} exit 1 ;; esac From 0cf6ff24d6bc3611aa738e79feaf1fbf2b0e2d4b Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 15 Sep 2021 23:12:59 +0700 Subject: [PATCH 08/32] [platform/cel-blackstone]: fix invalid init file --- .../debian/platform-modules-blackstone.init | 167 ++++-------------- 1 file changed, 39 insertions(+), 128 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index 8ee3d4465588..fc2b374f7e76 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -8,146 +8,57 @@ # Should-Stop: # Default-Start: S # Default-Stop: 0 6 -# Short-Description: Setup DX010 board. +# Short-Description: Setup Blackstone board. ### END INIT INFO -function export_gpio { -label=$3 -gpio_dir=$2 -gpio_num=$1 -gpio_base=`( cat /sys/class/gpio/gpiochip*/base | head -1 ) 2>/dev/null` -gpio_label=`( cat /sys/class/gpio/gpiochip*/label | head -1 ) 2>/dev/null` -if [[ "X$gpio_base" == "X" ]] || -( [[ "X$label" != "X" ]] && [[ "$label" != "$gpio_label" ]] ); then - echo "Platform driver error: No gpiochip found!" - exit 1; -fi -ionum=$((gpio_base+gpio_num)) -echo $ionum > /sys/class/gpio/export -if [ $? -ne 0 ]; then - echo "Platform driver error: Cannot export gpio$ionum!" - exit 1; -fi -if [[ "X$gpio_dir" != "X" ]]; then - echo $gpio_dir > /sys/class/gpio/gpio${ionum}/direction - if [ $? -ne 0 ]; then - echo "Platform driver error: Cannot set direction of gpio$ionum!" - exit 1; - fi -fi -} case "$1" in start) echo -n "Setting up board... " + depmod -a modprobe i2c-dev - modprobe i2c-mux-pca954x force-deselect-on-exit=1 - modprobe dx010_wdt - modprobe leds-dx010 - modprobe lm75 - modprobe slx_gpio_ich - - found=0 - for devnum in 0 1; do - devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name` - # iSMT adapter can be at either dffd0000 or dfff0000 - if [[ $devname == 'SMBus iSMT adapter at '* ]]; then - found=1 - break - fi + modprobe ipmi_devintf + modprobe mc24lc64t + modprobe baseboard-lpc + modprobe cls-i2c-ocores + modprobe cls-fpga + modprobe xcvr-cls + modprobe switch_cpld + modprobe i2c-mux-pca954x force_deselect_on_exit=1 + + # 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 optoe2 for SFP+. + for i in {1..2} + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done - [ $found -eq 0 ] && echo "cannot find iSMT" && exit 1 - - i2cset -y ${devnum} 0x70 0x10 0x00 0x01 i - sleep 1 - - # Attach PCA9548 0x71 Channel Extender for Main Board - echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-${devnum}/new_device - sleep 1 - - # Attach PCA9548 0x73 Channel Extender for CPU Board - echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-${devnum}/new_device - sleep 1 - - # Attach PCA9548 0x77 Channel Extender for Fan's EEPROMs - echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-${devnum}/new_device - sleep 1 - - # Attach syseeprom - echo 24lc64t 0x50 > /sys/bus/i2c/devices/i2c-12/new_device - - # Attach temperature sensors - echo lm75b 0x48 > /sys/bus/i2c/devices/i2c-5/new_device - echo lm75b 0x49 > /sys/bus/i2c/devices/i2c-6/new_device - echo lm75b 0x4a > /sys/bus/i2c/devices/i2c-7/new_device - echo lm75b 0x48 > /sys/bus/i2c/devices/i2c-14/new_device - echo lm75b 0x4e > /sys/bus/i2c/devices/i2c-15/new_device - - # Attach fans - echo emc2305 0x2e > /sys/bus/i2c/devices/i2c-13/new_device - echo emc2305 0x4d > /sys/bus/i2c/devices/i2c-13/new_device - - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-18/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-19/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-20/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-21/new_device - echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-22/new_device - - # Attach PSUs - echo dps460 0x5a > /sys/bus/i2c/devices/i2c-10/new_device - echo dps460 0x5b > /sys/bus/i2c/devices/i2c-11/new_device - - echo 24c02 0x52 > /sys/bus/i2c/devices/i2c-10/new_device - echo 24c02 0x53 > /sys/bus/i2c/devices/i2c-11/new_device - - # Attach PCA9506 GPIO expander for 40 pins - echo pca9505 0x20 > /sys/bus/i2c/devices/i2c-17/new_device - - modprobe dx010_cpld - sleep 2 - - # Export platform gpio sysfs - export_gpio 10 "in" # Fan 1 present - export_gpio 11 "in" # Fan 2 present - export_gpio 12 "in" # Fan 3 present - export_gpio 13 "in" # Fan 4 present - export_gpio 14 "in" # Fan 5 present - - export_gpio 15 "in" # Fan 1 direction - export_gpio 16 "in" # Fan 2 direction - export_gpio 17 "in" # Fan 3 direction - export_gpio 18 "in" # Fan 4 direction - export_gpio 19 "in" # Fan 5 direction - - export_gpio 22 "in" # PSU L PWOK - export_gpio 25 "in" # PSU R PWOK - export_gpio 27 "in" # PSU L ABS - export_gpio 28 "in" # PSU R ABS - - export_gpio 29 "out" # Fan 2 LED: Red - export_gpio 30 "out" # Fan 2 LED: Green - export_gpio 31 "out" # Fan 1 LED: Red - export_gpio 32 "out" # Fan 1 LED: Green - export_gpio 33 "out" # Fan 5 LED: Red - export_gpio 34 "out" # Fan 5 LED: Green - export_gpio 35 "out" # Fan 3 LED: Red - export_gpio 36 "out" # Fan 3 LED: Green - export_gpio 37 "out" # Fan 4 LED: Red - export_gpio 38 "out" # Fan 4 LED: Green - - # Turn off/down lpmod by defult (0 - Normal, 1 - Low Pow) - echo 0x00000000 > /sys/devices/platform/dx010_cpld/qsfp_lpmode - - # Attach 32 instances of EEPROM driver QSFP ports - for ((n=26;n<=58;n++)); + # Attach QSFP-DD i2c devices + echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-3/new_device + echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-3/new_device + echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-6/new_device + echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-6/new_device + + # use optoe3 for QSFP-DD. + for i in {7..38} do - echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$n/new_device - sleep 0.1 + echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done - /bin/sh /usr/local/bin/platform_api_mgnt.sh init + #/bin/sh /usr/local/bin/platform_api_mgnt.sh init echo "done." ;; @@ -161,7 +72,7 @@ force-reload|restart) ;; *) - echo "Usage: /etc/init.d/platform-modules-dx010.init {start|stop}" +Usage: /etc/init.d/platform-modules-blackstone.init {start|stop} exit 1 ;; esac From 4b6efeffbae293fd56730fc180362c29b4cae5e6 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 15 Sep 2021 23:34:36 +0700 Subject: [PATCH 09/32] [platform/cel-blackstone]: add rule to make all kernel module --- .../sonic-platform-modules-cel/blackstone/modules/Makefile | 2 +- .../debian/platform-modules-blackstone.init | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile index 0bdf369fd721..880646de76d9 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile @@ -1 +1 @@ -obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o switch_cpld.o +obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o switch_cpld.o cls-i2c-ocores.o diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index fc2b374f7e76..2763b2f4df14 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -58,7 +58,7 @@ start) echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done - #/bin/sh /usr/local/bin/platform_api_mgnt.sh init + #/bin/sh /usr/local/bin/platform_api_mgnt.sh init echo "done." ;; From 1deee18631351e8cccbe44a7b7b500690e489282 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 17 Sep 2021 14:34:49 +0700 Subject: [PATCH 10/32] [platform/cel-blackstone]: update mapping on fpga driver follow fpga spec --- .../blackstone/modules/cls-fpga.c | 126 +++++++++++++++--- 1 file changed, 108 insertions(+), 18 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c index be6b4170fd73..e818c4ff2df0 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c @@ -438,6 +438,36 @@ module_param(bus_clock_master_13, int, 0660); MODULE_PARM_DESC(bus_clock_master_13, "I2C master 13 bus speed in KHz 50/80/100/200/400"); +static int bus_clock_master_14 = 100; +module_param(bus_clock_master_14, int, 0660); +MODULE_PARM_DESC(bus_clock_master_14, + "I2C master 14 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_15 = 100; +module_param(bus_clock_master_15, int, 0660); +MODULE_PARM_DESC(bus_clock_master_15, + "I2C master 15 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_16 = 100; +module_param(bus_clock_master_16, int, 0660); +MODULE_PARM_DESC(bus_clock_master_16, + "I2C master 16 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_17 = 100; +module_param(bus_clock_master_17, int, 0660); +MODULE_PARM_DESC(bus_clock_master_17, + "I2C master 17 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_18 = 100; +module_param(bus_clock_master_18, int, 0660); +MODULE_PARM_DESC(bus_clock_master_18, + "I2C master 18 bus speed in KHz 50/80/100/200/400"); + +static int bus_clock_master_19 = 100; +module_param(bus_clock_master_19, int, 0660); +MODULE_PARM_DESC(bus_clock_master_19, + "I2C master 19 bus speed in KHz 50/80/100/200/400"); + /* RESOURCE SEPERATES BY FUNCTION */ /* Resource IOMEM for i2c bus 1 for SFP1*/ static struct resource cls_i2c_res_1[] = { @@ -525,6 +555,48 @@ static struct resource cls_i2c_res_13[] = { .flags = IORESOURCE_MEM,}, }; +/* Resource IOMEM for i2c bus 14 for ...*/ +static struct resource cls_i2c_res_14[] = { + { + .start = 0x9A0, .end = 0x9BF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 15 for ...*/ +static struct resource cls_i2c_res_15[] = { + { + .start = 0x9C0, .end = 0x9DF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 16 for ...*/ +static struct resource cls_i2c_res_16[] = { + { + .start = 0x9E0, .end = 0x9FF, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 17 for ...*/ +static struct resource cls_i2c_res_17[] = { + { + .start = 0xA00, .end = 0xA1F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 18 for ...*/ +static struct resource cls_i2c_res_18[] = { + { + .start = 0xA20, .end = 0xA3F, + .flags = IORESOURCE_MEM,}, +}; + +/* Resource IOMEM for i2c bus 19 for ...*/ +static struct resource cls_i2c_res_19[] = { + { + .start = 0xA40, .end = 0xA5F, + .flags = IORESOURCE_MEM,}, +}; + /* Resource IOMEM for reg access */ static struct resource reg_io_res[] = { { @@ -554,9 +626,9 @@ static struct resource xcvr_res[] = { */ static struct i2c_bus_config i2c_bus_configs[] = { { - .id = 1, - .res = cls_i2c_res_1, - .num_res = ARRAY_SIZE(cls_i2c_res_1), + .id = 10, + .res = cls_i2c_res_10, + .num_res = ARRAY_SIZE(cls_i2c_res_10), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -568,9 +640,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 = 11, + .res = cls_i2c_res_11, + .num_res = ARRAY_SIZE(cls_i2c_res_11), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -582,9 +654,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 = 14, + .res = cls_i2c_res_14, + .num_res = ARRAY_SIZE(cls_i2c_res_14), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -596,9 +668,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 = 15, + .res = cls_i2c_res_15, + .num_res = ARRAY_SIZE(cls_i2c_res_15), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -610,9 +682,9 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 6, - .res = cls_i2c_res_6, - .num_res = ARRAY_SIZE(cls_i2c_res_6), + .id = 18, + .res = cls_i2c_res_18, + .num_res = ARRAY_SIZE(cls_i2c_res_18), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -624,9 +696,9 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 11, - .res = cls_i2c_res_11, - .num_res = ARRAY_SIZE(cls_i2c_res_11), + .id = 19, + .res = cls_i2c_res_19, + .num_res = ARRAY_SIZE(cls_i2c_res_19), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -844,6 +916,24 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) case 13: i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_13; break; + case 14: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_14; + break; + case 15: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_15; + break; + case 16: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_16; + break; + case 17: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_17; + break; + case 18: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_18; + break; + case 19: + i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_19; + break; default: i2c_bus_configs[i].pdata.bus_khz = OCORE_BUS_CLK_khz; } From 469d4fb7066d3f1c2501cf302028893de3b8d5fe Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 21 Sep 2021 14:15:28 +0700 Subject: [PATCH 11/32] [platform/cel-blackstone]: enable switch_cpld init --- .../debian/platform-modules-blackstone.init | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index 9be876339262..d1c7ab6f1f74 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -24,7 +24,7 @@ start) modprobe cls-i2c-ocores modprobe cls-fpga modprobe xcvr-cls - # modprobe switch_cpld + modprobe switch_cpld modprobe i2c-mux-pca954x force_deselect_on_exit=1 # Instantiate TLV EEPROM device on I801 bus From e48106165c2a9dbe8d27b43fc52e389eb273e52e Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 24 Sep 2021 10:33:02 +0700 Subject: [PATCH 12/32] [platform/cel-blackstone]: update platform_sensors follow ipmi sensors --- .../blackstone/scripts/platform_sensors.py | 226 ++++++++---------- 1 file changed, 95 insertions(+), 131 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py b/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py index 38193c255f31..fd510aab9fca 100755 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/scripts/platform_sensors.py @@ -3,22 +3,26 @@ # Blackstone platform sensors. This script get the sensor data from BMC # using ipmitool and display them in lm-sensor alike format. # -# The following data is support: -# 1. Temperature sensors -# 2. PSUs -# 3. Fan trays import sys import logging import subprocess IPMI_SDR_CMD = "ipmitool sdr elist" -MAX_NUM_FANS = 7 -MAX_NUM_PSUS = 2 +SENSOR_GROUPS = [ + ('BB', 'Baseboard'), + ('BMC', 'BMC'), + ('COME', 'COM-E'), + ('Fan', 'Fan'), + ('PSU', 'PSU'), + ('SW', 'Switch board'), + ('XP', 'Voltage') +] def ipmi_sensor_dump(cmd): - ''' Execute ipmitool command return dump output + ''' + Execute ipmitool command return dump output exit if any error occur. ''' sensor_dump = '' @@ -29,145 +33,105 @@ def ipmi_sensor_dump(cmd): sys.exit(1) return sensor_dump -def get_reading_by_name(sensor_name, sdr_elist_dump): + +def get_reading_object(sdr_elist_dump): ''' - Search for the match sensor name, return sensor - reading value and unit, return object epmtry string - if search not match. - - The output of sensor dump: - TEMP_FAN_U52 | 00h | ok | 7.1 | 31 degrees C - TEMP_FAN_U17 | 01h | ok | 7.1 | 27 degrees C - TEMP_SW_U52 | 02h | ok | 7.1 | 30 degrees C - Fan2_Status | 07h | ok | 29.2 | Present - Fan2_Front | 0Eh | ok | 29.2 | 12000 RPM - Fan2_Rear | 46h | ok | 29.2 | 14700 RPM - PSU2_Status | 39h | ok | 10.2 | Presence detected - PSU2_Fan | 3Dh | ok | 10.2 | 16000 RPM - PSU2_VIn | 3Ah | ok | 10.2 | 234.30 Volts - PSU2_CIn | 3Bh | ok | 10.2 | 0.80 Amps + Load sensor data from sdr elist dump to object + + Example format: + Input sdr_elist_dump: + Fan2_Status | 07h | ok | 29.2 | Present + Fan2_Front | 0Eh | ok | 29.2 | 12000 RPM + Fan2_Rear | 46h | ok | 29.2 | 14700 RPM + PSU2_Status | 39h | ok | 10.2 | Presence detected + PSU2_Fan | 3Dh | ok | 10.2 | 16000 RPM + PSU2_VIn | 3Ah | ok | 10.2 | 234.30 Volts + + Output sensor_data: + { + 'Fan sensors': [ + ('Fan2_Status', 'Present'), + ('Fan2_Front', '12000 RPM'), + ('Fan2_Rear', '14700 RPM') + ], + 'PSU sensors': [ + ('PSU2_Status', 'Presence detected'), + ('PSU2_Fan', '16000 RPM'), + ('PSU2_VIn', '234.30 Volts') + ] + } ''' - found = '' + sensor_data = {} + max_name_width = 0 for line in sdr_elist_dump.split("\n"): - if sensor_name in line: - found = line.strip() - break - - if not found: - logging.error('Cannot find sensor name:' + sensor_name) - - else: - try: - found = found.split('|')[4] - except IndexError: - logging.error('Cannot get sensor data of:' + sensor_name) - - logging.basicConfig(level=logging.DEBUG) - return found - - -def read_temperature_sensors(ipmi_sdr_elist): - - sensor_list = [ - ('TEMP_FAN_U52', 'Fan Tray Middle Temp'), - ('TEMP_FAN_U17', 'Fan Tray Right Temp'), - ('TEMP_SW_U1_1', 'Switchboard Left Inlet Temp'), - ('TEMP_SW_U1_2', 'Switchboard Right Inlet Temp'), - ('TEMP_SW_U1_3', 'Switchboard Right Inlet Temp'), - ('TEMP_BB_U3', 'Baseboard Temp'), - ('TEMP_CPU', 'CPU Internal Temp'), - ('TEMP_SW_Internal', 'ASIC Internal Temp'), - ('SW_U104_Temp1', 'IR3595 Chip Left Temp'), - ('SW_U121_Temp1', 'IR3595 Chip Right Temp'), - ('SW_U128_Temp1', 'IR3584 Chip Temp'), - ('SW_U130_Temp1', 'IR3584 Chip Temp'), - ] - - output = '' - sensor_format = '{0:{width}}{1}\n' - # Find max length of sensor calling name - max_name_width = max(len(sensor[1]) for sensor in sensor_list) + for sensor_group in SENSOR_GROUPS: + if line.startswith(sensor_group[0]): + sensor_name = line.split('|')[0].strip() + sensor_val = line.split('|')[4].strip() - output += "Temperature Sensors\n" - output += "Adapter: IPMI adapter\n" - for sensor in sensor_list: - reading = get_reading_by_name(sensor[0],ipmi_sdr_elist) - output += sensor_format.format('{}:'.format(sensor[1]), - reading, - width=str(max_name_width+1)) - output += '\n' - return output + sensor_list = sensor_data.get(sensor_group[1], []) + sensor_list.append((sensor_name, sensor_val)) + sensor_data[sensor_group[1]] = sensor_list + max_name_width = len(sensor_name) if len( + sensor_name) > max_name_width else max_name_width -def read_fan_sensors(num_fans, ipmi_sdr_elist): + return sensor_data, max_name_width - sensor_list = [ - ('Fan{}_Status', 'Status'), - ('Fan{}_Front', 'Fan {} front'), - ('Fan{}_Rear', 'Fan {} rear'), - ] - output = '' - sensor_format = '{0:{width}}{1}\n' - # Find max length of sensor calling name - max_name_width = max(len(sensor[1]) for sensor in sensor_list) - - output += "Fan Trays\n" - output += "Adapter: IPMI adapter\n" - for fan_num in range(1, num_fans+1): - for sensor in sensor_list: - ipmi_sensor_name = sensor[0].format(fan_num) - display_sensor_name = sensor[1].format(fan_num) - reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist) - output += sensor_format.format('{}:'.format(display_sensor_name), - reading, - width=str(max_name_width+1)) - output += '\n' - return output - - -def read_psu_sensors(num_psus, ipmi_sdr_elist): - - sensor_list = [ - ('PSU{}_Status', 'PSU {} Status'), - ('PSU{}_Fan', 'PSU {} Fan'), - ('PSU{}_VIn', 'PSU {} Input Voltag'), - ('PSU{}_CIn', 'PSU {} Input Current'), - ('PSU{}_PIn', 'PSU {} Input Power'), - ('PSU{}_Temp1', 'PSU {} Temp1'), - ('PSU{}_Temp2', 'PSU {} Temp2'), - ('PSU{}_VOut', 'PSU {} Output Voltag'), - ('PSU{}_COut', 'PSU {} Output Current'), - ('PSU{}_POut', 'PSU {} Output Power'), - ] - - output = '' +def get_sensor_output_str(sensor_data, max_name_width): + ''' + Convert sensor data object to readable string format. + + Example format: + Input sensor_data: + { + 'Fan sensors': [ + ('Fan2_Status', 'Present'), + ('Fan2_Front', '12000 RPM'), + ('Fan2_Rear', '14700 RPM') + ], + 'PSU sensors': [ + ('PSU2_Status', 'Presence detected'), + ('PSU2_Fan', '16000 RPM'), + ('PSU2_VIn', '234.30 Volts') + ] + } + + Output output_string: + Fan sensors + Adapter: IPMI adapter + Fan2 Status: Present + Fan2 Front: 12000 RPM + Fan2 Rear: 14700 RPM + + PSU sensors + Adapter: IPMI adapter + PSU2 Status: Presence detected + PSU2 Fan: 16000 RPM + PSU2 VIn: 234.30 Volts + ''' + output_string = '' sensor_format = '{0:{width}}{1}\n' - # Find max length of sensor calling name - max_name_width = max(len(sensor[1]) for sensor in sensor_list) - - output += "PSU\n" - output += "Adapter: IPMI adapter\n" - for psu_num in range(1, num_psus+1): - for sensor in sensor_list: - ipmi_sensor_name = sensor[0].format(psu_num) - display_sensor_name = sensor[1].format(psu_num) - reading = get_reading_by_name(ipmi_sensor_name, ipmi_sdr_elist) - output += sensor_format.format('{}:'.format(display_sensor_name), - reading, - width=str(max_name_width+1)) - output += '\n' - return output + for key_sensor in sensor_data: + output_string += "{}\n".format(key_sensor) + output_string += "Adapter: IPMI adapter\n" + sensor_list = sensor_data[key_sensor] + for sensor_value in sensor_list: + display_sensor_name = sensor_value[0].replace('_', ' ') + output_string += sensor_format.format('{}:'.format(display_sensor_name), + sensor_value[1], + width=str(max_name_width+4)) + output_string += '\n' + return output_string def main(): output_string = '' - ipmi_sdr_elist = ipmi_sensor_dump(IPMI_SDR_CMD) - output_string += read_temperature_sensors(ipmi_sdr_elist) - output_string += read_psu_sensors(MAX_NUM_PSUS, ipmi_sdr_elist) - output_string += read_fan_sensors(MAX_NUM_FANS, ipmi_sdr_elist) + sensor_object, max_name_width = get_reading_object(ipmi_sdr_elist) + output_string += get_sensor_output_str(sensor_object, max_name_width) print(output_string) From 318b145879e5dd518346095393aa92846c290c00 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 24 Sep 2021 16:43:43 +0700 Subject: [PATCH 13/32] [device/celestica-blackstone]: update psuutil follow BMC spec --- .../plugins/psuutil.py | 89 ++++++++++--------- 1 file changed, 45 insertions(+), 44 deletions(-) diff --git a/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py index cc5461ccb5d4..08438f1ca1e9 100644 --- a/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py +++ b/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py @@ -1,67 +1,75 @@ -import os.path -import subprocess -import sys -import re +############################################################################# +# Celestica Blackstone +# +# Platform-specific PSU status interface for SONiC +# provides the followings: +# - Number of PSUs +# - Operational status of PSUs +# - Presence status of PSUs +############################################################################# try: + import sys + import subprocess from sonic_psu.psu_base import PsuBase except ImportError as e: raise ImportError(str(e) + "- required module not found") +# BMC IPMI config +IPMI_RAW_COMMAND = "ipmitool raw" +IPMI_SENSOR_NETFN = "0x04" +IPMI_EVENT_CMD = "0x2b" +IPMI_SENSOR_MAPPING = { + 1: "9", + 2: "10" +} +IPMI_PSU_PRESENCE_BIT = 0 +IPMI_PSU_FAILURE_BIT = 1 +IPMI_PSU_INPUT_LOST_BIT = 3 + +# PSUs config +NUM_OF_PSUS = 2 + class PsuUtil(PsuBase): """Platform-specific PSUutil class""" def __init__(self): - self.ipmi_sensor = "ipmitool sensor" PsuBase.__init__(self) - def run_command(self, command): - proc = subprocess.Popen(command, shell=True, universal_newlines=True, stdout=subprocess.PIPE) + def _run_command(self, command): + proc = subprocess.Popen( + command, shell=True, universal_newlines=True, stdout=subprocess.PIPE) (out, err) = proc.communicate() - if proc.returncode != 0: + print("PSUutil Error: cannot get PSUs data from BMC") sys.exit(proc.returncode) return out - def find_value(self, grep_string): - result = re.search(".+\| (0x\d{2})\d{2}\|.+", grep_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 + return NUM_OF_PSUS def get_psu_status(self, index): """ - Retrieves the oprational status of power supply unit (PSU) defined + Retrieves the operational 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 - - grep_key = "PSUL_Status" if index == 1 else "PSUR_Status" - grep_string = self.run_command(self.ipmi_sensor + ' | grep ' + grep_key) - status_byte = self.find_value(grep_string) + psu_status_cmd = " ".join( + [IPMI_RAW_COMMAND, IPMI_SENSOR_NETFN, IPMI_EVENT_CMD, IPMI_SENSOR_MAPPING.get(index)]) + res = self._run_command(psu_status_cmd) - if status_byte is None: - return False + status_byte = res.split()[1] + failure_detected = (int(status_byte, 16) >> IPMI_PSU_FAILURE_BIT) & 1 + input_lost = (int(status_byte, 16) >> IPMI_PSU_INPUT_LOST_BIT) & 1 - 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 + return False if (failure_detected or input_lost) else True def get_psu_presence(self, index): """ @@ -70,18 +78,11 @@ def get_psu_presence(self, 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 - - grep_key = "PSUL_Status" if index == 1 else "PSUR_Status" - grep_string = self.run_command(self.ipmi_sensor + ' | grep ' + grep_key) - status_byte = self.find_value(grep_string) + psu_status_cmd = " ".join( + [IPMI_RAW_COMMAND, IPMI_SENSOR_NETFN, IPMI_EVENT_CMD, IPMI_SENSOR_MAPPING.get(index)]) - if status_byte is None: - return False + res = self._run_command(psu_status_cmd) + status_byte = res.split()[1] + presence = (int(status_byte, 16) >> IPMI_PSU_PRESENCE_BIT) & 1 - presence = (int(status_byte, 16) >> 0) & 1 - if presence: - return True - else: - return False + return presence or False From c133492866f3978d3b94cec582ca713b0ad4cd53 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 24 Sep 2021 16:44:28 +0700 Subject: [PATCH 14/32] [device/celestica-blackstone]: fix typo on eeprom plugin --- device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py b/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py index 93290ebf82bf..49a1f7d01a0a 100644 --- a/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py +++ b/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py @@ -1,5 +1,5 @@ ############################################################################# -# Celestica Seastone2 +# Celestica Blackstone # # Platform and model specific eeprom subclass, inherits from the base class, # and provides the followings: From 4d90910d30bdf13bd2312e57b3c17fe193cea42a Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Mon, 27 Sep 2021 15:02:01 +0700 Subject: [PATCH 15/32] [platform/cel-blackstone]: Update FPGA driver follow FPGA rev0.2 spec --- .../blackstone/modules/cls-fpga.c | 75 +++++-------------- 1 file changed, 20 insertions(+), 55 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c index e818c4ff2df0..e43920247de3 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c @@ -469,134 +469,99 @@ MODULE_PARM_DESC(bus_clock_master_19, "I2C master 19 bus speed in KHz 50/80/100/200/400"); /* RESOURCE SEPERATES BY FUNCTION */ -/* Resource IOMEM for i2c bus 1 for SFP1*/ +/* Resource IOMEM for i2c bus 1 for FPGA_BMC_I2C1*/ static struct resource cls_i2c_res_1[] = { { .start = 0x800, .end = 0x81F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 2 for SFP2*/ +/* Resource IOMEM for i2c bus 2 for FPGA_BMC_I2C2*/ static struct resource cls_i2c_res_2[] = { { .start = 0x820, .end = 0x83F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 3 for PCA9548*/ +/* Resource IOMEM for i2c bus 3 for FPGA_BMC_I2C3*/ static struct resource cls_i2c_res_3[] = { { .start = 0x840, .end = 0x85F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 4 for MISC CPLD1/CPLD2*/ +/* Resource IOMEM for i2c bus 4 for FPGA_BMC_I2C4*/ static struct resource cls_i2c_res_4[] = { { .start = 0x860, .end = 0x87F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 5 for SYS CPLD*/ +/* Resource IOMEM for i2c bus 5 for FPGA_BMC_I2C5*/ static struct resource cls_i2c_res_5[] = { { .start = 0x880, .end = 0x89F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 6 for PCA9548*/ +/* Resource IOMEM for i2c bus 6 for FPGA_SW_PORT_I2C0*/ static struct resource cls_i2c_res_6[] = { { .start = 0x8A0, .end = 0x8BF, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 7 for PSU*/ +/* Resource IOMEM for i2c bus 7 for FPGA_BMC_I2C7*/ static struct resource cls_i2c_res_7[] = { { .start = 0x8C0, .end = 0x8DF, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 8 for FAN*/ +/* Resource IOMEM for i2c bus 8 for FPGA_BMC_I2C8*/ static struct resource cls_i2c_res_8[] = { { .start = 0x8E0, .end = 0x8FF, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 9 for PCA9548*/ +/* Resource IOMEM for i2c bus 9 for FPGA_BMC_I2C9*/ static struct resource cls_i2c_res_9[] = { { .start = 0x900, .end = 0x91F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 10 for LM75B*/ +/* Resource IOMEM for i2c bus 10 for MISC_CPLD1_I2C*/ static struct resource cls_i2c_res_10[] = { { .start = 0x920, .end = 0x93F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 11 for si5395B*/ +/* Resource IOMEM for i2c bus 11 for MISC_CPLD2_I2C*/ static struct resource cls_i2c_res_11[] = { { .start = 0x940, .end = 0x95F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 12 for EEPROM, PCIE CLK BUF*/ +/* Resource IOMEM for i2c bus 12 for FPGA_SW_PORT_I2C1*/ static struct resource cls_i2c_res_12[] = { { .start = 0x960, .end = 0x97F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 13 for VDDCORE_12V_DCDC*/ +/* Resource IOMEM for i2c bus 13 for FPGA_SFPP_0_I2C*/ static struct resource cls_i2c_res_13[] = { { .start = 0x980, .end = 0x99F, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 14 for ...*/ +/* Resource IOMEM for i2c bus 14 for FPGA_SFPP_1_I2C*/ static struct resource cls_i2c_res_14[] = { { .start = 0x9A0, .end = 0x9BF, .flags = IORESOURCE_MEM,}, }; -/* Resource IOMEM for i2c bus 15 for ...*/ -static struct resource cls_i2c_res_15[] = { - { - .start = 0x9C0, .end = 0x9DF, - .flags = IORESOURCE_MEM,}, -}; - -/* Resource IOMEM for i2c bus 16 for ...*/ -static struct resource cls_i2c_res_16[] = { - { - .start = 0x9E0, .end = 0x9FF, - .flags = IORESOURCE_MEM,}, -}; - -/* Resource IOMEM for i2c bus 17 for ...*/ -static struct resource cls_i2c_res_17[] = { - { - .start = 0xA00, .end = 0xA1F, - .flags = IORESOURCE_MEM,}, -}; - -/* Resource IOMEM for i2c bus 18 for ...*/ -static struct resource cls_i2c_res_18[] = { - { - .start = 0xA20, .end = 0xA3F, - .flags = IORESOURCE_MEM,}, -}; - -/* Resource IOMEM for i2c bus 19 for ...*/ -static struct resource cls_i2c_res_19[] = { - { - .start = 0xA40, .end = 0xA5F, - .flags = IORESOURCE_MEM,}, -}; - /* Resource IOMEM for reg access */ static struct resource reg_io_res[] = { { @@ -626,7 +591,7 @@ static struct resource xcvr_res[] = { */ static struct i2c_bus_config i2c_bus_configs[] = { { - .id = 10, + .id = 6, .res = cls_i2c_res_10, .num_res = ARRAY_SIZE(cls_i2c_res_10), .pdata = { @@ -640,7 +605,7 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 11, + .id = 10, .res = cls_i2c_res_11, .num_res = ARRAY_SIZE(cls_i2c_res_11), .pdata = { @@ -654,7 +619,7 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 14, + .id = 11, .res = cls_i2c_res_14, .num_res = ARRAY_SIZE(cls_i2c_res_14), .pdata = { @@ -668,7 +633,7 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 15, + .id = 12, .res = cls_i2c_res_15, .num_res = ARRAY_SIZE(cls_i2c_res_15), .pdata = { @@ -682,7 +647,7 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 18, + .id = 13, .res = cls_i2c_res_18, .num_res = ARRAY_SIZE(cls_i2c_res_18), .pdata = { @@ -696,7 +661,7 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, }, { - .id = 19, + .id = 14, .res = cls_i2c_res_19, .num_res = ARRAY_SIZE(cls_i2c_res_19), .pdata = { From 487f0b8476ead8e51c8405244b19ed53a3838b4c Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Mon, 27 Sep 2021 15:13:26 +0700 Subject: [PATCH 16/32] [platform/cel-blackstone]: fix invalid param in FPGA driver --- .../blackstone/modules/cls-fpga.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c index e43920247de3..d03fd25ebcf2 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c @@ -592,8 +592,8 @@ static struct resource xcvr_res[] = { static struct i2c_bus_config i2c_bus_configs[] = { { .id = 6, - .res = cls_i2c_res_10, - .num_res = ARRAY_SIZE(cls_i2c_res_10), + .res = cls_i2c_res_6, + .num_res = ARRAY_SIZE(cls_i2c_res_6), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -606,8 +606,8 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, { .id = 10, - .res = cls_i2c_res_11, - .num_res = ARRAY_SIZE(cls_i2c_res_11), + .res = cls_i2c_res_10, + .num_res = ARRAY_SIZE(cls_i2c_res_10), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -620,8 +620,8 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, { .id = 11, - .res = cls_i2c_res_14, - .num_res = ARRAY_SIZE(cls_i2c_res_14), + .res = cls_i2c_res_11, + .num_res = ARRAY_SIZE(cls_i2c_res_11), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -634,8 +634,8 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, { .id = 12, - .res = cls_i2c_res_15, - .num_res = ARRAY_SIZE(cls_i2c_res_15), + .res = cls_i2c_res_12, + .num_res = ARRAY_SIZE(cls_i2c_res_12), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -648,8 +648,8 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, { .id = 13, - .res = cls_i2c_res_18, - .num_res = ARRAY_SIZE(cls_i2c_res_18), + .res = cls_i2c_res_13, + .num_res = ARRAY_SIZE(cls_i2c_res_13), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, @@ -662,8 +662,8 @@ static struct i2c_bus_config i2c_bus_configs[] = { }, { .id = 14, - .res = cls_i2c_res_19, - .num_res = ARRAY_SIZE(cls_i2c_res_19), + .res = cls_i2c_res_14, + .num_res = ARRAY_SIZE(cls_i2c_res_14), .pdata = { .reg_shift = OCORE_REGSHIFT, .reg_io_width = OCORE_REG_IO_WIDTH, From 62e65801b8ee5063a49bbda39f7cdad8cb86fe6f Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Mon, 27 Sep 2021 15:28:17 +0700 Subject: [PATCH 17/32] [platform/cel-blackstone]: fix invalid buses in FPGA driver --- .../blackstone/modules/cls-fpga.c | 40 ------------------- 1 file changed, 40 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c index d03fd25ebcf2..b7b5e495ece7 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c @@ -443,31 +443,6 @@ module_param(bus_clock_master_14, int, 0660); MODULE_PARM_DESC(bus_clock_master_14, "I2C master 14 bus speed in KHz 50/80/100/200/400"); -static int bus_clock_master_15 = 100; -module_param(bus_clock_master_15, int, 0660); -MODULE_PARM_DESC(bus_clock_master_15, - "I2C master 15 bus speed in KHz 50/80/100/200/400"); - -static int bus_clock_master_16 = 100; -module_param(bus_clock_master_16, int, 0660); -MODULE_PARM_DESC(bus_clock_master_16, - "I2C master 16 bus speed in KHz 50/80/100/200/400"); - -static int bus_clock_master_17 = 100; -module_param(bus_clock_master_17, int, 0660); -MODULE_PARM_DESC(bus_clock_master_17, - "I2C master 17 bus speed in KHz 50/80/100/200/400"); - -static int bus_clock_master_18 = 100; -module_param(bus_clock_master_18, int, 0660); -MODULE_PARM_DESC(bus_clock_master_18, - "I2C master 18 bus speed in KHz 50/80/100/200/400"); - -static int bus_clock_master_19 = 100; -module_param(bus_clock_master_19, int, 0660); -MODULE_PARM_DESC(bus_clock_master_19, - "I2C master 19 bus speed in KHz 50/80/100/200/400"); - /* RESOURCE SEPERATES BY FUNCTION */ /* Resource IOMEM for i2c bus 1 for FPGA_BMC_I2C1*/ static struct resource cls_i2c_res_1[] = { @@ -884,21 +859,6 @@ static int cls_fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) case 14: i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_14; break; - case 15: - i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_15; - break; - case 16: - i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_16; - break; - case 17: - i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_17; - break; - case 18: - i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_18; - break; - case 19: - i2c_bus_configs[i].pdata.bus_khz = bus_clock_master_19; - break; default: i2c_bus_configs[i].pdata.bus_khz = OCORE_BUS_CLK_khz; } From f7b0da150ed163029a9e52d56f75d3cc750ba07c Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Mon, 27 Sep 2021 15:52:15 +0700 Subject: [PATCH 18/32] [platform/cel-blackstone]: update init script to enable i2c mapping --- .../debian/platform-modules-blackstone.init | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index d1c7ab6f1f74..d820789c076d 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -37,26 +37,26 @@ start) decode-syseeprom --init 2> /dev/null & # Attach switchboard CPLD i2c device - # echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-4/new_device + echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-3/new_device + + # Attach QSFP-DD i2c devices + echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device + echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-1/new_device + echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-4/new_device + echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-4/new_device # Attach Optical Module EEPROM # use optoe2 for SFP+. - # for i in {1..2} - # do - # echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device - # done - - # Attach QSFP-DD i2c devices - # echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-3/new_device - # echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-3/new_device - # echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-6/new_device - # echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-6/new_device + for i in {5..6} + do + echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device + done # use optoe3 for QSFP-DD. - # for i in {7..38} - # do - # echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device - # done + for i in {7..38} + do + echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device + done #/bin/sh /usr/local/bin/platform_api_mgnt.sh init From 118fa0254fc753708eba8fb9511975898bfbffaf Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 28 Sep 2021 11:48:46 +0700 Subject: [PATCH 19/32] [device/celestica-blackstone]: disable cpld2 in switch cpld driver --- .../blackstone/modules/switch_cpld.c | 152 +++++++++--------- 1 file changed, 76 insertions(+), 76 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c index 3a1b7669547f..885670bbbfa7 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c @@ -2,8 +2,6 @@ * switch_cpld.c - i2c driver for Blackstone DP switchboard CPLD1/CPLD2 * provides sysfs interfaces to access CPLD register and control port LEDs * - * Author: Budsakol Sirirattanasakul - * * Copyright (C) 2021 Celestica Corp. * * This program is free software; you can redistribute it and/or modify @@ -30,7 +28,7 @@ struct switch_cpld_data { struct mutex lock; struct i2c_client *client; - struct i2c_client *client2; + // struct i2c_client *client2; uint8_t read_addr; }; @@ -142,15 +140,15 @@ static ssize_t port_led_mode_show(struct device *dev, 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; + // 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; + // 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", @@ -165,7 +163,7 @@ static ssize_t port_led_mode_store(struct device *dev, 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; + // struct i2c_client *client2 = data->client2; if (sysfs_streq(buf, "test")) led_mode = 0x01; @@ -179,10 +177,10 @@ static ssize_t port_led_mode_store(struct device *dev, return status; } - status = i2c_smbus_write_byte_data(client2, 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; } @@ -193,15 +191,15 @@ static ssize_t port_led_color_show(struct device *dev, 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; + // 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; + // 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" : @@ -224,7 +222,7 @@ static ssize_t port_led_color_store(struct device *dev, 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; + // struct i2c_client *client2 = data->client2; if (sysfs_streq(buf, "off")) { led_color1 = 0x07; @@ -259,10 +257,10 @@ static ssize_t port_led_color_store(struct device *dev, return status; } - status = i2c_smbus_write_byte_data(client2, LED_TEST, led_color2); - if (status != 0) { - return status; - } + // status = i2c_smbus_write_byte_data(client2, LED_TEST, led_color2); + // if (status != 0) { + // return status; + // } return size; } @@ -286,14 +284,14 @@ static int switch_cpld_probe(struct i2c_client *client, int err; struct switch_cpld_data *drvdata1, *drvdata2; struct device *hwmon_dev1, *hwmon_dev2; - struct i2c_client *client2; + // 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 (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; @@ -326,63 +324,64 @@ static int switch_cpld_probe(struct i2c_client *client, 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; - } + // /* 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; + // goto err_link2; + goto err_link; } return 0; -err_link2: - sysfs_remove_link(&client->dev.kobj, "CPLD2"); +// err_link2: +// sysfs_remove_link(&client->dev.kobj, "CPLD2"); -err_client2: - if (client2) - i2c_unregister_device(client2); +// err_client2: +// if (client2) +// i2c_unregister_device(client2); err_link: sysfs_remove_link(&client->dev.kobj, "CPLD1"); @@ -397,9 +396,9 @@ 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(&data->client->dev.kobj, "CPLD2"); sysfs_remove_link(&client->dev.kobj, "CPLD1"); - i2c_unregister_device(data->client2); + // i2c_unregister_device(data->client2); return 0; } @@ -423,6 +422,7 @@ static struct i2c_driver switch_cpld_driver = { module_i2c_driver(switch_cpld_driver); MODULE_AUTHOR("Budsakol Sirirattanasakul"); +MODULE_AUTHOR("Wirut Getbamrung"); MODULE_DESCRIPTION("Celestica Blackstone Switchboard CPLD driver"); MODULE_VERSION("1.0.0"); MODULE_LICENSE("GPL"); From b580af1e1d250a64c078220b3e02b472a3de13b5 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 28 Sep 2021 14:42:07 +0700 Subject: [PATCH 20/32] [platform/cel-blackstone]: remove unuse command on switch CPLD driver --- .../blackstone/modules/switch_cpld.c | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c index 885670bbbfa7..7dbc529e9e0c 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c @@ -15,18 +15,18 @@ #include #include #include -#include +// #include #include #define CPLD1_ADDR 0x30 -#define CPLD2_ADDR 0x31 +// #define CPLD2_ADDR 0x31 #define SCRATCH_ADDR 0x01 #define LED_OPMODE 0x09 #define LED_TEST 0x0A struct switch_cpld_data { - struct mutex lock; + // struct mutex lock; struct i2c_client *client; // struct i2c_client *client2; uint8_t read_addr; @@ -283,7 +283,7 @@ static int switch_cpld_probe(struct i2c_client *client, { int err; struct switch_cpld_data *drvdata1, *drvdata2; - struct device *hwmon_dev1, *hwmon_dev2; + struct device *hwmon_dev1;//, *hwmon_dev2; // struct i2c_client *client2; // if (client->addr != CPLD1_ADDR) { @@ -305,7 +305,7 @@ static int switch_cpld_probe(struct i2c_client *client, goto exit; } - mutex_init(&drvdata1->lock); + // mutex_init(&drvdata1->lock); drvdata1->client = client; drvdata1->read_addr = 0x00; i2c_set_clientdata(client, drvdata1); @@ -319,10 +319,10 @@ static int switch_cpld_probe(struct i2c_client *client, goto exit; } - err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD1"); - if (err) { - goto exit; - } + // err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD1"); + // if (err) { + // goto exit; + // } // /* CPLD2 */ // drvdata2 = devm_kzalloc(&client->dev, @@ -384,7 +384,7 @@ static int switch_cpld_probe(struct i2c_client *client, // i2c_unregister_device(client2); err_link: - sysfs_remove_link(&client->dev.kobj, "CPLD1"); + sysfs_remove_link(&client->dev.kobj, "CPLD"); exit: dev_err(&client->dev, "probe error %d\n", err); @@ -397,13 +397,13 @@ static int switch_cpld_remove(struct i2c_client *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"); + sysfs_remove_link(&client->dev.kobj, "CPLD"); // i2c_unregister_device(data->client2); return 0; } static const struct i2c_device_id switch_cpld_ids[] = { - { "switch_cpld", 0x30 }, + { "switch_cpld", CPLD1_ADDR }, { } }; From 5aa86cb1a4e654b857ca9179a117b2458fa8b935 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 28 Sep 2021 15:46:17 +0700 Subject: [PATCH 21/32] [platform/cel-blackstone]: remove cpld2 command from switch cpld driver --- .../blackstone/modules/switch_cpld.c | 95 +------------------ 1 file changed, 5 insertions(+), 90 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c index 7dbc529e9e0c..2a2580940c3d 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c @@ -15,7 +15,6 @@ #include #include #include -// #include #include #define CPLD1_ADDR 0x30 @@ -26,9 +25,7 @@ #define LED_TEST 0x0A struct switch_cpld_data { - // struct mutex lock; struct i2c_client *client; - // struct i2c_client *client2; uint8_t read_addr; }; @@ -140,16 +137,11 @@ static ssize_t port_led_mode_show(struct device *dev, 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"); @@ -163,7 +155,6 @@ static ssize_t port_led_mode_store(struct device *dev, 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; @@ -177,11 +168,6 @@ static ssize_t port_led_mode_store(struct device *dev, return status; } - // status = i2c_smbus_write_byte_data(client2, LED_OPMODE, led_mode); - // if (status != 0) { - // return status; - // } - return size; } @@ -191,16 +177,11 @@ static ssize_t port_led_color_show(struct device *dev, 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", @@ -222,7 +203,6 @@ static ssize_t port_led_color_store(struct device *dev, 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; @@ -257,11 +237,6 @@ static ssize_t port_led_color_store(struct device *dev, return status; } - // status = i2c_smbus_write_byte_data(client2, LED_TEST, led_color2); - // if (status != 0) { - // return status; - // } - return size; } @@ -283,15 +258,7 @@ static int switch_cpld_probe(struct i2c_client *client, { 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; - // } + struct device *hwmon_dev1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EPFNOSUPPORT; @@ -305,7 +272,6 @@ static int switch_cpld_probe(struct i2c_client *client, goto exit; } - // mutex_init(&drvdata1->lock); drvdata1->client = client; drvdata1->read_addr = 0x00; i2c_set_clientdata(client, drvdata1); @@ -319,70 +285,21 @@ static int switch_cpld_probe(struct i2c_client *client, 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; - // } + err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD"); + if (err) { + goto exit; + } //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; goto err_link; } 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, "CPLD"); @@ -396,9 +313,7 @@ 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, "CPLD"); - // i2c_unregister_device(data->client2); return 0; } From 93d287bcea8238d955ff692046bbbc08931c1a36 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 28 Sep 2021 16:07:02 +0700 Subject: [PATCH 22/32] [platform/cel-blackstone]: change driver name from switch cpld to misc cpld --- .../blackstone/modules/Makefile | 2 +- .../modules/{switch_cpld.c => misc_cpld.c} | 67 +++++++++---------- .../debian/platform-modules-blackstone.init | 5 +- 3 files changed, 37 insertions(+), 37 deletions(-) rename platform/broadcom/sonic-platform-modules-cel/blackstone/modules/{switch_cpld.c => misc_cpld.c} (80%) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile index 880646de76d9..6db3989ee07e 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/Makefile @@ -1 +1 @@ -obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o switch_cpld.o cls-i2c-ocores.o +obj-m := baseboard-lpc.o mc24lc64t.o cls-fpga.o xcvr-cls.o misc_cpld.o cls-i2c-ocores.o diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c similarity index 80% rename from platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c rename to platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c index 2a2580940c3d..b8e5caeff4f8 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/switch_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c @@ -1,5 +1,5 @@ /* - * switch_cpld.c - i2c driver for Blackstone DP switchboard CPLD1/CPLD2 + * misc_cpld.c - i2c driver for Blackstone MISC CPLD1/CPLD2 * provides sysfs interfaces to access CPLD register and control port LEDs * * Copyright (C) 2021 Celestica Corp. @@ -24,7 +24,7 @@ #define LED_OPMODE 0x09 #define LED_TEST 0x0A -struct switch_cpld_data { +struct misc_cpld_data { struct i2c_client *client; uint8_t read_addr; }; @@ -32,7 +32,7 @@ struct switch_cpld_data { static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int value; @@ -48,7 +48,7 @@ static ssize_t getreg_store(struct device *dev, struct device_attribute *attr, { uint8_t value; ssize_t status; - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); status = kstrtou8(buf, 0, &value); if (status != 0) @@ -64,7 +64,7 @@ static ssize_t setreg_store(struct device *dev, struct device_attribute *attr, { uint8_t addr, value; ssize_t status; - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; char *tok; @@ -91,7 +91,7 @@ static ssize_t setreg_store(struct device *dev, struct device_attribute *attr, static ssize_t scratch_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; int value; @@ -107,7 +107,7 @@ static ssize_t scratch_store(struct device *dev, struct device_attribute *attr, { uint8_t value; ssize_t status; - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client = data->client; status = kstrtou8(buf, 0, &value); @@ -123,19 +123,19 @@ DEVICE_ATTR_RW(getreg); DEVICE_ATTR_WO(setreg); DEVICE_ATTR_RW(scratch); -static struct attribute *switch_cpld_attrs[] = { +static struct attribute *misc_cpld_attrs[] = { &dev_attr_getreg.attr, &dev_attr_setreg.attr, &dev_attr_scratch.attr, NULL, }; -ATTRIBUTE_GROUPS(switch_cpld); +ATTRIBUTE_GROUPS(misc_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 misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client1 = data->client; led_mode_1 = i2c_smbus_read_byte_data(client1, LED_OPMODE); @@ -153,7 +153,7 @@ static ssize_t port_led_mode_store(struct device *dev, { int status; uint8_t led_mode; - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client1 = data->client; if (sysfs_streq(buf, "test")) @@ -175,7 +175,7 @@ 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 misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client1 = data->client; led_color1 = i2c_smbus_read_byte_data(client1, LED_TEST); @@ -201,7 +201,7 @@ static ssize_t port_led_color_store(struct device *dev, { int status; uint8_t led_color1, led_color2; - struct switch_cpld_data *data = dev_get_drvdata(dev); + struct misc_cpld_data *data = dev_get_drvdata(dev); struct i2c_client *client1 = data->client; if (sysfs_streq(buf, "off")) { @@ -253,11 +253,11 @@ static struct attribute_group sff_led_groups = { .attrs = sff_led_attrs, }; -static int switch_cpld_probe(struct i2c_client *client, +static int misc_cpld_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; - struct switch_cpld_data *drvdata1, *drvdata2; + struct misc_cpld_data *drvdata1, *drvdata2; struct device *hwmon_dev1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) @@ -265,7 +265,7 @@ static int switch_cpld_probe(struct i2c_client *client, /* CPLD1 */ drvdata1 = devm_kzalloc(&client->dev, - sizeof(struct switch_cpld_data), GFP_KERNEL); + sizeof(struct misc_cpld_data), GFP_KERNEL); if (!drvdata1) { err = -ENOMEM; @@ -276,16 +276,16 @@ static int switch_cpld_probe(struct i2c_client *client, drvdata1->read_addr = 0x00; i2c_set_clientdata(client, drvdata1); hwmon_dev1 = devm_hwmon_device_register_with_groups(&client->dev, - "CPLD1", + "MISC_CPLD", drvdata1, - switch_cpld_groups); + misc_cpld_groups); if (IS_ERR(hwmon_dev1)) { err = PTR_ERR(hwmon_dev1); goto exit; } - err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "CPLD"); + err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "MISC_CPLD"); if (err) { goto exit; } @@ -301,43 +301,42 @@ static int switch_cpld_probe(struct i2c_client *client, return 0; err_link: - sysfs_remove_link(&client->dev.kobj, "CPLD"); + sysfs_remove_link(&client->dev.kobj, "MISC_CPLD"); exit: dev_err(&client->dev, "probe error %d\n", err); return err; } -static int switch_cpld_remove(struct i2c_client *client) +static int misc_cpld_remove(struct i2c_client *client) { - struct switch_cpld_data *data = i2c_get_clientdata(client); + struct misc_cpld_data *data = i2c_get_clientdata(client); sysfs_remove_group(&client->dev.kobj, &sff_led_groups); - sysfs_remove_link(&client->dev.kobj, "CPLD"); + sysfs_remove_link(&client->dev.kobj, "MISC_CPLD"); return 0; } -static const struct i2c_device_id switch_cpld_ids[] = { - { "switch_cpld", CPLD1_ADDR }, +static const struct i2c_device_id misc_cpld_ids[] = { + { "misc_cpld", CPLD1_ADDR }, { } }; -MODULE_DEVICE_TABLE(i2c, switch_cpld_ids); +MODULE_DEVICE_TABLE(i2c, misc_cpld_ids); -static struct i2c_driver switch_cpld_driver = { +static struct i2c_driver misc_cpld_driver = { .driver = { - .name = "switch_cpld", + .name = "misc_cpld", .owner = THIS_MODULE, }, - .probe = switch_cpld_probe, - .remove = switch_cpld_remove, - .id_table = switch_cpld_ids, + .probe = misc_cpld_probe, + .remove = misc_cpld_remove, + .id_table = misc_cpld_ids, }; -module_i2c_driver(switch_cpld_driver); +module_i2c_driver(misc_cpld_driver); -MODULE_AUTHOR("Budsakol Sirirattanasakul"); MODULE_AUTHOR("Wirut Getbamrung"); -MODULE_DESCRIPTION("Celestica Blackstone Switchboard CPLD driver"); +MODULE_DESCRIPTION("Celestica Blackstone MISC_CPLD driver"); MODULE_VERSION("1.0.0"); MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index d820789c076d..cec5ed415673 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -24,7 +24,7 @@ start) modprobe cls-i2c-ocores modprobe cls-fpga modprobe xcvr-cls - modprobe switch_cpld + modprobe misc_cpld modprobe i2c-mux-pca954x force_deselect_on_exit=1 # Instantiate TLV EEPROM device on I801 bus @@ -37,7 +37,8 @@ start) decode-syseeprom --init 2> /dev/null & # Attach switchboard CPLD i2c device - echo switch_cpld 0x30 > /sys/bus/i2c/devices/i2c-3/new_device + echo misc_cpld 0x30 > /sys/bus/i2c/devices/i2c-2/new_device + echo misc_cpld 0x31 > /sys/bus/i2c/devices/i2c-3/new_device # Attach QSFP-DD i2c devices echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device From 9077d96828443a2c2734a857a0c16f29ec87460e Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Tue, 28 Sep 2021 16:24:43 +0700 Subject: [PATCH 23/32] [platform/cel-blackstone]: remove unused variable in misc cpld driver --- .../sonic-platform-modules-cel/blackstone/modules/misc_cpld.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c index b8e5caeff4f8..8fafb57f6b75 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c @@ -257,7 +257,7 @@ static int misc_cpld_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; - struct misc_cpld_data *drvdata1, *drvdata2; + struct misc_cpld_data *drvdata1; struct device *hwmon_dev1; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) @@ -310,8 +310,6 @@ static int misc_cpld_probe(struct i2c_client *client, static int misc_cpld_remove(struct i2c_client *client) { - struct misc_cpld_data *data = i2c_get_clientdata(client); - sysfs_remove_group(&client->dev.kobj, &sff_led_groups); sysfs_remove_link(&client->dev.kobj, "MISC_CPLD"); return 0; From 656c763373b1c05634f8278cc2d1c6b601b0f262 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 29 Sep 2021 11:04:26 +0700 Subject: [PATCH 24/32] [platform/cel-blackstone]: remove unused coment on misc cpld driver --- .../sonic-platform-modules-cel/blackstone/modules/misc_cpld.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c index 8fafb57f6b75..330c79fe98b6 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c @@ -18,8 +18,6 @@ #include #define CPLD1_ADDR 0x30 -// #define CPLD2_ADDR 0x31 - #define SCRATCH_ADDR 0x01 #define LED_OPMODE 0x09 #define LED_TEST 0x0A @@ -263,7 +261,6 @@ static int misc_cpld_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EPFNOSUPPORT; - /* CPLD1 */ drvdata1 = devm_kzalloc(&client->dev, sizeof(struct misc_cpld_data), GFP_KERNEL); From ba29efbab68073eb8636cd7216b3b6af78fa53ec Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 29 Sep 2021 16:08:47 +0700 Subject: [PATCH 25/32] Revert "[device/celestica-blackstone]: fix typo on eeprom plugin" This reverts commit c133492866f3978d3b94cec582ca713b0ad4cd53. --- device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py b/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py index 49a1f7d01a0a..93290ebf82bf 100644 --- a/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py +++ b/device/celestica/x86_64-cel_seastone_2-r0/plugins/eeprom.py @@ -1,5 +1,5 @@ ############################################################################# -# Celestica Blackstone +# Celestica Seastone2 # # Platform and model specific eeprom subclass, inherits from the base class, # and provides the followings: From 775b3ff735c69c0d60d9d663b02736e7982aaede Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 29 Sep 2021 16:09:45 +0700 Subject: [PATCH 26/32] Revert "[device/celestica-blackstone]: update psuutil follow BMC spec" This reverts commit 318b145879e5dd518346095393aa92846c290c00. --- .../plugins/psuutil.py | 89 +++++++++---------- 1 file changed, 44 insertions(+), 45 deletions(-) diff --git a/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py index 08438f1ca1e9..cc5461ccb5d4 100644 --- a/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py +++ b/device/celestica/x86_64-cel_seastone_2-r0/plugins/psuutil.py @@ -1,75 +1,67 @@ -############################################################################# -# Celestica Blackstone -# -# Platform-specific PSU status interface for SONiC -# provides the followings: -# - Number of PSUs -# - Operational status of PSUs -# - Presence status of PSUs -############################################################################# +import os.path +import subprocess +import sys +import re try: - import sys - import subprocess from sonic_psu.psu_base import PsuBase except ImportError as e: raise ImportError(str(e) + "- required module not found") -# BMC IPMI config -IPMI_RAW_COMMAND = "ipmitool raw" -IPMI_SENSOR_NETFN = "0x04" -IPMI_EVENT_CMD = "0x2b" -IPMI_SENSOR_MAPPING = { - 1: "9", - 2: "10" -} -IPMI_PSU_PRESENCE_BIT = 0 -IPMI_PSU_FAILURE_BIT = 1 -IPMI_PSU_INPUT_LOST_BIT = 3 - -# PSUs config -NUM_OF_PSUS = 2 - class PsuUtil(PsuBase): """Platform-specific PSUutil class""" def __init__(self): + self.ipmi_sensor = "ipmitool sensor" PsuBase.__init__(self) - def _run_command(self, command): - proc = subprocess.Popen( - command, shell=True, universal_newlines=True, stdout=subprocess.PIPE) + def run_command(self, command): + proc = subprocess.Popen(command, shell=True, universal_newlines=True, stdout=subprocess.PIPE) (out, err) = proc.communicate() + if proc.returncode != 0: - print("PSUutil Error: cannot get PSUs data from BMC") sys.exit(proc.returncode) return out + def find_value(self, grep_string): + result = re.search(".+\| (0x\d{2})\d{2}\|.+", grep_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 NUM_OF_PSUS + return 2 def get_psu_status(self, index): """ - Retrieves the operational status of power supply unit (PSU) defined + 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 """ - psu_status_cmd = " ".join( - [IPMI_RAW_COMMAND, IPMI_SENSOR_NETFN, IPMI_EVENT_CMD, IPMI_SENSOR_MAPPING.get(index)]) - res = self._run_command(psu_status_cmd) + if index is None: + return False + + grep_key = "PSUL_Status" if index == 1 else "PSUR_Status" + grep_string = self.run_command(self.ipmi_sensor + ' | grep ' + grep_key) + status_byte = self.find_value(grep_string) - status_byte = res.split()[1] - failure_detected = (int(status_byte, 16) >> IPMI_PSU_FAILURE_BIT) & 1 - input_lost = (int(status_byte, 16) >> IPMI_PSU_INPUT_LOST_BIT) & 1 + if status_byte is None: + return False - return False if (failure_detected or input_lost) else True + 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): """ @@ -78,11 +70,18 @@ def get_psu_presence(self, 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 """ - psu_status_cmd = " ".join( - [IPMI_RAW_COMMAND, IPMI_SENSOR_NETFN, IPMI_EVENT_CMD, IPMI_SENSOR_MAPPING.get(index)]) + if index is None: + return False + + grep_key = "PSUL_Status" if index == 1 else "PSUR_Status" + grep_string = self.run_command(self.ipmi_sensor + ' | grep ' + grep_key) + status_byte = self.find_value(grep_string) - res = self._run_command(psu_status_cmd) - status_byte = res.split()[1] - presence = (int(status_byte, 16) >> IPMI_PSU_PRESENCE_BIT) & 1 + if status_byte is None: + return False - return presence or False + presence = (int(status_byte, 16) >> 0) & 1 + if presence: + return True + else: + return False From d8bf94e695517186506e1d5cbe352546e6c1bf57 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 29 Sep 2021 16:12:22 +0700 Subject: [PATCH 27/32] [device/celestica-blackstone]: update psuutil follow lastest BMC spec --- .../plugins/psuutil.py | 94 ++++++++----------- 1 file changed, 41 insertions(+), 53 deletions(-) diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py index bca8076c4512..08438f1ca1e9 100644 --- a/device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/psuutil.py @@ -1,80 +1,75 @@ -#!/usr/bin/env python - ############################################################################# # Celestica Blackstone # -# Platform and model specific psu subclass, inherits from the base class, -# and provides the followings: -# - psuutil numpsus -# - psuutil status +# Platform-specific PSU status interface for SONiC +# provides the followings: +# - Number of PSUs +# - Operational status of PSUs +# - Presence status of PSUs ############################################################################# -import os.path -import subprocess -import sys -import re - try: + import sys + import subprocess from sonic_psu.psu_base import PsuBase except ImportError as e: raise ImportError(str(e) + "- required module not found") +# BMC IPMI config +IPMI_RAW_COMMAND = "ipmitool raw" +IPMI_SENSOR_NETFN = "0x04" +IPMI_EVENT_CMD = "0x2b" +IPMI_SENSOR_MAPPING = { + 1: "9", + 2: "10" +} +IPMI_PSU_PRESENCE_BIT = 0 +IPMI_PSU_FAILURE_BIT = 1 +IPMI_PSU_INPUT_LOST_BIT = 3 + +# PSUs config +NUM_OF_PSUS = 2 + class PsuUtil(PsuBase): """Platform-specific PSUutil class""" def __init__(self): - self.ipmi_raw = "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, universal_newlines=True, stdout=subprocess.PIPE) + def _run_command(self, command): + proc = subprocess.Popen( + command, shell=True, universal_newlines=True, stdout=subprocess.PIPE) (out, err) = proc.communicate() - if proc.returncode != 0: + print("PSUutil Error: cannot get PSUs data from BMC") 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 + return NUM_OF_PSUS def get_psu_status(self, index): """ - Retrieves the oprational status of power supply unit (PSU) defined + Retrieves the operational 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_status_cmd = " ".join( + [IPMI_RAW_COMMAND, IPMI_SENSOR_NETFN, IPMI_EVENT_CMD, IPMI_SENSOR_MAPPING.get(index)]) + res = self._run_command(psu_status_cmd) - 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) + status_byte = res.split()[1] + failure_detected = (int(status_byte, 16) >> IPMI_PSU_FAILURE_BIT) & 1 + input_lost = (int(status_byte, 16) >> IPMI_PSU_INPUT_LOST_BIT) & 1 - 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 + return False if (failure_detected or input_lost) else True def get_psu_presence(self, index): """ @@ -83,18 +78,11 @@ def get_psu_presence(self, 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) + psu_status_cmd = " ".join( + [IPMI_RAW_COMMAND, IPMI_SENSOR_NETFN, IPMI_EVENT_CMD, IPMI_SENSOR_MAPPING.get(index)]) - if status_byte is None: - return False + res = self._run_command(psu_status_cmd) + status_byte = res.split()[1] + presence = (int(status_byte, 16) >> IPMI_PSU_PRESENCE_BIT) & 1 - presence = (int(status_byte, 16) >> 0) & 1 - if presence: - return True - else: - return False + return presence or False From 58b2cfac32addcb502c5b8143b7091d732953c19 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Thu, 7 Oct 2021 14:58:19 +0700 Subject: [PATCH 28/32] [device/celestica]: remove unuse files in plugin --- .../plugins/helper.py | 70 ------------------- .../plugins/platform.py | 23 ------ 2 files changed, 93 deletions(-) delete mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py delete mode 100644 device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py deleted file mode 100644 index 9377fa85b69f..000000000000 --- a/device/celestica/x86_64-cel_blackstone-r0/plugins/helper.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/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 diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py deleted file mode 100644 index a632de87e742..000000000000 --- a/device/celestica/x86_64-cel_blackstone-r0/plugins/platform.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/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() From c3b379f0e7c1f14643f04ed7412ef93f230ae381 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 27 Oct 2021 15:07:10 +0700 Subject: [PATCH 29/32] [platform/cel-blackstone]: update misc cpld name device name * [platform/cel-blackstone]: update misc_cpld device name * [platform/cel-blackstone]: update misc_cpld driver version * [platform/cel-blackstone]: update misc_cpld init command --- .../blackstone/modules/misc_cpld.c | 37 +++++++++++++------ .../debian/platform-modules-blackstone.init | 4 +- 2 files changed, 27 insertions(+), 14 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c index 330c79fe98b6..9cfc43d5de9d 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/misc_cpld.c @@ -18,6 +18,7 @@ #include #define CPLD1_ADDR 0x30 +#define CPLD2_ADDR 0x31 #define SCRATCH_ADDR 0x01 #define LED_OPMODE 0x09 #define LED_TEST 0x0A @@ -25,6 +26,7 @@ struct misc_cpld_data { struct i2c_client *client; uint8_t read_addr; + const char *link_name; }; static ssize_t getreg_show(struct device *dev, struct device_attribute *attr, @@ -256,7 +258,13 @@ static int misc_cpld_probe(struct i2c_client *client, { int err; struct misc_cpld_data *drvdata1; - struct device *hwmon_dev1; + struct device *hwmon_dev; + char *device_name; + + device_name = "CPLD1"; + if(id->driver_data == CPLD2_ADDR){ + device_name = "CPLD2"; + } if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -EPFNOSUPPORT; @@ -271,18 +279,19 @@ static int misc_cpld_probe(struct i2c_client *client, drvdata1->client = client; drvdata1->read_addr = 0x00; + drvdata1->link_name = device_name; i2c_set_clientdata(client, drvdata1); - hwmon_dev1 = devm_hwmon_device_register_with_groups(&client->dev, - "MISC_CPLD", + hwmon_dev = devm_hwmon_device_register_with_groups(&client->dev, + device_name, drvdata1, misc_cpld_groups); - if (IS_ERR(hwmon_dev1)) { - err = PTR_ERR(hwmon_dev1); + if (IS_ERR(hwmon_dev)) { + err = PTR_ERR(hwmon_dev); goto exit; } - err = sysfs_create_link(&client->dev.kobj, &hwmon_dev1->kobj, "MISC_CPLD"); + err = sysfs_create_link(&client->dev.kobj, &hwmon_dev->kobj, device_name); if (err) { goto exit; } @@ -298,7 +307,7 @@ static int misc_cpld_probe(struct i2c_client *client, return 0; err_link: - sysfs_remove_link(&client->dev.kobj, "MISC_CPLD"); + sysfs_remove_link(&client->dev.kobj, device_name); exit: dev_err(&client->dev, "probe error %d\n", err); @@ -307,14 +316,18 @@ static int misc_cpld_probe(struct i2c_client *client, static int misc_cpld_remove(struct i2c_client *client) { + struct misc_cpld_data *data = dev_get_drvdata(&client->dev); + char *device_name = data->link_name; + sysfs_remove_group(&client->dev.kobj, &sff_led_groups); - sysfs_remove_link(&client->dev.kobj, "MISC_CPLD"); + sysfs_remove_link(&client->dev.kobj, device_name); return 0; } static const struct i2c_device_id misc_cpld_ids[] = { - { "misc_cpld", CPLD1_ADDR }, - { } + { "misc_cpld1", CPLD1_ADDR }, + { "misc_cpld2", CPLD2_ADDR }, + {} }; MODULE_DEVICE_TABLE(i2c, misc_cpld_ids); @@ -333,5 +346,5 @@ module_i2c_driver(misc_cpld_driver); MODULE_AUTHOR("Wirut Getbamrung"); MODULE_DESCRIPTION("Celestica Blackstone MISC_CPLD driver"); -MODULE_VERSION("1.0.0"); -MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0.1"); +MODULE_LICENSE("GPL"); \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index cec5ed415673..42bfea0caad8 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -37,8 +37,8 @@ start) decode-syseeprom --init 2> /dev/null & # Attach switchboard CPLD i2c device - echo misc_cpld 0x30 > /sys/bus/i2c/devices/i2c-2/new_device - echo misc_cpld 0x31 > /sys/bus/i2c/devices/i2c-3/new_device + echo misc_cpld1 0x30 > /sys/bus/i2c/devices/i2c-10/new_device + echo misc_cpld2 0x31 > /sys/bus/i2c/devices/i2c-11/new_device # Attach QSFP-DD i2c devices echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device From 1cafe0365ead1303bab5cfc08512438e1ef301c8 Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Wed, 27 Oct 2021 15:15:24 +0700 Subject: [PATCH 30/32] [platform/cel-blackstone]: update FPGA driver to support BMC I2C * [platform/cel-blackstone]: update FPGA driver to support BMC I2C * [platform/cel-blackstone]: update i2c devices driver init command --- .../blackstone/modules/cls-fpga.c | 112 ++++++++++++++++++ .../debian/platform-modules-blackstone.init | 12 +- 2 files changed, 118 insertions(+), 6 deletions(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c index b7b5e495ece7..af1f34517eb0 100644 --- a/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c +++ b/platform/broadcom/sonic-platform-modules-cel/blackstone/modules/cls-fpga.c @@ -565,6 +565,76 @@ static struct resource xcvr_res[] = { * these buses need to be uninitialized because it interfere the BMC activity */ 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 = 0, + .devices = NULL, + }, + }, + { + .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, + }, + }, { .id = 6, .res = cls_i2c_res_6, @@ -579,6 +649,48 @@ static struct i2c_bus_config i2c_bus_configs[] = { .devices = NULL, }, }, + { + .id = 7, + .res = cls_i2c_res_7, + .num_res = ARRAY_SIZE(cls_i2c_res_7), + .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 = 8, + .res = cls_i2c_res_8, + .num_res = ARRAY_SIZE(cls_i2c_res_8), + .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 = 9, + .res = cls_i2c_res_9, + .num_res = ARRAY_SIZE(cls_i2c_res_9), + .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 = 10, .res = cls_i2c_res_10, diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index 42bfea0caad8..fb62e869edd1 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -41,20 +41,20 @@ start) echo misc_cpld2 0x31 > /sys/bus/i2c/devices/i2c-11/new_device # Attach QSFP-DD i2c devices - echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-1/new_device - echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-1/new_device - echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-4/new_device - echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-4/new_device + echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-6/new_device + echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-6/new_device + echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-12/new_device + echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-12/new_device # Attach Optical Module EEPROM # use optoe2 for SFP+. - for i in {5..6} + for i in {13..14} do echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done # use optoe3 for QSFP-DD. - for i in {7..38} + for i in {15..46} do echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done From cb591d2d88ac54ec3fc3e40a75fb866b68bf2cdf Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Fri, 5 Nov 2021 15:22:06 +0700 Subject: [PATCH 31/32] [device/celestica-blackstone]: Platform API code initialization * [device/celestica-blackstone]: update necessary chassis apis * [platform/cel-blackstone]: add platform api installer * [platform/cel]: update missing apis installer command * [device/celestica-blackstone]: update sfputil follow hw spec * [device/celestica-blackstone]: update skip_syseepromd config for pmon --- .../plugins/sfputil.py | 197 ++++--------- .../pmon_daemon_control.json | 2 +- .../sonic_platform/chassis.py | 274 +++++++++--------- .../sonic_platform/eeprom.py | 2 +- .../debian/platform-modules-blackstone.init | 2 +- .../platform-modules-blackstone.install | 3 + .../platform-modules-blackstone.postinst | 2 +- 7 files changed, 199 insertions(+), 283 deletions(-) diff --git a/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py b/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py index 08a66786d680..c93d01d685b3 100644 --- a/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py +++ b/device/celestica/x86_64-cel_blackstone-r0/plugins/sfputil.py @@ -8,74 +8,27 @@ # - sfputil show presence ############################################################################# -try: - from sonic_eeprom import eeprom_tlvinfo -except ImportError as 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) - try: import time + from os import path from sonic_sfp.sfputilbase import SfpUtilBase except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) + raise ImportError('%s - required module not found' % str(e)) class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" + '''Platform-specific SfpUtil class''' PORT_START = 1 - PORT_END = 33 - QSFP_PORT_START = 1 - QSFP_PORT_END = 32 + PORT_END = 32 - EEPROM_OFFSET = 1 - PORT_INFO_PATH = '/sys/devices/platform/cls-xcvr' + QSFPDD_PORT_START = 1 + QSFPDD_PORT_END = 32 + EEPROM_OFFSET = 15 - _port_name = "" + PORT_INFO_PATH = '/sys/devices/platform/cls-xcvr' _port_to_eeprom_mapping = {} - _port_to_i2cbus_mapping = { - 1: 17, - 2: 18, - 3: 15, - 4: 16, - 5: 21, - 6: 20, - 7: 38, - 8: 19, - 9: 35, - 10: 34, - 11: 37, - 12: 33, - 13: 32, - 14: 36, - 15: 22, - 16: 31, - 17: 24, - 18: 30, - 19: 27, - 20: 23, - 21: 28, - 22: 25, - 23: 12, - 24: 29, - 25: 26, - 26: 13, - 27: 7, - 28: 14, - 29: 9, - 30: 11, - 31: 10, - 32: 8, - 33: 1, - 34: 2 - } + _port_to_i2cbus_mapping = {} @property def port_start(self): @@ -85,13 +38,9 @@ def port_start(self): def port_end(self): return self.PORT_END - @property - def qsfp_ports(self): - return [] - @property def osfp_ports(self): - return list(range(self.QSFP_PORT_START, self.QSFP_PORT_END + 1)) + return list(range(self.QSFPDD_PORT_START, self.QSFPDD_PORT_END + 1)) @property def port_to_eeprom_mapping(self): @@ -102,28 +51,36 @@ 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.QSFP_PORT_START + 1) - else: - self._port_name = "SFP" + str(port_num) - return self._port_name - - # def get_eeprom_dom_raw(self, port_num): - # if port_num in self.osfp_ports: - # # QSFP DOM EEPROM is also at addr 0x50 and thus also stored in eeprom_ifraw - # return None - # else: - # # Read dom eeprom at addr 0x51 - # return self._read_eeprom_devid(port_num, self.DOM_EEPROM_ADDR, 256) + return 'QSFPDD{}'.format(port_num) if port_num in self.osfp_ports else 'SFP+{}' + str(port_num - self.QSFPDD_PORT_END) def __init__(self): # Override port_to_eeprom_mapping for class initialization eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' for x in range(self.PORT_START, self.PORT_END+1): - self.port_to_eeprom_mapping[x] = eeprom_path.format(self.port_to_i2cbus_mapping[x]) + self.port_to_i2cbus_mapping[x] = (x + self.EEPROM_OFFSET) - 1 + self.port_to_eeprom_mapping[x] = eeprom_path.format( + self.port_to_i2cbus_mapping[x]) SfpUtilBase.__init__(self) + def _read_val(self, path): + ret = '' + try: + with open(path, 'r') as f: + ret = f.readline() + except IOError as e: + print('Error: unable to open file: %s' % str(e)) + return ret + + def _write_val(self, path, val): + try: + with open(path, 'w') as f: + f.write(val) + except IOError as e: + print('Error: unable to write file: %s' % str(e)) + return False + return True + def get_presence(self, port_num): # Check for invalid port_num @@ -132,104 +89,58 @@ def get_presence(self, port_num): # Get path for access port presence status port_name = self.get_port_name(port_num) - sysfs_filename = "qsfp_modprsL" if port_num in self.osfp_ports else "sfp_modabs" - reg_path = "/".join([self.PORT_INFO_PATH, port_name, sysfs_filename]) + sysfs_filename = 'qsfp_modprsL' if port_num in self.osfp_ports else 'sfp_modabs' # 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 + status = self._read_val(path.join( + self.PORT_INFO_PATH, port_name, sysfs_filename)) # Module present is active low - if reg_value == 0: - return True - - return False + return True if int(status) == 0 else False def get_low_power_mode(self, port_num): - # Check for invalid QSFP port_num - if port_num not in self.osfp_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)) + # Check for invalid QSFP-DD port_num + if port_num not in self.osfp_ports: return False # Read status - content = reg_file.readline().rstrip() - reg_value = int(content, 16) - # ModPrsL is active low - if reg_value == 0: - return False + port_name = self.get_port_name(port_num) + status = self._read_val(path.join( + self.PORT_INFO_PATH, port_name, 'qsfp_lpmode')) - return True + # LPmode is active high + return True if int(status, 16) == 1 else False def set_low_power_mode(self, port_num, lpmode): - # Check for invalid QSFP port_num - if port_num not in self.osfp_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)) + # Check for invalid QSFP-DD port_num + if port_num not in self.osfp_ports: return False - content = hex(lpmode) - - reg_file.seek(0) - reg_file.write(content) - reg_file.close() - - return True + return self._write_val(path.join(self.PORT_INFO_PATH, self.get_port_name(port_num), 'qsfp_lpmode'), hex(lpmode)) def reset(self, port_num): - # Check for invalid QSFP port_num + + # Check for invalid QSFP-DD port_num if port_num not in self.osfp_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 + sysfs_path = path.join(self.PORT_INFO_PATH, + self.get_port_name(port_num), 'qsfp_resetL') - # Convert our register value back to a hex string and write back - reg_file.seek(0) - reg_file.write(hex(0)) - reg_file.close() + self._write_val(sysfs_path, hex(0)) # 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() + self._write_val(sysfs_path, hex(1)) return True def get_transceiver_change_event(self, timeout=0): - """ + ''' TBD: When the feature request. - """ + ''' raise NotImplementedError diff --git a/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json b/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json index 1bf19bb80fa1..e7bc43133fe7 100644 --- a/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json +++ b/device/celestica/x86_64-cel_blackstone-r0/pmon_daemon_control.json @@ -3,7 +3,7 @@ "skip_ledd": true, "skip_pcied": true, "skip_psud": true, - "skip_syseepromd": true, + "skip_syseepromd": false, "skip_thermalctld": true, "skip_xcvrd": true } \ No newline at end of file diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py index 8a9ed17139df..96c3c3343206 100644 --- a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/chassis.py @@ -7,6 +7,7 @@ ############################################################################# try: + import os import sys from sonic_platform_base.chassis_base import ChassisBase from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper @@ -16,18 +17,19 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -NUM_FAN_TRAY = 5 -NUM_PSU = 2 -NUM_THERMAL = 5 -NUM_SFP = 32 -NUM_COMPONENT = 5 -RESET_REGISTER = "0x103" -HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +# NUM_FAN_TRAY = 5 +# NUM_PSU = 2 +# NUM_THERMAL = 5 +# NUM_SFP = 32 +# NUM_COMPONENT = 5 + +SYS_CPLD_PLATFORM = "/sys/devices/platform/sys_cpld" +RESET_SOURCE_FILE = "reboot_cause" +GETREG_FILE = "getreg" +STATUS_LED_COLOR_FILE = "sys_led_color" + +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause" REBOOT_CAUSE_FILE = "reboot-cause.txt" -PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" -GETREG_PATH = "/sys/devices/platform/dx010_cpld/getreg" -HOST_CHK_CMD = "docker > /dev/null 2>&1" -STATUS_LED_PATH = "/sys/devices/platform/leds_dx010/leds/dx010:green:stat/brightness" class Chassis(ChassisBase): @@ -36,62 +38,62 @@ class Chassis(ChassisBase): def __init__(self): ChassisBase.__init__(self) self._api_helper = APIHelper() - self.sfp_module_initialized = False self.__initialize_eeprom() - self.is_host = self._api_helper.is_host() - - self.__initialize_fan() - self.__initialize_psu() - self.__initialize_thermals() - self.__initialize_components() - - def __initialize_sfp(self): - sfputil_helper = SfpUtilHelper() - port_config_file_path = device_info.get_path_to_port_config_file() - sfputil_helper.read_porttab_mappings(port_config_file_path, 0) - - from sonic_platform.sfp import Sfp - for index in range(0, NUM_SFP): - sfp = Sfp(index, sfputil_helper.logical[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_drawer import FanDrawer - for i in range(NUM_FAN_TRAY): - fandrawer = FanDrawer(i) - self._fan_drawer_list.append(fandrawer) - self._fan_list.extend(fandrawer._fan_list) - - def __initialize_thermals(self): - from sonic_platform.thermal import Thermal - airflow = self.__get_air_flow() - for index in range(0, NUM_THERMAL): - thermal = Thermal(index, airflow) - self._thermal_list.append(thermal) + + # self.is_host = self._api_helper.is_host() + # self.sfp_module_initialized = False + # self.__initialize_fan() + # self.__initialize_psu() + # self.__initialize_thermals() + # self.__initialize_components() def __initialize_eeprom(self): from sonic_platform.eeprom import Tlv self._eeprom = Tlv() - 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_air_flow(self): - air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format( - self._api_helper.platform) \ - if self.is_host else '/usr/share/sonic/platform/fan_airflow' - air_flow = self._api_helper.read_one_line_file(air_flow_path) - return air_flow or 'B2F' + # def __initialize_sfp(self): + # sfputil_helper = SfpUtilHelper() + # port_config_file_path = device_info.get_path_to_port_config_file() + # sfputil_helper.read_porttab_mappings(port_config_file_path, 0) + + # from sonic_platform.sfp import Sfp + # for index in range(0, NUM_SFP): + # sfp = Sfp(index, sfputil_helper.logical[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_drawer import FanDrawer + # for i in range(NUM_FAN_TRAY): + # fandrawer = FanDrawer(i) + # self._fan_drawer_list.append(fandrawer) + # self._fan_list.extend(fandrawer._fan_list) + + # def __initialize_thermals(self): + # from sonic_platform.thermal import Thermal + # airflow = self.__get_air_flow() + # for index in range(0, NUM_THERMAL): + # thermal = Thermal(index, airflow) + # self._thermal_list.append(thermal) + + # 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_air_flow(self): + # air_flow_path = '/usr/share/sonic/device/{}/fan_airflow'.format( + # self._api_helper.platform) \ + # if self.is_host else '/usr/share/sonic/platform/fan_airflow' + # air_flow = self._api_helper.read_one_line_file(air_flow_path) + # return air_flow or 'B2F' def get_base_mac(self): """ @@ -132,58 +134,62 @@ def get_reboot_cause(self): REBOOT_CAUSE_NON_HARDWARE = "Non-Hardware" """ - reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + reboot_cause_path = os.path.join( + HOST_REBOOT_CAUSE_PATH, REBOOT_CAUSE_FILE) + hw_reboot_cause_path = os.path.join( + SYS_CPLD_PLATFORM, RESET_SOURCE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( reboot_cause_path) or "Unknown" - hw_reboot_cause = self._api_helper.get_cpld_reg_value( - GETREG_PATH, RESET_REGISTER) + hw_reboot_cause = self._api_helper.read_txt_file( + hw_reboot_cause_path) prev_reboot_cause = { - '0x11': (self.REBOOT_CAUSE_POWER_LOSS, 'Power on reset'), - '0x22': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPLD_WD_RESET'), - '0x33': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by CPU'), - '0x44': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Power cycle reset triggered by reset button'), - '0x55': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, ''), - '0x66': (self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC, ''), - '0x77': (self.REBOOT_CAUSE_WATCHDOG, '') + 'POR': (self.REBOOT_CAUSE_POWER_LOSS, 'Power on reset'), + 'soft-warm-rst': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Soft-set CPU warm reset'), + 'soft-cold-rst': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Soft-set CPU cold reset'), + 'warm-rst': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPU warm reset'), + 'cold-rst': (self.REBOOT_CAUSE_HARDWARE_OTHER, 'CPU cold reset'), + 'wdt-rst': (self.REBOOT_CAUSE_WATCHDOG, 'Watchdog reset'), + 'power-cycle': (self.REBOOT_CAUSE_WATCHDOG, 'Power cycle reset') }.get(hw_reboot_cause, (self.REBOOT_CAUSE_HARDWARE_OTHER, 'Unknown reason')) - if sw_reboot_cause != 'Unknown' and hw_reboot_cause == '0x11': + if sw_reboot_cause != 'Unknown' and hw_reboot_cause == 'POR': prev_reboot_cause = ( self.REBOOT_CAUSE_NON_HARDWARE, sw_reboot_cause) return prev_reboot_cause - def get_change_event(self, timeout=0): - """ - Returns a nested dictionary containing all devices which have - experienced a change at chassis level - Args: - timeout: Timeout in milliseconds (optional). If timeout == 0, - this method will block until a change is detected. - Returns: - (bool, dict): - - True if call successful, False if not; - - A nested dictionary where key is a device type, - value is a dictionary with key:value pairs in the format of - {'device_id':'device_event'}, - where device_id is the device ID for this device and - device_event, - status='1' represents device inserted, - status='0' represents device removed. - Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} - indicates that fan 0 has been removed, fan 2 - has been inserted and sfp 11 has been removed. - """ - # SFP event - if not self.sfp_module_initialized: - self.__initialize_sfp() - - sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) - if sfp_event: - return True, {'sfp': sfp_event} - - return False, {'sfp': {}} + # def get_change_event(self, timeout=0): + # """ + # Returns a nested dictionary containing all devices which have + # experienced a change at chassis level + # Args: + # timeout: Timeout in milliseconds (optional). If timeout == 0, + # this method will block until a change is detected. + # Returns: + # (bool, dict): + # - True if call successful, False if not; + # - A nested dictionary where key is a device type, + # value is a dictionary with key:value pairs in the format of + # {'device_id':'device_event'}, + # where device_id is the device ID for this device and + # device_event, + # status='1' represents device inserted, + # status='0' represents device removed. + # Ex. {'fan':{'0':'0', '2':'1'}, 'sfp':{'11':'0'}} + # indicates that fan 0 has been removed, fan 2 + # has been inserted and sfp 11 has been removed. + # """ + # # SFP event + # if not self.sfp_module_initialized: + # self.__initialize_sfp() + + # sfp_event = SfpEvent(self._sfp_list).get_sfp_event(timeout) + # if sfp_event: + # return True, {'sfp': sfp_event} + + # return False, {'sfp': {}} ############################################################## ######################## SFP methods ######################### @@ -239,22 +245,22 @@ def get_sfp(self, index): ####################### 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() + # 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 + # return self._watchdog - def get_thermal_manager(self): - from .thermal_manager import ThermalManager - return ThermalManager + # def get_thermal_manager(self): + # from .thermal_manager import ThermalManager + # return ThermalManager ############################################################## ###################### Device methods ######################## @@ -319,34 +325,30 @@ def is_replaceable(self): def set_status_led(self, color): """ - Sets the state of the PSU status LED + Sets the state of the system LED Args: - color: A string representing the color with which to set the PSU status LED - Note: Only support green and off + color: A string representing the color with which to set the + system LED Returns: - bool: True if status LED state is set successfully, False if not - """ + bool: True if system LED state is set successfully, False if not - set_status_str = { - self.STATUS_LED_COLOR_GREEN: '1', - self.STATUS_LED_COLOR_OFF: '0' - }.get(color, None) + """ + color = str(color).lower() + status_led_path = os.path.join( + SYS_CPLD_PLATFORM, STATUS_LED_COLOR_FILE) - if not set_status_str: + if color not in ["yellow", "green", "both"]: return False - return self._api_helper.write_txt_file(STATUS_LED_PATH, set_status_str) + return self._api_helper.write_txt_file(status_led_path, color) def get_status_led(self): """ - Gets the state of the PSU status LED + Gets the state of the system LED Returns: - A string, one of the predefined STATUS_LED_COLOR_* strings above + A string, one of the valid LED color strings which could be vendor + specified. """ - status = self._api_helper.read_txt_file(STATUS_LED_PATH) - status_str = { - '255': self.STATUS_LED_COLOR_GREEN, - '0': self.STATUS_LED_COLOR_OFF - }.get(status, None) - - return status_str + status_led_path = os.path.join( + SYS_CPLD_PLATFORM, STATUS_LED_COLOR_FILE) + return self._api_helper.read_txt_file(status_led_path) or "Unknown" diff --git a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py index b0d37d57beac..dba1c031fef7 100644 --- a/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py +++ b/device/celestica/x86_64-cel_blackstone-r0/sonic_platform/eeprom.py @@ -31,7 +31,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder): EEPROM_DECODE_HEADLINES = 6 def __init__(self): - self._eeprom_path = "/sys/class/i2c-adapter/i2c-12/12-0050/eeprom" + self._eeprom_path = "/sys/class/i2c-adapter/i2c-0/0-0056/eeprom" super(Tlv, self).__init__(self._eeprom_path, 0, '', True) self._eeprom = self._load_eeprom() diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init index fb62e869edd1..4ec18b8d594e 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.init @@ -59,7 +59,7 @@ start) echo optoe3 0x50 > /sys/bus/i2c/devices/i2c-$i/new_device done - #/bin/sh /usr/local/bin/platform_api_mgnt.sh init + /bin/sh /usr/local/bin/platform_api_mgnt.sh init echo "done." ;; diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install index 352cccdc37e8..f97b2d3f1fd3 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.install @@ -2,3 +2,6 @@ blackstone/scripts/sensors usr/bin blackstone/scripts/platform_sensors.py usr/local/bin blackstone/cfg/blackstone-modules.conf etc/modules-load.d blackstone/systemd/platform-modules-blackstone.service lib/systemd/system +blackstone/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-cel_blackstone-r0 +blackstone/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/x86_64-cel_blackstone-r0 +services/platform_api/platform_api_mgnt.sh usr/local/bin \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst index 5c2c96e6b9de..ef73d4538105 100644 --- a/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst +++ b/platform/broadcom/sonic-platform-modules-cel/debian/platform-modules-blackstone.postinst @@ -2,4 +2,4 @@ depmod -a systemctl enable platform-modules-blackstone.service systemctl start platform-modules-blackstone.service - +/usr/local/bin/platform_api_mgnt.sh install \ No newline at end of file From 490756db8a1f256102e458fb1ac8c755f6e32cdd Mon Sep 17 00:00:00 2001 From: Wirut Getbamrung Date: Thu, 11 Nov 2021 17:38:35 +0700 Subject: [PATCH 32/32] [platform/cel-blackstone]: initialize platform APIs * [device/celestica-blackstone]: update necessary chassis apis * [platform/cel-blackstone]: add platform api installer * [platform/cel]: update missing apis installer command * [device/celestica-blackstone]: update sfputil follow hw spec * [device/celestica-blackstone]: update skip_syseepromd config for pmon * [platform/cel]: update api installer script --- .../services/platform_api/platform_api_mgnt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh index 208c8696c4b3..aa10c70dd35d 100755 --- a/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh +++ b/platform/broadcom/sonic-platform-modules-cel/services/platform_api/platform_api_mgnt.sh @@ -10,7 +10,7 @@ PY3_PACK=$DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl install() { # Install python2.7 sonic-platform package if [ -e $PY2_PACK ]; then - pip install $PY2_PACK + pip2 install $PY2_PACK fi # Install python3 sonic-platform package