From 13bd63e73a4bad961e9b32f0dec11459fd0f2958 Mon Sep 17 00:00:00 2001 From: arunlk-dell <83708154+arunlk-dell@users.noreply.github.com> Date: Fri, 26 Aug 2022 05:37:23 +0530 Subject: [PATCH] DellEMC: S5296F Platform API 2.0 changes (#11162) Why I did it S5296F - Platform API 2.0 changes How I did it Implemented the functional API's needed for Platform API 2.0 How to verify it Used the API 2.0 test suite to validate the test cases. --- .../platform.json | 578 ++++++++++++++++++ .../pmon_daemon_control.json | 7 +- .../debian/platform-modules-s5296f.install | 1 + .../sonic-platform-modules-dell/debian/rules | 10 + .../s5296f/modules/dell_s5296f_fpga_ocores.c | 519 ++++++---------- .../s5296f/setup.py | 1 + .../s5296f/sonic_platform/__init__.py | 3 + .../s5296f/sonic_platform/chassis.py | 453 ++++++++++++++ .../s5296f/sonic_platform/component.py | 233 +++++++ .../s5296f/sonic_platform/eeprom.py | 133 ++++ .../s5296f/sonic_platform/fan.py | 214 +++++++ .../s5296f/sonic_platform/fan_drawer.py | 110 ++++ .../s5296f/sonic_platform/hwaccess.py | 1 + .../sonic_platform/media_settings_plugin.py | 13 + .../s5296f/sonic_platform/platform.py | 24 + .../s5296f/sonic_platform/psu.py | 325 ++++++++++ .../s5296f/sonic_platform/sfp.py | 367 +++++++++++ .../s5296f/sonic_platform/thermal.py | 189 ++++++ .../s5296f/sonic_platform/watchdog.py | 207 +++++++ 19 files changed, 3052 insertions(+), 336 deletions(-) create mode 100644 device/dell/x86_64-dellemc_s5296f_c3538-r0/platform.json create mode 120000 platform/broadcom/sonic-platform-modules-dell/s5296f/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/chassis.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/component.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/eeprom.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan_drawer.py create mode 120000 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/hwaccess.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/media_settings_plugin.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/platform.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/psu.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/sfp.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/thermal.py create mode 100644 platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/watchdog.py diff --git a/device/dell/x86_64-dellemc_s5296f_c3538-r0/platform.json b/device/dell/x86_64-dellemc_s5296f_c3538-r0/platform.json new file mode 100644 index 0000000000..b38f625d62 --- /dev/null +++ b/device/dell/x86_64-dellemc_s5296f_c3538-r0/platform.json @@ -0,0 +1,578 @@ +{ + "chassis": { + "name": "S5296F-ON", + "status_led": { + "controllable": true, + "colors": ["green", "flashing green", "yellow", "flashing yellow"] + }, + "thermal_manager" : false, + "components": [ + { + "name": "BIOS" + }, + { + "name": "FPGA" + }, + { + "name": "BMC" + }, + { + "name": "System CPLD" + }, + { + "name": "Secondary CPLD 1" + }, + { + "name": "Secondary CPLD 2" + }, + { + "name": "Secondary CPLD 3" + }, + { + "name": "Secondary CPLD 4" + } + ], + "fans": [ + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray2-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray3-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + }, + { + "name": "FanTray4-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray1-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray2-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray3", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray3-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray4", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FanTray4-Fan1", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU1 Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "PSU2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU2 Fan", + "speed": { + "controllable": false + }, + "status_led": { + "available": false + } + } + ] + } + ], + "thermals": [ + { + "name": "ASIC On-board", + "controllable": false, + "low-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "CPU On-board", + "controllable": false, + "low-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "Inlet Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "high-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PSU1 Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "high-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PSU1 Sensor", + "controllable": false, + "low-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PSU2 Airflow Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "high-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PSU2 Sensor", + "controllable": false, + "low-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PT Left Sensor", + "controllable": false, + "low-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PT Middle Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "high-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + }, + { + "name": "PT Right Sensor", + "controllable": false, + "low-crit-threshold": false, + "high-threshold": false, + "high-crit-threshold": false, + "minimum-recorded": false, + "maximum-recorded": false + } + ], + "modules": [], + "sfps": [ + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "SFP/SFP+/SFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + }, + { + "name": "QSFP28" + } + ] + }, + "interfaces": {} +} diff --git a/device/dell/x86_64-dellemc_s5296f_c3538-r0/pmon_daemon_control.json b/device/dell/x86_64-dellemc_s5296f_c3538-r0/pmon_daemon_control.json index 72ef3c2210..94592fa8ce 100644 --- a/device/dell/x86_64-dellemc_s5296f_c3538-r0/pmon_daemon_control.json +++ b/device/dell/x86_64-dellemc_s5296f_c3538-r0/pmon_daemon_control.json @@ -1,8 +1,3 @@ { - "skip_sensors": true, - "skip_fancontrol": true, - "skip_ledd": true, - "skip_psud": true, - "skip_syseepromd": true, - "skip_thermalctld": true + "skip_ledd": true } diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5296f.install b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5296f.install index 497554a476..f102aa9e31 100644 --- a/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5296f.install +++ b/platform/broadcom/sonic-platform-modules-dell/debian/platform-modules-s5296f.install @@ -4,6 +4,7 @@ s5296f/scripts/sensors usr/bin s5296f/scripts/pcisysfs.py usr/bin s5296f/cfg/s5296f-modules.conf etc/modules-load.d s5296f/systemd/platform-modules-s5296f.service etc/systemd/system +s5296f/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_s5296f_c3538-r0 common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5296f_c3538-r0 common/fw-updater usr/local/bin common/onie_mode_set usr/local/bin diff --git a/platform/broadcom/sonic-platform-modules-dell/debian/rules b/platform/broadcom/sonic-platform-modules-dell/debian/rules index 421057fdac..871bab3a46 100755 --- a/platform/broadcom/sonic-platform-modules-dell/debian/rules +++ b/platform/broadcom/sonic-platform-modules-dell/debian/rules @@ -55,6 +55,11 @@ override_dh_auto_build: cd $(MOD_SRC_DIR)/$${mod}; \ python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ cd $(MOD_SRC_DIR); \ + elif [ $$mod = "s5296f" ]; then \ + cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ + cd $(MOD_SRC_DIR); \ elif [ $$mod = "n3248te" ]; then \ cd $(MOD_SRC_DIR)/$${mod}; \ python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \ @@ -143,6 +148,11 @@ override_dh_clean: rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \ rm -rf $(MOD_SRC_DIR)/$${mod}/build; \ rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \ + elif [ $$mod = "s5296f" ]; then \ + rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ + rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/build; \ + rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \ elif [ $$mod = "z9332f" ]; then \ rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \ rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \ diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/modules/dell_s5296f_fpga_ocores.c b/platform/broadcom/sonic-platform-modules-dell/s5296f/modules/dell_s5296f_fpga_ocores.c index 0673d6e9d0..d2bb1b6f76 100644 --- a/platform/broadcom/sonic-platform-modules-dell/s5296f/modules/dell_s5296f_fpga_ocores.c +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/modules/dell_s5296f_fpga_ocores.c @@ -89,7 +89,7 @@ struct fpgapci_dev { unsigned int irq_first; unsigned int irq_length; unsigned int irq_assigned; - unsigned int xcvr_intr_count; + }; static int use_irq = 1; @@ -107,6 +107,13 @@ MODULE_PARM_DESC(num_bus, /* Subsystem: Xilinx Corporation Device 0007 */ //#define VENDOR 0x10EE #define DEVICE 0x7021 + +/* Altera FPGA PCIE info: + Unassigned class [ff00]: Altera Corporation Device 0004 (rev 01) + Subsystem: Altera Corporation Device 0004 */ +#define PCI_VENDOR_ID_ALTERA 0x1172 +#define PCI_DEVICE_ID_ALTERA 0x0004 + static phys_addr_t fpga_phys_addr; typedef signed char s8; @@ -190,7 +197,7 @@ struct fpgalogic_i2c { #define FPGAI2C_REG_STAT_NACK 0x80 /* SR[7:0] - Status register */ -#define FPGAI2C_REG_SR_RXACK (1 << 7) /* Receive acknowledge from slave ‘1’ = No acknowledge received*/ +#define FPGAI2C_REG_SR_RXACK (1 << 7) /* Receive acknowledge from secondary �1� = No acknowledge received*/ #define FPGAI2C_REG_SR_BUSY (1 << 6) /* Busy, I2C bus busy (as defined by start / stop bits) */ #define FPGAI2C_REG_SR_AL (1 << 5) /* Arbitration lost - fpga i2c logic lost arbitration */ #define FPGAI2C_REG_SR_TIP (1 << 1) /* Transfer in progress */ @@ -227,13 +234,6 @@ enum { #define I2C_PCI_BUS_NUM_12 12 #define I2C_PCI_BUS_NUM_16 16 -#define IRQ_LTCH_STS 0x20 -#define PRSNT_LTCH_STS 0x10 - -#define PORT_CTRL_OFFSET 0x4000 -#define PORT_STS_OFFSET 0x4004 -#define PORT_IRQ_STS_OFFSET 0x4008 -#define PORT_IRQ_EN_OFFSET 0x400C #define MB_BRD_REV_TYPE 0x0008 #define MB_BRD_REV_MASK 0x00f0 #define MB_BRD_REV_00 0x0000 @@ -256,7 +256,7 @@ enum { #define BRD_TYPE_S5232_NON_NEBS 0xc #define BRD_TYPE_S5232_NEBS 0xd -#define FPGA_CTL_REG_SIZE 0x6000 +#define FPGA_CTL_REG_SIZE 0x60 #define MSI_VECTOR_MAP_MASK 0x1f #define MSI_VECTOR_MAP1 0x58 #define I2C_CH1_MSI_MAP_VECT_8 0x00000008 @@ -292,8 +292,6 @@ enum { #define MSI_VECTOR_REV_00 16 #define MSI_VECTOR_REV_01 32 -#define FPGA_MSI_VECTOR_ID_4 4 -#define FPGA_MSI_VECTOR_ID_5 5 #define FPGA_MSI_VECTOR_ID_8 8 #define FPGA_MSI_VECTOR_ID_9 9 #define FPGA_MSI_VECTOR_ID_10 10 @@ -312,7 +310,7 @@ enum { #define FPGA_MSI_VECTOR_ID_23 23 #define FPGA_MSI_VECTOR_ID_24 24 - +#define MAX_WAIT_LOOP 10 static int total_i2c_pci_bus = 0; static uint32_t board_rev_type = 0; @@ -431,7 +429,7 @@ static int fpgai2c_poll(struct fpgalogic_i2c *i2c) } /* Error? */ - if (stat & FPGAI2C_REG_STAT_ARBLOST) { + if ((stat & FPGAI2C_REG_STAT_ARBLOST) || ( i2c->msg == NULL) || ( i2c->msg->buf == NULL)) { i2c->state = STATE_ERROR; fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_STOP); return -EAGAIN; @@ -516,72 +514,6 @@ static int fpgai2c_poll(struct fpgalogic_i2c *i2c) return 0; } -static ssize_t get_mod_msi(struct device *dev, struct device_attribute *devattr, char *buf) -{ - int ind = 0, port_status=0, port_irq_status=0; - struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(dev); - PRINT("%s:xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); - for(ind=0;ind<64;ind++) - { - port_status = ioread32(fpga_ctl_addr + PORT_STS_OFFSET + (ind*16)); - port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); - PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); - } - return sprintf(buf,"0x%04x\n",fpgapci->xcvr_intr_count); -} -static DEVICE_ATTR(port_msi, S_IRUGO, get_mod_msi, NULL); - -static struct attribute *port_attrs[] = { - &dev_attr_port_msi.attr, - NULL, -}; - -static struct attribute_group port_attr_grp = { - .attrs = port_attrs, -}; - - -static irqreturn_t fpgaport_1_32_isr(int irq, void *dev) -{ - struct pci_dev *pdev = dev; - struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); - int ind = 0, port_status=0, port_irq_status=0; - for(ind=0;ind<32;ind++) - { - port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); - if(port_irq_status&(IRQ_LTCH_STS|PRSNT_LTCH_STS)) - { - PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); - //write on clear - iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); - } - } - fpgapci->xcvr_intr_count++; - PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); - sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); - return IRQ_HANDLED; -} - -static irqreturn_t fpgaport_33_64_isr(int irq, void *dev) -{ - struct pci_dev *pdev = dev; - struct fpgapci_dev *fpgapci = (struct fpgapci_dev*) dev_get_drvdata(&pdev->dev); - int ind = 0, port_status=0, port_irq_status=0; - for(ind=32;ind<64;ind++) - { - port_irq_status = ioread32(fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); - if(port_irq_status| (IRQ_LTCH_STS|PRSNT_LTCH_STS)) - { - PRINT("%s:port:%d, port_status:%#x, port_irq_status:%#x\n", __FUNCTION__, ind, port_status, port_irq_status); - iowrite32( IRQ_LTCH_STS|PRSNT_LTCH_STS,fpga_ctl_addr + PORT_IRQ_STS_OFFSET + (ind*16)); - } - } - fpgapci->xcvr_intr_count++; - PRINT("%s: xcvr_intr_count:%u\n", __FUNCTION__, fpgapci->xcvr_intr_count); - sysfs_notify(&pdev->dev.kobj, NULL, "port_msi"); - return IRQ_HANDLED; -} - static void fpgai2c_process(struct fpgalogic_i2c *i2c) { struct i2c_msg *msg = i2c->msg; @@ -610,6 +542,12 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c) return; } + /* Spurious IRQs would lead to invocation of handler with msg being NULL. + * Skip handling them. + */ + if (msg == NULL) + return; + if ((i2c->state == STATE_START) || (i2c->state == STATE_WRITE)) { i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; @@ -621,6 +559,11 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c) } } else { + if(( i2c->msg == NULL) || ( i2c->msg->buf == NULL) || (i2c->pos >= i2c->msg->len) ) { + printk("crash debug..1 fpgai2c_process MSG and MAS->BUFF is NULL or pos > len "); + return; + } + msg->buf[i2c->pos++] = fpgai2c_reg_get(i2c, FPGAI2C_REG_DATA); } @@ -657,12 +600,25 @@ static void fpgai2c_process(struct fpgalogic_i2c *i2c) } if (i2c->state == STATE_READ) { + + if(( i2c->msg == NULL) || ( i2c->msg->buf == NULL) || (i2c->pos >= i2c->msg->len) ) { + printk("crash debug..2 fpgai2c_process MSG and MAS->BUFF is NULL or pos > len "); + return; + } + + PRINT("fpgai2c_poll STATE_READ i2c->pos=%d msg->len-1 = 0x%x set FPGAI2C_REG_CMD = 0x%x\n",i2c->pos, msg->len-1, - i2c->pos == (msg->len-1) ? FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + i2c->pos == (msg->len-1) ? FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, i2c->pos == (msg->len-1) ? - FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); + FPGAI2C_REG_CMD_READ_NACK : FPGAI2C_REG_CMD_READ_ACK); } else { PRINT("fpgai2c_process set FPGAI2C_REG_DATA(0x%x)\n",FPGAI2C_REG_DATA); + + if(( i2c->msg == NULL) || ( i2c->msg->buf == NULL) || (i2c->pos >= i2c->msg->len) ) { + printk("crash debug..3 fpgai2c_process MSG and MAS->BUFF is NULL or pos > len "); + return; + } + fpgai2c_reg_set(i2c, FPGAI2C_REG_DATA, msg->buf[i2c->pos++]); fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_WRITE); } @@ -745,7 +701,7 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c) { int prescale; int diff; - u8 ctrl; + u8 ctrl = 0, stat, loop = 0; if (i2c->reg_io_width == 0) i2c->reg_io_width = 1; /* Set to default value */ @@ -776,9 +732,7 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c) } } - ctrl = fpgai2c_reg_get(i2c, FPGAI2C_REG_CONTROL); - - PRINT("%s(), line:%d\n", __func__, __LINE__); + PRINT("%s(), line:%d\n", __func__, __LINE__); PRINT("i2c->base = 0x%p\n",i2c->base); PRINT("ctrl = 0x%x\n",ctrl); @@ -806,12 +760,23 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c) fpgai2c_reg_set(i2c, FPGAI2C_REG_PREHIGH, prescale >> 8); /* Init the device */ - fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); - if (!use_irq) - fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_EN); - else - fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_IEN | FPGAI2C_REG_CTRL_EN); - + fpgai2c_reg_set(i2c, FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_EN); + if (use_irq) { + /* Clear any pending interrupts */ + fpgai2c_reg_set(i2c, FPGAI2C_REG_CMD, FPGAI2C_REG_CMD_IACK); + while (loop < MAX_WAIT_LOOP) { + stat = fpgai2c_reg_get(i2c, FPGAI2C_REG_STATUS); + if (stat & FPGAI2C_REG_STAT_IF) { + udelay(100); + loop++; + } else { + break; + } + } + if (loop >=10) { + printk("interrupts can't be cleared: loop %d\n", loop); + } + } fpgai2c_dump(i2c); /* Initialize interrupt handlers if not already done */ @@ -820,6 +785,17 @@ static int fpgai2c_init(struct fpgalogic_i2c *i2c) return 0; } +static int fpgai2c_interrupt_enable(struct fpgapci_dev *fpgapci) +{ + int i; + u8 ctrl = 0; + + /* Enable Interrupts */ + for (i = 0 ; i < total_i2c_pci_bus; i ++) { + fpgai2c_reg_set(&fpgalogic_i2c[i], FPGAI2C_REG_CONTROL, ctrl | FPGAI2C_REG_CTRL_IEN | FPGAI2C_REG_CTRL_EN); + } + return 0; +} static u32 fpgai2c_func(struct i2c_adapter *adap) { @@ -861,56 +837,17 @@ static int i2c_init_internal_data(void) } -static int i2c_pci_init (void) +static int i2c_pci_init (struct fpgapci_dev *fpgapci) { int i; - if (num_bus == 0) { - board_rev_type = ioread32(fpga_ctl_addr + MB_BRD_REV_TYPE); - - if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { - num_bus = I2C_PCI_MAX_BUS_REV00; - } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || - ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || - ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { - switch (board_rev_type & MB_BRD_TYPE_MASK){ - case BRD_TYPE_S5212_NON_NEBS: - case BRD_TYPE_S5212_NEBS: - num_bus = I2C_PCI_BUS_NUM_5; - break; - case BRD_TYPE_S5224_NON_NEBS: - case BRD_TYPE_S5224_NEBS: - num_bus = I2C_PCI_BUS_NUM_7; - break; - case BRD_TYPE_Z9232_NON_NEBS: - case BRD_TYPE_Z9232_NEBS: - case BRD_TYPE_S5232_NON_NEBS: - case BRD_TYPE_S5232_NEBS: - num_bus = I2C_PCI_BUS_NUM_8; - break; - case BRD_TYPE_S5248_NON_NEBS: - case BRD_TYPE_S5248_NEBS: - num_bus = I2C_PCI_BUS_NUM_10; - break; - case BRD_TYPE_Z9264_NON_NEBS: - case BRD_TYPE_Z9264_NEBS: - num_bus = I2C_PCI_BUS_NUM_12; - break; - case BRD_TYPE_S5296_NON_NEBS: - case BRD_TYPE_S5296_NEBS: - num_bus = I2C_PCI_BUS_NUM_16; - break; - default: - num_bus = I2C_PCI_BUS_NUM_16; - printk("Wrong BRD_TYPE: 0x%x\n", board_rev_type); - break; - } + if ((fpgapci != NULL) && (fpgapci->pci_dev->vendor == PCI_VENDOR_ID_ALTERA)) { + num_bus = I2C_PCI_BUS_NUM_10; } else { - printk("Wrong board_rev_type 0x%x\n", board_rev_type); - } - } + num_bus = I2C_PCI_MAX_BUS; + } - printk("board_rev_type 0x%x, num_bus 0x%x\n", board_rev_type, num_bus); + printk("vendor 0x%x, num_bus 0x%x\n", fpgapci->pci_dev->vendor, num_bus); total_i2c_pci_bus = num_bus; memset (&i2c_pci_adap, 0, sizeof(i2c_pci_adap)); @@ -1100,196 +1037,119 @@ static int register_intr_handler(struct pci_dev *dev, int irq_num_id) PRINT ( ": fpgapci_dev is 0\n"); return err; } - - if ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_00) { - /* Request interrupt line for unique function - * alternatively function will be called from free_irq as well - * with flag IRQF_SHARED */ - switch(irq_num_id) { - /* Currently we only support test vector 2 for FPGA Logic I2C channel - * controller 1-7 interrupt*/ - case FPGA_MSI_VECTOR_ID_4: - err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, dev); - PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_5: - err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, dev); - PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_8: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[0]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_9: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[1]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_10: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[2]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_11: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[3]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_12: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[4]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_13: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[5]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_14: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[6]); - fpgapci->irq_assigned++; - break; - - default: - PRINT("No more interrupt handler for number (%d)\n", - dev->irq + irq_num_id); - break; - } - } else if (((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_01) || - ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_02) || - ((board_rev_type & MB_BRD_REV_MASK) == MB_BRD_REV_03)) { /* FPGA SPEC 4.3.1.34, First i2c channel mapped to vector 8 */ switch (irq_num_id) { - case FPGA_MSI_VECTOR_ID_4: - err = request_irq(dev->irq + irq_num_id, fpgaport_1_32_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, dev); - PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_5: - err = request_irq(dev->irq + irq_num_id, fpgaport_33_64_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, dev); - PRINT ( "%d: fpgapci_dev: irq: %d, %d\n", __LINE__, dev->irq, irq_num_id); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_8: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[0]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_9: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[1]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_10: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[2]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_11: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[3]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_12: - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, - FPGA_PCI_NAME, &fpgalogic_i2c[4]); - fpgapci->irq_assigned++; - break; - case FPGA_MSI_VECTOR_ID_13: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[5]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_14: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[6]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_15: - /*it is an external interrupt number. Ignore this case */ - break; - case FPGA_MSI_VECTOR_ID_16: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_7) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[7]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_17: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[8]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_18: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[9]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_19: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[10]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_20: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[11]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_21: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[12]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_22: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[13]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_23: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[14]); - fpgapci->irq_assigned++; - } - break; - case FPGA_MSI_VECTOR_ID_24: - if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { - err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, - IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[15]); - fpgapci->irq_assigned++; - } - break; + case FPGA_MSI_VECTOR_ID_8: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[0]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_9: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[1]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_10: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[2]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_11: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[3]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_12: + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, IRQF_EARLY_RESUME, + FPGA_PCI_NAME, &fpgalogic_i2c[4]); + fpgapci->irq_assigned++; + break; + case FPGA_MSI_VECTOR_ID_13: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[5]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_14: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_5) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[6]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_15: + /*it is an external interrupt number. Ignore this case */ + break; + case FPGA_MSI_VECTOR_ID_16: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_7) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[7]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_17: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[8]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_18: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_8) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[9]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_19: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[10]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_20: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_10) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[11]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_21: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[12]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_22: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[13]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_23: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[14]); + fpgapci->irq_assigned++; + } + break; + case FPGA_MSI_VECTOR_ID_24: + if (total_i2c_pci_bus > I2C_PCI_BUS_NUM_12) { + err = request_irq(dev->irq + irq_num_id, fpgai2c_isr, + IRQF_EARLY_RESUME, FPGA_PCI_NAME, &fpgalogic_i2c[15]); + fpgapci->irq_assigned++; + } + break; - default: - PRINT("No more interrupt handler for number (%d)\n", - dev->irq + irq_num_id); - break; + default: + PRINT("No more interrupt handler for number (%d)\n", + dev->irq + irq_num_id); + break; } - } return err; } @@ -1415,7 +1275,7 @@ static int fpgapci_setup_device(struct fpgapci_dev *fpgapci,struct pci_dev *dev) goto fail_map_bars; } - i2c_pci_init(); + i2c_pci_init(fpgapci); return 0; /* ERROR HANDLING */ @@ -1491,7 +1351,6 @@ error_no_msi: static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) { struct fpgapci_dev *fpgapci = 0; - int status = 0; #ifdef TEST PRINT ( " vendor = 0x%x, device = 0x%x, class = 0x%x, bus:slot.func = %02x:%02x.%02x\n", @@ -1508,11 +1367,6 @@ static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) fpgapci->pci_dev = dev; dev_set_drvdata(&dev->dev, (void*)fpgapci); - status = sysfs_create_group(&dev->dev.kobj, &port_attr_grp); - if (status) { - printk(KERN_INFO "%s:Cannot create sysfs\n", __FUNCTION__); - } - fpgapci->upstream = find_upstream_dev (dev); if(fpgapci_setup_device(fpgapci,dev)) { @@ -1523,6 +1377,9 @@ static int fpgapci_probe(struct pci_dev *dev, const struct pci_device_id *id) if(fpgapci_configure_msi(fpgapci,dev)) { goto error_cannot_configure; } + /* Enable interrupt after config msi */ + fpgai2c_interrupt_enable(fpgapci); + } @@ -1581,6 +1438,7 @@ static void fpgapci_remove(struct pci_dev *dev) static const struct pci_device_id fpgapci_ids[] = { {PCI_DEVICE(PCI_VENDOR_ID_XILINX, DEVICE)}, + {PCI_DEVICE(PCI_VENDOR_ID_ALTERA, PCI_DEVICE_ID_ALTERA)}, {0, }, }; @@ -1624,3 +1482,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("joyce_yu@dell.com"); MODULE_DESCRIPTION ("Driver for FPGA Logic I2C bus"); MODULE_SUPPORTED_DEVICE ("FPGA Logic I2C bus"); +MODULE_VERSION ("01.01"); diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/setup.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/setup.py new file mode 120000 index 0000000000..4f6de9941d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/setup.py @@ -0,0 +1 @@ +../s6100/setup.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/__init__.py new file mode 100644 index 0000000000..28edc0b13f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan","fan_drawer","watchdog"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/chassis.py new file mode 100644 index 0000000000..c981e4bc7a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/chassis.py @@ -0,0 +1,453 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import time + import sys + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.sfp import Sfp + from sonic_platform.eeprom import Eeprom + from sonic_platform.component import Component + from sonic_platform.psu import Psu + from sonic_platform.thermal import Thermal + from sonic_platform.watchdog import Watchdog + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.hwaccess import pci_get_value, pci_set_value +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +MAX_S5296F_COMPONENT = 8 # BIOS,BMC,FPGA,SYSTEM CPLD,4 SECONDARY CPLDs +MAX_S5296F_FANTRAY = 4 +MAX_S5296F_FAN = 1 +MAX_S5296F_PSU = 2 +MAX_S5296F_THERMAL = 10 +SYSTEM_LED_REG = 0x24 +SYSTEM_BEACON_LED_SET = 0x8 +SYSTEM_BEACON_LED_CLEAR = 0xFFFFFFF7 + +media_part_num_list = set([ \ +"8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC", +"C5RNH","5250G","N8TDR","7D64H","7D64H","RN84N","RN84N","HMTNW","6K3Y6","6K3Y6","TY5FM","50M0R","PGYJT","WP2PP","85Y13","1HCGH","FP9R1","FYD0M","C6Y7M","C6Y7M","V250M","V250M", +"5CWK6","5CWK6","53HVN","53HVN","358VV","358VV","MV799","MV799","YJF03","P9GND","T1KCN","1DXKP","MT7R2","K0T7R","W5G04","7TCDN","7TCDN","7TCDN","7TCDN","7TCDN","V3XJK","0MV31", +"5FVP7","N6KM9","C41MF","77KC3","XW7J0","V4NJV","2XJHY","H93DH","H93DH","F8CG0","F8CG0","F8CG0","119N6","WFMF5","794RX","288F6","1M31V","1M31V","5NP8R","5NP8R","4TC09","4TC09", +"FC6KV","FC6KV","J90VN","J90VN","05RH0","05RH0","YDN52","0C2YV","YDN52","0C2YV","9JT65","D7M6H","6GW14","FYVFW","0VF5H","P4YPY","P4YPY","TCPM2","TCPM2","JNPF8","JNPF8","27GG5", +"27GG5","P8T4W","P8T4W","JR54Y","M6N0J","XJYD0","K44H9","035KG","P7C7N","76V43","3CC35","FN4FC","26FN3","YFNDD","YFNDD","7R9N9","035KG","P7C7N","76V43","3CC35","PLRXPLSCS43811", +"FN4FC","26FN3","YFNDD","YFNDD","7R9N9","G86YJ","V407F","V407F","9KH6T","G86YJ","V407F","9KH6T","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY", +"9X8JP","GMFC5","GMFC5","GMFC5","D7P80","3MFXG","3MFXG","0GWXJ","THPF3","THPF3","THPF3","THPF3","THPF3","PJ62G","3XCX1","JJYKG","RRRTK","16K56","86JM2","K5R6C","7MG2C","WTPPN","9HTT2", +"NKM4F","VXGGG","JC9W6","6MR8M","RP3GV","M5PPJ","XKY55","TKCXT","05J8P","5WGKD","XFDRT","NW8DM","YPKH3","5WGKD","XFDRT","NW8DM","YPKH3","71XXK","MVCX6","0XYP6","HPPVW","3GHRT","71XXK", +"MVCX6","0XYP6","HPPVW","3GHRT","2X5T6","135V2","KD5MV","2X5T6","KD5MV","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","3YWG7","5CMT2","RCVP5","X5DH4", +"4WJ41","4WJ41","14NV5","14NV5","14NV5","4WGYD","YKMH7","X7CCC","X7CCC","0X9CT","0CY8V","P7D7R","W4GPP","W4GPP","W4GPP","HHHCHC","07RN7","07RN7","0YR96","0YR96","JCYM9","FTLX8571D3BCL", +"DDW0X","VPFDJ","229KM","9FC7D","DDW0X","VPFDJ","6FMR5","J7K20","N3K9W","6FMR5","8R4VM","7VN5T","D9YM8","8R4VM","VYXPW","87TPX","WY6FK","VYXPW","87TPX","WY6FK","WG8C4","N8K82","2DV6Y", +"77C3C","RC0HM","77C3C","RC0HM","JHXTN","3P3PG","92YVM","4VX5M","4VX5M","6RRGD","W4JWV","22V6R","XR11M","9GMDY","JMCWK","TP2F0","6MGDY","78RHK", "C0TP5","0WDNV","FCLF8522P2BTL"\ +]) + +class Chassis(ChassisBase): + """ + DELLEMC Platform-specific Chassis class + """ + + REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason" + OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi" + PCI_RES = "/sys/bus/pci/devices/0000:04:00.0/resource0" + oir_fd = -1 + + sysled_offset = 0x0024 + SYSLED_COLOR_TO_REG = { + "blinking_green": 0x0, + "green" : 0x10, + "amber" : 0x20, + "blinking_amber": 0x30 + } + + REG_TO_SYSLED_COLOR = { + 0x0 : "blinking_green", + 0x10 : "green", + 0x20 : "amber", + 0x30 : "blinking_amber" + } + + _global_port_pres_dict = {} + + def __init__(self): + ChassisBase.__init__(self) + # sfp.py will read eeprom contents and retrive the eeprom data. + # We pass the eeprom path from chassis.py + self.PORT_START = 1 + self.PORT_END = 104 + self.SFP28_PORT_END = 96 + i2c_bus_for_port = 2 + i2c_mux_to_populate = 603 + i2c_mux_is_good = False + + PORTS_IN_BLOCK = (self.PORT_END + 1) + _sfp_port = range(1, self.SFP28_PORT_END + 1) + eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom" + mux_channel = "/sys/class/i2c-adapter/i2c-{0}/{0}-0074/channel-0" + + for index in range(self.PORT_START, PORTS_IN_BLOCK): + eeprom_path = "" + if index%8 == 1: # 8 buses per i2c mux + i2c_mux_is_good = True if os.path.exists(mux_channel.format(i2c_mux_to_populate)) else False + i2c_mux_to_populate += 1 + if i2c_mux_is_good: + eeprom_path = eeprom_base.format(i2c_bus_for_port) + i2c_bus_for_port += 1 + if index not in _sfp_port: + sfp_node = Sfp(index, 'QSFP', eeprom_path) + else: + sfp_node = Sfp(index, 'SFP', eeprom_path) + self._sfp_list.append(sfp_node) + self._num_sfps = len(self._sfp_list) + + self._eeprom = Eeprom() + + for i in range(MAX_S5296F_THERMAL): + self._thermal_list.append(Thermal(i)) + + for i in range(MAX_S5296F_COMPONENT): + self._component_list.append(Component(i)) + + for i in range(MAX_S5296F_PSU): + self._psu_list.append(Psu(i)) + + for i in range(MAX_S5296F_FANTRAY): + fandrawer = FanDrawer(i) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + self._num_fans = MAX_S5296F_FANTRAY * MAX_S5296F_FAN + + self._watchdog = Watchdog() + + def __del__(self): + if self.oir_fd != -1: + self.epoll.unregister(self.oir_fd.fileno()) + self.epoll.close() + self.oir_fd.close() + +# not needed /delete after validation + + def _get_register(self, reg_file): + retval = 'ERR' + if (not os.path.isfile(reg_file)): + print(reg_file, 'not found !') + return retval + + try: + with os.fdopen(os.open(reg_file, os.O_RDONLY)) as fd: + retval = fd.read() + except Exception as ex: + pass + retval = retval.rstrip('\r\n') + retval = retval.lstrip(" ") + return retval + +# not needed /delete after validation + + def _check_interrupts(self, port_dict): + retval = 0 + is_port_dict_updated = False + for port_num in range(self.PORT_START, (self.PORT_END + 1)): + sfp = self.get_sfp(port_num) + presence = sfp.get_presence() + if(presence and (self._global_port_pres_dict[port_num] == '0')): + is_port_dict_updated = True + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and (self._global_port_pres_dict[port_num] == '1')): + is_port_dict_updated = True + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + return retval, is_port_dict_updated + +# check for this event change for sfp / do we need to handle timeout/sleep + + def get_change_event(self, timeout=0): + """ + Returns a nested dictionary containing all devices which have + experienced a change at chassis level + """ + start_ms = time.time() * 1000 + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + if not self._global_port_pres_dict: + for port_num in self._sfp_port: + presence = self.get_sfp(port_num).get_presence() + self._global_port_pres_dict[port_num] = '1' if presence else '0' + + while True: + time.sleep(0.5) + for port_num in range(self.PORT_START, (self.PORT_END + 1)): + presence = self.get_sfp(port_num).get_presence() + if(presence and self._global_port_pres_dict[port_num] == '0'): + self._global_port_pres_dict[port_num] = '1' + port_dict[port_num] = '1' + elif(not presence and + self._global_port_pres_dict[port_num] == '1'): + self._global_port_pres_dict[port_num] = '0' + port_dict[port_num] = '0' + + if(len(port_dict) > 0): + return True, change_dict + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, change_dict + + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The 'index' is 1-based + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis (Service tag) + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + + def set_status_led(self, color): + """ + Sets the state of the system LED + Args: + color: A string representing the color with which to set the + system LED + Returns: + bool: True if system LED state is set successfully, False if not + """ + if color not in list(self.SYSLED_COLOR_TO_REG.keys()): + return False + + val = pci_get_value(self.PCI_RES, self.sysled_offset) + val = (val & 0xFFCF) | self.SYSLED_COLOR_TO_REG[color] + + pci_set_value(self.PCI_RES, val, self.sysled_offset) + self.sys_ledcolor = color + return True + + def get_status_led(self): + """ + Gets the state of the system LED + Returns: + A string, one of the valid LED color strings which could be + vendor specified. + """ + val = pci_get_value(self.PCI_RES, self.sysled_offset) + if val != -1: + val = val & 0x30 + return self.REG_TO_SYSLED_COLOR.get(val) + return self.sys_ledcolor + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.base_mac_addr() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.serial_number_str() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.system_eeprom_info() + + def get_eeprom(self): + """ + Retrieves the Sys Eeprom instance for the chassis. + Returns : + The instance of the Sys Eeprom + """ + return self._eeprom + + def get_num_fans(self): + """ + Retrives the number of Fans on the chassis. + Returns : + An integer represents the number of Fans on the chassis. + """ + return self._num_fans + + def get_num_sfps(self): + """ + Retrives the numnber of Media on the chassis. + Returns: + An integer represences the number of SFPs on the chassis. + """ + return self._num_sfps + + def get_revision(self): + """ + Retrieves the revision number of the chassis (Service tag) + Returns: + string: Revision number of chassis + """ + return self._eeprom.revision_str() + + 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. + """ + try: + with open(self.REBOOT_CAUSE_PATH) as fd: + reboot_cause = int(fd.read(), 16) + except Exception as ex: + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + + if reboot_cause & 0x1: + return (self.REBOOT_CAUSE_POWER_LOSS, "Power on reset") + elif reboot_cause & 0x2: + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + elif reboot_cause & 0x4: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown") + elif reboot_cause & 0x8: + return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None) + elif reboot_cause & 0x10: + return (self.REBOOT_CAUSE_WATCHDOG, None) + elif reboot_cause & 0x20: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown") + elif reboot_cause & 0x40: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown") + elif reboot_cause & 0x80: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown") + elif reboot_cause & 0x100: + return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot") + else: + return (self.REBOOT_CAUSE_NON_HARDWARE, None) + + def get_qualified_media_list(self): + return media_part_num_list + + def set_locator_led(self, color): + """ + Sets the state of the Chassis Locator LED + + Args: + color: A string representing the color with which to set the Chassis Locator LED + + Returns: + bool: True if the Chassis Locator LED state is set successfully, False if not + + """ + val = pci_get_value(self.PCI_RES, SYSTEM_LED_REG) + if self.LOCATOR_LED_ON == color: + val = int(val) | SYSTEM_BEACON_LED_SET + elif self.LOCATOR_LED_OFF == color: + val = int(val) & SYSTEM_BEACON_LED_CLEAR + else: + return False + pci_set_value(self.PCI_RES, val, SYSTEM_LED_REG) + return True + + def get_locator_led(self): + """ + Gets the state of the Chassis Locator LED + + Returns: + LOCATOR_LED_ON or LOCATOR_LED_OFF + """ + val = pci_get_value(self.PCI_RES, SYSTEM_LED_REG) + val = int(val) & SYSTEM_BEACON_LED_SET + if not val: + return self.LOCATOR_LED_OFF + else: + return self.LOCATOR_LED_ON + + 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 or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/component.py new file mode 100644 index 0000000000..43c43e0a4e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/component.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python + +######################################################################## +# DELLEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Components' (e.g., BIOS, CPLD, FPGA, BMC etc.) available in +# the platform +# +######################################################################## + + +try: + import subprocess + from sonic_platform_base.component_base import ComponentBase + import sonic_platform.hwaccess as hwaccess + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +def get_bios_version(): + return subprocess.check_output(['dmidecode', '-s', + 'system-version']).decode('utf-8').strip() + +def get_fpga_version(): + val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:04:00.0/resource0', 0) + return '{}.{}'.format((val >> 8) & 0xff, val & 0xff) + +def get_bmc_version(): + """ Returns BMC Version """ + bmc_ver = '' + try: + bmc_ver = subprocess.check_output( + "ipmitool mc info | awk '/Firmware Revision/ { print $NF }'", + shell=True, text=True).strip() + except (FileNotFoundError, subprocess.CalledProcessError): + pass + return bmc_ver + +def get_cpld_version(bus, i2caddr): + """ Return CPLD version """ + major = hwaccess.i2c_get(bus, i2caddr, 1) + minor = hwaccess.i2c_get(bus, i2caddr, 0) + if major != -1 and minor != -1: + return '{}.{}'.format(major, minor) + return '' + +def get_cpld0_version(): + return get_cpld_version(601, 0x31) + +def get_cpld1_version(): + return get_cpld_version(600, 0x30) + +def get_cpld2_version(): + return get_cpld_version(600, 0x31) + +def get_cpld3_version(): + return get_cpld_version(600, 0x32) + +def get_cpld4_version(): + return get_cpld_version(600, 0x33) + + +class Component(ComponentBase): + """DellEMC Platform-specific Component class""" + + CHASSIS_COMPONENTS = [ + ['BIOS', + 'Performs initialization of hardware components during booting', + get_bios_version + ], + + ['FPGA', + 'Used for managing the system LEDs', + get_fpga_version + ], + + ['BMC', + 'Platform management controller for on-board temperature monitoring, in-chassis power, Fan and LED control', + get_bmc_version + ], + + ['System CPLD', + 'Used for managing the CPU power sequence and CPU states', + get_cpld0_version + ], + + ['Secondary CPLD 1', + 'Used for managing SFP28/QSFP28 port transceivers (SFP28 1-24, QSFP28 1-4)', + get_cpld1_version + ], + + ['Secondary CPLD 2', + 'Used for managing SFP28/QSFP28 port transceivers (SFP28 25-48, QSFP28 5-8)', + get_cpld2_version + ], + + ['Secondary CPLD 3', + 'Used for managing SFP28/QSFP28 port transceivers (SFP28 49-72)', + get_cpld3_version + ], + + ['Secondary CPLD 4', + 'Used for managing SFP28/QSFP28 port transceivers (SFP28 73-96)', + get_cpld4_version + ] + ] + + def __init__(self, component_index = 0): + self.index = component_index + self.name = self.CHASSIS_COMPONENTS[self.index][0] + self.description = self.CHASSIS_COMPONENTS[self.index][1] + self.version = self.CHASSIS_COMPONENTS[self.index][2]() + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return self.name + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return self.description + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + Returns: + A string containing the firmware version of the component + """ + return self.version + + def get_presence(self): + """ + Retrieves the presence of the component + Returns: + bool: True if present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the part number of the component + Returns: + string: Part number of component + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the component + Returns: + string: Serial number of component + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the component + Returns: + bool: True if component is operating properly, False if not + """ + return True + + 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 or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether component is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def install_firmware(self, image_path): + """ + Installs firmware to the component + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install was successful, False if not + """ + return False + + def get_available_firmware_version(self, image_path): + """ + Retrieves the available firmware version of the component + Note: the firmware version will be read from image + Args: + image_path: A string, path to firmware image + Returns: + A string containing the available firmware version of the component + """ + return "N/A" + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + Args: + image_path: A string, path to firmware image + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return "None" + + def update_firmware(self, image_path): + """ + Updates firmware of the component + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + Args: + image_path: A string, path to firmware image + Raises: + RuntimeError: update failed + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/eeprom.py new file mode 100644 index 0000000000..dbe660f9de --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/eeprom.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python + +############################################################################# +# DellEmc S5296F +# +# Platform and model specific eeprom subclass, inherits from the base class, +# and provides the followings: +# - the eeprom format definition +# - specific encoder/decoder if there is special need +############################################################################# + +try: + import os.path + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.eeprom_path = None + for b in (0, 1): + f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b) + if os.path.exists(f): + self.eeprom_path = f + break + if self.eeprom_path is None: + return + super(Eeprom, self).__init__(self.eeprom_path, 0, '', True) + self.eeprom_tlv_dict = dict() + try: + self.eeprom_data = self.read_eeprom() + except: + self.eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + eeprom = self.eeprom_data + + if not self.is_valid_tlvinfo_header(eeprom): + return + + total_length = (eeprom[9] << 8) | eeprom[10] + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length + + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break + + tlv = eeprom[tlv_index:tlv_index + 2 + + eeprom[tlv_index + 1]] + code = "0x%02X" % tlv[0] + name, value = self.decoder(None, tlv) + + self.eeprom_tlv_dict[code] = value + if eeprom[tlv_index] == self._TLV_CODE_CRC_32: + break + + tlv_index += eeprom[tlv_index+1] + 2 + + def serial_number_str(self): + """ + Returns the serial number + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + return results[2].decode('ascii') + + def base_mac_addr(self): + """ + Returns the base mac address found in the system EEPROM + """ + (is_valid, t) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or t[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in t[2]]).upper() + + def modelstr(self): + """ + Returns the Model name + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + """ + Returns the part number + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_str(self): + """ + Returns the servicetag number + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + """ + Returns the device revision + """ + (is_valid, results) = self.get_tlv_field( + self.eeprom_data, self._TLV_CODE_LABEL_REVISION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.eeprom_tlv_dict diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan.py new file mode 100644 index 0000000000..bf172a2ac2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan.py @@ -0,0 +1,214 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fans' information which are available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_base import FanBase + from sonic_platform.ipmihelper import IpmiSensor, IpmiFru +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FAN1_MAX_SPEED_OFFSET = 71 +PSU_FAN_MAX_SPEED_OFFSET = 50 +FAN_DIRECTION_OFFSET = 69 +PSU_FAN_DIRECTION_OFFSET = 47 + + +class Fan(FanBase): + """DellEMC Platform-specific Fan class""" + # { FAN-ID: { Sensor-Name: Sensor-ID } } + FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x53, "State": 0x5b, "Speed": 0x20}, + 2: {"Prsnt": 0x54, "State": 0x5c, "Speed": 0x21}, + 3: {"Prsnt": 0x55, "State": 0x5d, "Speed": 0x22}, + 4: {"Prsnt": 0x56, "State": 0x5e, "Speed": 0x23} + } + PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x28}, + 2: {"State": 0x32, "Speed": 0x29} } + + # { FANTRAY-ID: FRU-ID } + FAN_FRU_MAPPING = { 1: 3, 2: 4, 3: 5, 4: 6 } + PSU_FRU_MAPPING = { 1: 1, 2: 2 } + + def __init__(self, fantray_index=1, fan_index=1, psu_fan=False, + dependency=None): + self.is_psu_fan = psu_fan + if not self.is_psu_fan: + # API index is starting from 0, DellEMC platform index is + # starting from 1 + self.fantrayindex = fantray_index + 1 + self.fanindex = fan_index + 1 + self.max_speed_offset = FAN1_MAX_SPEED_OFFSET + self.fan_direction_offset = FAN_DIRECTION_OFFSET + self.index = self.fantrayindex + self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"], + is_discrete = True) + self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"], + is_discrete = True) + self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"]) + self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex]) + else: + self.dependency = dependency + self.fanindex = fan_index + self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"], + is_discrete = True) + self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"]) + self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex]) + self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET + self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET + self.max_speed = 0 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + String: The name of the device + """ + if self.is_psu_fan: + return "PSU{} Fan".format(self.fanindex) + else: + return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex) + + def get_model(self): + """ + Retrieves the part number of the FAN + Returns: + String: Part number of FAN + """ + return self.fru.get_board_part_number() + + def get_serial(self): + """ + Retrieves the serial number of the FAN + Returns: + String: Serial number of FAN + """ + return self.fru.get_board_serial() + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if fan is present, False if not + """ + presence = False + if self.is_psu_fan: + return self.dependency.get_presence() + else: + is_valid, state = self.prsnt_sensor.get_reading() + if is_valid: + if (state & 0b1): + presence = True + return presence + + def get_status(self): + """ + Retrieves the operational status of the FAN + Returns: + bool: True if FAN is operating properly, False if not + """ + status = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if not state > 1: + status = True + return status + + def get_direction(self): + """ + Retrieves the fan airfow direction + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + + Notes: + In DellEMC platforms, + - Forward/Exhaust : Air flows from Port side to Fan side. + - Reverse/Intake : Air flows from Fan side to Port side. + """ + direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE] + fan_status = self.get_presence() + if not fan_status: + return None + is_valid, fan_direction = self.fru.get_fru_data(self.fan_direction_offset) + if is_valid and fan_direction[0] < len(direction): + return direction[fan_direction[0]] + else: + return None + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + is_valid, fan_speed = self.speed_sensor.get_reading() + return fan_speed if is_valid else None + + def get_speed(self): + """ + Retrieves the speed of the fan + Returns: + int: percentage of the max fan speed + """ + rpm = self.get_speed_rpm() + if rpm is None: + return None + if self.max_speed == 0: + is_valid, resp = self.fru.get_fru_data(self.max_speed_offset, 2) + if is_valid: + self.max_speed = (resp[1] << 8) | resp[0] + if self.max_speed == 0: + return None + return (100 * rpm) // self.max_speed + + 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 or -1 if cannot determine the position + """ + return self.fanindex + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + 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 + """ + if self.get_presence(): + # The tolerance value is fixed as 20% for all the DellEMC platforms + tolerance = 20 + else: + tolerance = 0 + + return tolerance + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by HW + # Return True to avoid thermalctld alarm + return True diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..8cd0f3ba32 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/fan_drawer.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +S5296F_FANS_PER_FANTRAY = 1 + + +class FanDrawer(FanDrawerBase): + """DellEMC Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 1-based in DellEMC platforms + self.fantrayindex = fantray_index + 1 + for i in range(S5296F_FANS_PER_FANTRAY): + self._fan_list.append(Fan(fantray_index, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantrayindex) + + + def get_presence(self): + """ + Retrives the presence of the fan drawer + Returns: + bool: True if fan_tray is present, False if not + """ + return self.get_fan(0).get_presence() + + def get_model(self): + """ + Retrieves the part number of the fan drawer + Returns: + string: Part number of fan drawer + """ + return "NA" + + def get_serial(self): + """ + Retrieves the serial number of the fan drawer + Returns: + string: Serial number of the fan drawer + """ + return "NA" + + def get_status(self): + """ + Retrieves the operational status of the fan drawer + Returns: + bool: True if fan drawer is operating properly, False if not + """ + return self.get_fan(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 or -1 if cannot determine the position + """ + return self.fantrayindex + + def is_replaceable(self): + """ + Indicate whether this fan drawer is replaceable. + Returns: + bool: True if it is replaceable, False if not + """ + return True + + def set_status_led(self, color): + """ + Set led to expected color + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if set success, False if fail. + """ + # Fan tray status LED controlled by BMC + # Return True to avoid thermalctld alarm + return True + + def get_maximum_consumed_power(self): + """ + Retrives the maximum power drawn by Fan Drawer + Returns: + A float, with value of the maximum consumable power of the + component. + """ + # Value based on the hw spec + return 54.0 diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/hwaccess.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/hwaccess.py new file mode 120000 index 0000000000..e8fa340a44 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/hwaccess.py @@ -0,0 +1 @@ +../../common/sonic_platform/hwaccess.py \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/media_settings_plugin.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/media_settings_plugin.py new file mode 100644 index 0000000000..3b7667846e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/media_settings_plugin.py @@ -0,0 +1,13 @@ +# Media settings key plugin +# +# Generate keys used for lookup in media_settings,json + +def get_media_settings_key(physical_port, transceiver_dict): + d = transceiver_dict[physical_port] + media_interface = d['media_interface'] + generic_key = '{}-{}'.format(d['form_factor'], media_interface) + if media_interface == 'CR': + generic_key = '{}-{}'.format(generic_key, d['cable_length_detailed']) + return ['{}-{}'.format(d['manufacturename'], d['modelname']), + generic_key + ] diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/platform.py new file mode 100644 index 0000000000..996d94cf5a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/platform.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +############################################################################# +# +# 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): + """ + DELLEMC Platform-specific class + """ + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/psu.py new file mode 100644 index 0000000000..8e2c06f7ae --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/psu.py @@ -0,0 +1,325 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs' information which are available in the platform +# +######################################################################## + + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.ipmihelper import IpmiSensor, IpmiFru + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Psu(PsuBase): + """DellEMC Platform-specific PSU class""" + + # { PSU-ID: { Sensor-Name: Sensor-ID } } + SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39, + "Power": 0x37, "Voltage": 0x38, + "InCurrent": 0x36, "InPower": 0x34, + "InVoltage": 0x35, "Temperature": 0xc }, + 2: { "State": 0x32, "Current": 0x3F, + "Power": 0x3D, "Voltage": 0x3E, + "InCurrent": 0x3C, "InPower": 0x3A, + "InVoltage": 0x3B, "Temperature": 0xd } } + # ( PSU-ID: FRU-ID } + FRU_MAPPING = { 1: 1, 2: 2 } + + def __init__(self, psu_index): + PsuBase.__init__(self) + # PSU is 1-based in DellEMC platforms + self.index = psu_index + 1 + self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"], + is_discrete=True) + self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"]) + self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"]) + self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"]) + self.input_voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InVoltage"]) + self.input_current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InCurrent"]) + self.input_power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InPower"]) + self.temp_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Temperature"]) + self.fru = IpmiFru(self.FRU_MAPPING[self.index]) + + self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, + dependency=self)) + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the Power Supply Unit (PSU) + + Returns: + bool: True if PSU is present, False if not + """ + presence = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if (state & 0b1) == 1: + presence = True + + return presence + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celcius up to + nearest thousandth of one degree celcius, e.g. 30.125 + """ + is_valid, temperature = self.temp_sensor.get_reading() + if not is_valid: + temperature = 0 + return float(temperature) + + def get_model(self): + """ + Retrieves the part number of the PSU + + Returns: + string: Part number of PSU + """ + return self.fru.get_board_part_number() + + def get_serial(self): + """ + Retrieves the serial number of the PSU + + Returns: + string: Serial number of PSU + """ + return self.fru.get_board_serial() + + def get_revision(self): + """ + Retrives thehardware revision of the device + Returns: + String: revision value of device + """ + serial = self.fru.get_board_serial() + if serial != "NA" and len(serial) == 23: + return serial[-3:] + else: + return "NA" + + def is_replaceable(self): + """ + Indicate whether this PSU is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_status(self): + """ + Retrieves the operational status of the PSU + + Returns: + bool: True if PSU is operating properly, False if not + """ + status = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if (state == 0x01): + status = True + + return status + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + is_valid, voltage = self.voltage_sensor.get_reading() + if not is_valid: + return None + return float(voltage) + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + is_valid, current = self.current_sensor.get_reading() + if not is_valid: + return None + + return float(current) + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + is_valid, power = self.power_sensor.get_reading() + if not is_valid: + return None + + return float(power) + + def get_input_voltage(self): + """ + Retrieves current PSU voltage input + + Returns: + A float number, the input voltage in volts, + e.g. 12.1 + """ + is_valid, input_voltage = self.input_voltage_sensor.get_reading() + if not is_valid: + return None + + return float(input_voltage) + + def get_input_current(self): + """ + Retrieves present electric current supplied to PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + is_valid, input_current = self.input_current_sensor.get_reading() + if not is_valid: + return None + + return float(input_current) + + def get_input_power(self): + """ + Retrieves current energy supplied to PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + is_valid, input_power = self.input_power_sensor.get_reading() + if not is_valid: + return None + + return float(input_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. + """ + status = False + is_valid, state = self.state_sensor.get_reading() + if is_valid: + if (state == 0x01): + status = True + + return status + + def get_mfr_id(self): + """ + Retrives the Manufacturer Id of PSU + + Returns: + A string, the manunfacturer id. + """ + return self.fru.get_board_mfr_id() + + def get_type(self): + """ + Retrives the Power Type of PSU + + Returns : + A string, PSU power type + """ + board_product = self.fru.get_board_product() + if board_product is not None : + info = board_product.split(',') + if 'AC' in info : return 'AC' + if 'DC' in info : return 'DC' + return None + + 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 or -1 if cannot determine the position + """ + return self.index + + def get_temperature_high_threshold(self): + """ + Returns the high temperature threshold for PSU in Celsius + """ + is_valid, high_threshold = self.temp_sensor.get_threshold("UpperCritical") + if not is_valid: + high_threshold = 105 + high_threshold = "{:.2f}".format(high_threshold) + + return float(high_threshold) + + def get_voltage_low_threshold(self): + """ + Returns PSU low threshold in Volts + """ + is_valid, low_threshold = self.voltage_sensor.get_threshold("LowerCritical") + if not is_valid: + low_threshold = 11.4 #Revisit the value + low_threshold = "{:.2f}".format(low_threshold) + + return float(low_threshold) + + + def get_voltage_high_threshold(self): + """ + Returns PSU high threshold in Volts + """ + is_valid, high_threshold = self.voltage_sensor.get_threshold("UpperCritical") + if not is_valid: + high_threshold = 12.6 #Revisit the value + high_threshold = "{:.2f}".format(high_threshold) + + return float(high_threshold) + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + return float(750) + + 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 + """ + # Hardware not supported + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/sfp.py new file mode 100644 index 0000000000..d87ad3db74 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/sfp.py @@ -0,0 +1,367 @@ +#!/usr/bin/env python + +############################################################################# +# DELLEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + import os + import time + import struct + import mmap + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 +SFP_INFO_OFFSET = 0 +QSFP_DD_PAGE0 = 0 + +SFP_TYPE_LIST = [ + '0x3' # SFP/SFP+/SFP28 and later +] +QSFP_TYPE_LIST = [ + '0xc', # QSFP + '0xd', # QSFP+ or later + '0x11' # QSFP28 or later +] +QSFP_DD_TYPE_LIST = [ + '0x18' #QSFP-DD Type +] + +class Sfp(SfpOptoeBase): + """ + DELLEMC Platform-specific Sfp class + """ + BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0" + + def __init__(self, index, sfp_type, eeprom_path): + SfpOptoeBase.__init__(self) + self.port_type = sfp_type + self.sfp_type = sfp_type + self.index = index + self.eeprom_path = eeprom_path + self._initialize_media(delay=False) + + def get_eeprom_path(self): + return self.eeprom_path + + def get_name(self): + return "SFP/SFP+/SFP28" if self.index < 96 else "QSFP28 or later" + + def pci_mem_read(self, mm, offset): + mm.seek(offset) + read_data_stream = mm.read(4) + reg_val = struct.unpack('I', read_data_stream) + mem_val = str(reg_val)[1:-2] + # print "reg_val read:%x"%reg_val + return mem_val + + def pci_mem_write(self, mm, offset, data): + mm.seek(offset) + # print "data to write:%x"%data + mm.write(struct.pack('I', data)) + + def pci_set_value(self, resource, val, offset): + fd = os.open(resource, os.O_RDWR) + mm = mmap.mmap(fd, 0) + val = self.pci_mem_write(mm, offset, val) + mm.close() + os.close(fd) + return val + + def pci_get_value(self, resource, offset): + fd = os.open(resource, os.O_RDWR) + mm = mmap.mmap(fd, 0) + val = self.pci_mem_read(mm, offset) + mm.close() + os.close(fd) + return val + + def _initialize_media(self,delay=False): + """ + Initialize the media type and eeprom driver for SFP + """ + if delay: + time.sleep(1) + self._xcvr_api = None + self.get_xcvr_api() + + self.set_media_type() + self.reinit_sfp_driver() + + 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 or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_presence(self): + """ + Retrieves the presence of the sfp + Returns : True if sfp is present and false if it is absent + """ + # Check for invalid port_num + mask = {'QSFP' : (1 << 4), 'SFP' : (1 << 0)} + # Port offset starts with 0x4004 + port_offset = 16388 + ((self.index-1) * 16) + + try: + reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset)) + # ModPrsL is active low + if reg_value & mask[self.port_type] == 0: + return True + except ValueError: + pass + + return False + + def get_reset_status(self): + """ + Retrives the reset status of SFP + """ + reset_status = False + if (self.port_type == 'QSFP'): + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset)) + + # Absence of status throws error + if (reg_value == ""): + return reset_status + + # Mask off 4th bit for reset status + mask = (1 << 4) + + if ((reg_value & mask) == 0): + reset_status = True + else: + reset_status = False + + return reset_status + + def get_lpmode(self): + """ + Retrieves the lpmode(low power mode) of this SFP + """ + lpmode_state = False + if (self.port_type == 'QSFP'): + + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset)) + + # Absence of status throws error + if (reg_value == ""): + return lpmode_state + + # Mask off 6th bit for lpmode + mask = (1 << 6) + + # LPMode is active high + if reg_value & mask == 0: + lpmode_state = False + else: + lpmode_state = True + + return lpmode_state + + def reset(self): + """ + Reset the SFP and returns all user settings to their default state + """ + if (self.port_type == 'QSFP'): + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset)) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 4th bit for reset + mask = (1 << 4) + + # ResetL is active low + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + # Sleep 1 second to allow it to settle + time.sleep(1) + + reg_value = reg_value | mask + + # Convert our register value back to a hex string and write back + self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + else: + return False + + def set_lpmode(self, lpmode): + """ + Sets the lpmode(low power mode) of this SFP + """ + if (self.port_type == 'QSFP'): + # Port offset starts with 0x4000 + port_offset = 16384 + ((self.index-1) * 16) + + reg_value = int(self.pci_get_value(self.BASE_RES_PATH, port_offset)) + + # Absence of status throws error + if (reg_value == ""): + return False + + # Mask off 6th bit for lowpower mode + mask = (1 << 6) + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = reg_value | mask + else: + reg_value = reg_value & ~mask + + # Convert our register value back to a hex string and write back + self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset) + + return True + + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + """ + reset = self.get_reset_status() + + if (reset == True): + status = False + else: + status = True + + return status + + def set_media_type(self): + """ + Reads optic eeprom byte to determine media type inserted + """ + eeprom_raw = [] + eeprom_raw = self._xcvr_api_factory._get_id() + if eeprom_raw is not None: + eeprom_raw = hex(eeprom_raw) + if eeprom_raw in SFP_TYPE_LIST: + self.sfp_type = 'SFP' + elif eeprom_raw in QSFP_TYPE_LIST: + self.sfp_type = 'QSFP' + elif eeprom_raw in QSFP_DD_TYPE_LIST: + self.sfp_type = 'QSFP_DD' + else: + #Set native port type if EEPROM type is not recognized/readable + self.sfp_type = self.port_type + else: + self.sfp_type = self.port_type + + return self.sfp_type + + def reinit_sfp_driver(self): + """ + Changes the driver based on media type detected + """ + del_sfp_path = "/sys/class/i2c-adapter/i2c-{0}/delete_device".format(self.index+1) + new_sfp_path = "/sys/class/i2c-adapter/i2c-{0}/new_device".format(self.index+1) + driver_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/name".format(self.index+1) + delete_device = "echo 0x50 >" + del_sfp_path + + if not os.path.isfile(driver_path): + print(driver_path, "does not exist") + return False + + try: + with os.fdopen(os.open(driver_path, os.O_RDONLY)) as fd: + driver_name = fd.read() + driver_name = driver_name.rstrip('\r\n') + driver_name = driver_name.lstrip(" ") + + #Avoid re-initialization of the QSFP/SFP optic on QSFP/SFP port. + if self.sfp_type == 'SFP' and driver_name in ['optoe1', 'optoe3']: + subprocess.Popen(delete_device, shell=True, stdout=subprocess.PIPE) + time.sleep(0.2) + new_device = "echo optoe2 0x50 >" + new_sfp_path + subprocess.Popen(new_device, shell=True, stdout=subprocess.PIPE) + time.sleep(2) + elif self.sfp_type == 'QSFP' and driver_name in ['optoe2', 'optoe3']: + subprocess.Popen(delete_device, shell=True, stdout=subprocess.PIPE) + time.sleep(0.2) + new_device = "echo optoe1 0x50 >" + new_sfp_path + subprocess.Popen(new_device, shell=True, stdout=subprocess.PIPE) + time.sleep(2) + elif self.sfp_type == 'QSFP_DD' and driver_name in ['optoe1', 'optoe2']: + subprocess.Popen(delete_device, shell=True, stdout=subprocess.PIPE) + time.sleep(0.2) + new_device = "echo optoe3 0x50 >" + new_sfp_path + subprocess.Popen(new_device, shell=True, stdout=subprocess.PIPE) + time.sleep(2) + + except IOError as e: + print("Error: Unable to open file: %s" % str(e)) + return False + + def get_max_port_power(self): + """ + Retrieves the maximumum power allowed on the port in watts + """ + return 5.0 if self.sfp_type == 'QSFP' else 2.5 + + def get_error_description(self): + """ + Retrives the error descriptions of the SFP module + Returns: + String that represents the current error descriptions of vendor specific errors + In case there are multiple errors, they should be joined by '|', + like: "Bad EEPROM|Unsupported cable" + """ + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + else: + if not os.path.isfile(self.eeprom_path): + return "EEPROM driver is not attached" + + if self.sfp_type == 'SFP': + offset = SFP_INFO_OFFSET + elif self.sfp_type == 'QSFP': + offset = QSFP_INFO_OFFSET + elif self.sfp_type == 'QSFP_DD': + offset = QSFP_DD_PAGE0 + + try: + with open(self.eeprom_path, mode="rb", buffering=0) as eeprom: + eeprom.seek(offset) + eeprom.read(1) + except OSError as e: + return "EEPROM read failed ({})".format(e.strerror) + + return self.SFP_STATUS_OK + diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/thermal.py new file mode 100644 index 0000000000..c6761ceaef --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/thermal.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python + +######################################################################## +# DellEMC S5296F +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermals' information which are available in the platform +# +######################################################################## + + +try: + from sonic_platform_base.thermal_base import ThermalBase + from sonic_platform.ipmihelper import IpmiSensor +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Thermal(ThermalBase): + """DellEMC Platform-specific Thermal class""" + + # [ Sensor-Name, Sensor-ID ] + SENSOR_MAPPING = [ + ['PT Middle Sensor', 0x1], + ['ASIC On-board', 0x2], + ['PT Left Sensor', 0x3], + ['PT Right Sensor', 0x4], + ['Inlet Airflow Sensor', 0x5], + ['PSU1 Airflow Sensor', 0x7], + ['PSU2 Airflow Sensor', 0x8], + ['PSU1 Sensor', 0xc], + ['PSU2 Sensor', 0xd], + ['CPU On-board', 0xe] + ] + + def __init__(self, thermal_index): + ThermalBase.__init__(self) + self.index = thermal_index + 1 + self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1]) + + def get_name(self): + """ + Retrieves the name of the thermal + + Returns: + string: The name of the thermal + """ + return self.SENSOR_MAPPING[self.index - 1][0] + + def get_presence(self): + """ + Retrieves the presence of the thermal + + Returns: + bool: True if thermal is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the Thermal + + Returns: + string: Model/part number of Thermal + """ + return 'NA' + + def get_serial(self): + """ + Retrieves the serial number of the Thermal + + Returns: + string: Serial number of Thermal + """ + return 'NA' + + def get_status(self): + """ + Retrieves the operational status of the thermal + + Returns: + A boolean value, True if thermal is operating properly, + False if not + """ + return True + + 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 + """ + is_valid, temperature = self.sensor.get_reading() + if not is_valid: + temperature = 0 + + return float(temperature) + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + + Returns: + A float number, the high threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical") + if not is_valid: + return 0.0 + + return float(high_threshold) + + 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 + """ + is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical") + if not is_valid: + return 0.0 + + return float(high_crit_threshold) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + + Returns: + A float number, the low threshold temperature of thermal in + Celsius up to nearest thousandth of one degree Celsius, + e.g. 30.125 + """ + is_valid, low_threshold = self.sensor.get_threshold("LowerNonRecoverable") + if not is_valid: + low_threshold = 0 + + return float(low_threshold) + + 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 + """ + # Thermal threshold values are pre-defined based on HW. + return False + + 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 + """ + # Thermal threshold values are pre-defined based on HW. + return False + + 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 or -1 if cannot determine the position + """ + return self.index + + def is_replaceable(self): + """ + Indicate whether this Thermal is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/watchdog.py new file mode 100644 index 0000000000..491224d18c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-dell/s5296f/sonic_platform/watchdog.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python + +######################################################################## +# +# DELLEMC S5296F +# +# Abstract base class for implementing a platform-specific class with +# which to interact with a hardware watchdog module in SONiC +# +######################################################################## + +try: + import ctypes + import subprocess + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class _timespec(ctypes.Structure): + _fields_ = [ + ('tv_sec', ctypes.c_long), + ('tv_nsec', ctypes.c_long) + ] + + +class Watchdog(WatchdogBase): + """ + Abstract base class for interfacing with a hardware watchdog module + """ + + TIMERS = [15,20,30,40,50,60,65,70,80,100,120,140,160,180,210,240] + + armed_time = 0 + timeout = 0 + CLOCK_MONOTONIC = 1 + + def __init__(self): + self._librt = ctypes.CDLL('librt.so.1', use_errno=True) + self._clock_gettime = self._librt.clock_gettime + self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)] + + def _get_command_result(self, cmdline): + try: + proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE, + stderr=subprocess.STDOUT) + stdout = proc.communicate()[0] + proc.wait() + result = stdout.rstrip('\n'.encode()) + except OSError: + result = None + + return result + + def _get_reg_val(self): + # 0x31 = CPLD I2C Base Address + # 0x07 = Watchdog Function Register + value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07") + if not value: + return None + else: + return int(value, 16) + + def _set_reg_val(self,val): + # 0x31 = CPLD I2C Base Address + # 0x07 = Watchdog Function Register + value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s" + % (val)) + return value + + def _get_time(self): + """ + To get clock monotonic time + """ + ts = _timespec() + if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0: + self._errno = ctypes.get_errno() + return 0 + return ts.tv_sec + ts.tv_nsec * 1e-9 + + 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. + """ + timer_offset = -1 + for key,timer_seconds in enumerate(self.TIMERS): + if seconds > 0 and seconds <= timer_seconds: + timer_offset = key + seconds = timer_seconds + break + + if timer_offset == -1: + return -1 + +# cpld_version = Component.get_cpld0_version() +# wd_enabled_version = "0.8" + +# if cpld_version < wd_enabled_version: +# syslog.syslog(syslog.LOG_ERR, +# 'Older System CPLD ver, Update to 0.8 to support watchdog ') +# return -1 + + # Extracting 5th to 8th bits for WD timer values + reg_val = self._get_reg_val() + wd_timer_offset = (reg_val >> 4) & 0xf + + if wd_timer_offset != timer_offset: + # Setting 5th to 7th bits + # value from timer_offset + self.disarm() + self._set_reg_val((reg_val & 0x07) | (timer_offset << 4)) + + if self.is_armed(): + # Setting last bit to WD Timer punch + # Last bit = WD Timer punch + self._set_reg_val(reg_val & 0xFE) + + else: + # Setting 4th bit to enable WD + # 4th bit = Enable WD + reg_val = self._get_reg_val() + self._set_reg_val(reg_val | 0x8) + + self.armed_time = self._get_time() + self.timeout = seconds + return seconds + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False + if not + """ + if self.is_armed(): + # Setting 4th bit to disable WD + # 4th bit = Disable WD + reg_val = self._get_reg_val() + self._set_reg_val(reg_val & 0xF7) + + self.armed_time = 0 + self.timeout = 0 + return True + + return False + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + + # Extracting 4th bit to get WD Enable/Disable status + # 0 - Disabled WD + # 1 - Enabled WD + reg_val = self._get_reg_val() + wd_offset = (reg_val >> 3) & 1 + + return bool(wd_offset) + + 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 + their watchdog timer. If the watchdog is not armed, returns + -1. + + S5296F doesnot have hardware support to show remaining time. + Due to this limitation, this API is implemented in software. + This API would return correct software time difference if it + is called from the process which armed the watchdog timer. + If this API called from any other process, it would return + 0. If the watchdog is not armed, this API would return -1. + """ + if not self.is_armed(): + return -1 + + if self.armed_time > 0 and self.timeout != 0: + cur_time = self._get_time() + + if cur_time <= 0: + return 0 + + diff_time = int(cur_time - self.armed_time) + + if diff_time > self.timeout: + return self.timeout + else: + return self.timeout - diff_time + + return 0 +