diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pcie.yaml b/device/accton/x86_64-accton_as7712_32x-r0/pcie.yaml new file mode 100644 index 00000000000..09f1b4ae020 --- /dev/null +++ b/device/accton/x86_64-accton_as7712_32x-r0/pcie.yaml @@ -0,0 +1,95 @@ +- bus: '00' + dev: '00' + fn: '0' + id: 1f0c + name: 'Host bridge: Intel Corporation Atom processor C2000 SoC Transaction Router + (rev 02)' +- bus: '00' + dev: '01' + fn: '0' + id: 1f10 + name: 'PCI bridge: Intel Corporation Atom processor C2000 PCIe Root Port 1 (rev + 02)' +- bus: '00' + dev: '02' + fn: '0' + id: 1f11 + name: 'PCI bridge: Intel Corporation Atom processor C2000 PCIe Root Port 2 (rev + 02)' +- bus: '00' + dev: '03' + fn: '0' + id: 1f12 + name: 'PCI bridge: Intel Corporation Atom processor C2000 PCIe Root Port 3 (rev + 02)' +- bus: '00' + dev: 0e + fn: '0' + id: 1f14 + name: 'Host bridge: Intel Corporation Atom processor C2000 RAS (rev 02)' +- bus: '00' + dev: 0f + fn: '0' + id: 1f16 + name: 'IOMMU: Intel Corporation Atom processor C2000 RCEC (rev 02)' +- bus: '00' + dev: '13' + fn: '0' + id: 1f15 + name: 'System peripheral: Intel Corporation Atom processor C2000 SMBus 2.0 (rev + 02)' +- bus: '00' + dev: '14' + fn: '0' + id: 1f41 + name: 'Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)' +- bus: '00' + dev: '14' + fn: '1' + id: 1f41 + name: 'Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)' +- bus: '00' + dev: '14' + fn: '2' + id: 1f41 + name: 'Ethernet controller: Intel Corporation Ethernet Connection I354 (rev 03)' +- bus: '00' + dev: '16' + fn: '0' + id: 1f2c + name: 'USB controller: Intel Corporation Atom processor C2000 USB Enhanced Host + Controller (rev 02)' +- bus: '00' + dev: '17' + fn: '0' + id: 1f22 + name: 'SATA controller: Intel Corporation Atom processor C2000 AHCI SATA2 Controller + (rev 02)' +- bus: '00' + dev: '18' + fn: '0' + id: 1f32 + name: 'SATA controller: Intel Corporation Atom processor C2000 AHCI SATA3 Controller + (rev 02)' +- bus: '00' + dev: 1f + fn: '0' + id: 1f38 + name: 'ISA bridge: Intel Corporation Atom processor C2000 PCU (rev 02)' +- bus: '00' + dev: 1f + fn: '3' + id: 1f3c + name: 'SMBus: Intel Corporation Atom processor C2000 PCU SMBus (rev 02)' +- bus: '01' + dev: '00' + fn: '0' + id: b960 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Broadcom BCM56960 Switch + ASIC (rev 11)' +- bus: '01' + dev: '00' + fn: '1' + id: b960 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Broadcom BCM56960 Switch + ASIC (rev 11)' diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json index 7df46b922ec..d89eed78db1 100644 --- a/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json +++ b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pd-plugin.json @@ -21,11 +21,11 @@ { "i2c": { - "valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" } + "valmap": { "F2B":"exhaust", "B2F":"intake" } } }, - "PSU_FAN_MAX_SPEED":"18000" + "PSU_FAN_MAX_SPEED":"26688" }, "FAN": @@ -34,7 +34,7 @@ { "i2c": { - "valmap": {"1":"EXHAUST", "0":"INTAKE"} + "valmap": {"1":"exhaust", "0":"intake"} } }, diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json index 439a52ca9a5..fa54fbc30ca 100644 --- a/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json +++ b/device/accton/x86_64-accton_as7712_32x-r0/pddf/pddf-device.json @@ -5,7 +5,7 @@ "num_fantrays":6, "num_fans_pertray":2, "num_ports":32, - "num_temps": 4, + "num_temps": 8, "pddf_dev_types": { "description":"AS7712 - Below is the list of supported PDDF device types (chip names) for various components. If any component uses some other driver, we will create the client using 'echo > /new_device' method", @@ -210,7 +210,7 @@ "TEMP1" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP1", "device_parent":"MUX1"}, - "dev_attr": { "display_name":"Temp_1"}, + "dev_attr": { "display_name":"MB_RearLeft_temp(0x48)"}, "i2c": { "topo_info": { "parent_bus":"0x3", "dev_addr":"0x48", "dev_type":"lm75"}, @@ -226,7 +226,7 @@ "TEMP2" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP2", "device_parent":"MUX1"}, - "dev_attr": { "display_name":"Temp_2"}, + "dev_attr": { "display_name":"MB_FrontMiddle_temp(0x49)"}, "i2c": { "topo_info": { "parent_bus":"0x3", "dev_addr":"0x49", "dev_type":"lm75"}, @@ -242,7 +242,7 @@ "TEMP3" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP3", "device_parent":"MUX1"}, - "dev_attr": { "display_name":"Temp_3"}, + "dev_attr": { "display_name":"MB_MiddleLeft_temp(0x4A)"}, "i2c": { "topo_info": { "parent_bus":"0x3", "dev_addr":"0x4a", "dev_type":"lm75"}, @@ -258,7 +258,7 @@ "TEMP4" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP4", "device_parent":"MUX1"}, - "dev_attr": { "display_name":"Temp_CPU"}, + "dev_attr": { "display_name":"CB_temp(0x4B)"}, "i2c": { "topo_info": { "parent_bus":"0x3", "dev_addr":"0x4b", "dev_type":"lm75"}, @@ -270,7 +270,71 @@ ] } }, + + "TEMP5" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP5"}, + "dev_attr": { "display_name":"CPU_Core_0_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon0"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp2_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp2_max"}, + { "attr_name": "temp1_input", "drv_attr_name":"temp2_input"} + ] + } + }, + "TEMP6" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP6"}, + "dev_attr": { "display_name":"CPU_Core_1_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon0"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp3_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp3_max"}, + { "attr_name": "temp1_input", "drv_attr_name":"temp3_input"} + ] + } + }, + + "TEMP7" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP7"}, + "dev_attr": { "display_name":"CPU_Core_2_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon0"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp4_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp4_max"}, + { "attr_name": "temp1_input", "drv_attr_name":"temp4_input"} + ] + } + }, + + "TEMP8" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP8"}, + "dev_attr": { "display_name":"CPU_Core_3_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon0"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp5_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp5_max"}, + { "attr_name": "temp1_input", "drv_attr_name":"temp5_input"} + ] + } + }, + "CPLD1": { "dev_info": { "device_type":"CPLD", "device_name":"CPLD1", "device_parent":"MUX1"}, @@ -354,7 +418,11 @@ { "attr_name":"psu_i_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_p_out", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, - { "attr_name":"psu_temp1_input", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_max", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xa5", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_min", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xa4", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out_max", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xa7", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_high_threshold", "attr_devaddr":"0x5b", "attr_devtype":"pmbus", "attr_offset":"0xa8", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} ] } }, @@ -391,7 +459,11 @@ { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, - { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_max", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa5", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_min", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa4", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out_max", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa7", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_high_threshold", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa8", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} ] } }, @@ -483,12 +555,12 @@ "LOC_LED": { "dev_info": { "device_type":"LED", "device_name":"LOC_LED"}, - "dev_attr": { "index":"0"}, + "dev_attr": { "index":"0", "flag":"rw"}, "i2c" : { "attr_list": [ - {"attr_name":"STATUS_LED_COLOR_BLUE", "bits" : "7", "descr" : "", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, - {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "7", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} + {"attr_name":"blue", "bits" : "7", "descr" : "", "value" : "0x0", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"off", "bits" : "7", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} ] } }, @@ -496,13 +568,13 @@ "DIAG_LED": { "dev_info": { "device_type":"LED", "device_name":"DIAG_LED"}, - "dev_attr": { "index":"0"}, + "dev_attr": { "index":"0", "flag":"rw"}, "i2c" : { "attr_list": [ - {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "1:0", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, - {"attr_name":"STATUS_LED_COLOR_RED", "bits" : "1:0", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, - {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "1:0", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} + {"attr_name":"green", "bits" : "1:0", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"red", "bits" : "1:0", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"}, + {"attr_name":"off", "bits" : "1:0", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x41"} ] } diff --git a/device/accton/x86_64-accton_as7712_32x-r0/platform.json b/device/accton/x86_64-accton_as7712_32x-r0/platform.json new file mode 100644 index 00000000000..c0b4ebfcae8 --- /dev/null +++ b/device/accton/x86_64-accton_as7712_32x-r0/platform.json @@ -0,0 +1,880 @@ +{ + "chassis": { + "name": "7712-32X", + "thermal_manager":false, + "status_led": { + "controllable": true, + "colors": ["green", "red", "off"] + }, + "components": [ + { + "name": "CPLD1" + }, + { + "name": "CPLD2" + }, + { + "name": "CPLD3" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "FAN-1F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-1R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-4F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-4R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-5F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-5R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-6F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-6R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-1F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-1R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray2", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-2F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray3", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-3F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray4", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-4F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-4R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray5", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-5F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-5R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray6", + "status_led": { + "controllable": false + }, + "num_fans" : 2, + "fans": [ + { + "name": "FAN-6F", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-6R", + "speed": { + "controllable": true, + "minimum": 32 + }, + "status_led": { + "controllable": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU-1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-1 FAN-1" + } + ], + "thermals": [ + { + "name": "PSU-1 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ] + }, + { + "name": "PSU-2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-2 FAN-1" + } + ], + "thermals": [ + { + "name": "PSU-2 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ] + } + ], + "thermals": [ + { + "name": "MB_RearLeft_temp(0x48)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_FrontMiddle_temp(0x49)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_MiddleLeft_temp(0x4A)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CB_temp(0x4B)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CPU_Core_0_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + }, + { + "name": "CPU_Core_1_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + }, + { + "name": "CPU_Core_2_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + }, + { + "name": "CPU_Core_3_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + } + ], + "sfps": [ + { + "name": "Ethernet0" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet56" + }, + { + "name": "Ethernet60" + }, + { + "name": "Ethernet64" + }, + { + "name": "Ethernet68" + }, + { + "name": "Ethernet72" + }, + { + "name": "Ethernet76" + }, + { + "name": "Ethernet80" + }, + { + "name": "Ethernet84" + }, + { + "name": "Ethernet88" + }, + { + "name": "Ethernet92" + }, + { + "name": "Ethernet96" + }, + { + "name": "Ethernet100" + }, + { + "name": "Ethernet104" + }, + { + "name": "Ethernet108" + }, + { + "name": "Ethernet112" + }, + { + "name": "Ethernet116" + }, + { + "name": "Ethernet120" + }, + { + "name": "Ethernet124" + } + ] + }, + "interfaces": { + "Ethernet0": { + "index": "1,1,1,1", + "lanes": "49,50,51,52", + "breakout_modes": { + "1x100G[40G]": ["Eth1(Port1)"], + "2x50G": ["Eth1/1(Port1)", "Eth1/2(Port1)"], + "4x25G": ["Eth1/1(Port1)", "Eth1/2(Port1)", "Eth1/3(Port1)", "Eth1/4(Port1)"], + "4x10G": ["Eth1/1(Port1)", "Eth1/2(Port1)", "Eth1/3(Port1)", "Eth1/4(Port1)"] + } + }, + + "Ethernet4": { + "index": "2,2,2,2", + "lanes": "53,54,55,56", + "breakout_modes": { + "1x100G[40G]": ["Eth2(Port2)"], + "2x50G": ["Eth2/1(Port2)", "Eth2/2(Port2)"], + "4x25G": ["Eth2/1(Port2)", "Eth2/2(Port2)", "Eth2/3(Port2)", "Eth2/4(Port2)"], + "4x10G": ["Eth2/1(Port2)", "Eth2/2(Port2)", "Eth2/3(Port2)", "Eth2/4(Port2)"] + } + }, + + "Ethernet8": { + "index": "3,3,3,3", + "lanes": "57,58,59,60", + "breakout_modes": { + "1x100G[40G]": ["Eth3(Port3)"], + "2x50G": ["Eth3/1(Port3)", "Eth3/2(Port3)"], + "4x25G": ["Eth3/1(Port3)", "Eth3/2(Port3)", "Eth3/3(Port3)", "Eth3/4(Port3)"], + "4x10G": ["Eth3/1(Port3)", "Eth3/2(Port3)", "Eth3/3(Port3)", "Eth3/4(Port3)"] + } + }, + + "Ethernet12": { + "index": "4,4,4,4", + "lanes": "61,62,63,64", + "breakout_modes": { + "1x100G[40G]": ["Eth4(Port4)"], + "2x50G": ["Eth4/1(Port4)", "Eth4/2(Port4)"], + "4x25G": ["Eth4/1(Port4)", "Eth4/2(Port4)", "Eth4/3(Port4)", "Eth4/4(Port4)"], + "4x10G": ["Eth4/1(Port4)", "Eth4/2(Port4)", "Eth4/3(Port4)", "Eth4/4(Port4)"] + } + }, + + "Ethernet16": { + "index": "5,5,5,5", + "lanes": "65,66,67,68", + "breakout_modes": { + "1x100G[40G]": ["Eth5(Port5)"], + "2x50G": ["Eth5/1(Port5)", "Eth5/2(Port5)"], + "4x25G": ["Eth5/1(Port5)", "Eth5/2(Port5)", "Eth5/3(Port5)", "Eth5/4(Port5)"], + "4x10G": ["Eth5/1(Port5)", "Eth5/2(Port5)", "Eth5/3(Port5)", "Eth5/4(Port5)"] + } + }, + + "Ethernet20": { + "index": "6,6,6,6", + "lanes": "69,70,71,72", + "breakout_modes": { + "1x100G[40G]": ["Eth6(Port6)"], + "2x50G": ["Eth6/1(Port6)", "Eth6/2(Port6)"], + "4x25G": ["Eth6/1(Port6)", "Eth6/2(Port6)", "Eth6/3(Port6)", "Eth6/4(Port6)"], + "4x10G": ["Eth6/1(Port6)", "Eth6/2(Port6)", "Eth6/3(Port6)", "Eth6/4(Port6)"] + } + }, + + "Ethernet24": { + "index": "7,7,7,7", + "lanes": "73,74,75,76", + "breakout_modes": { + "1x100G[40G]": ["Eth7(Port7)"], + "2x50G": ["Eth7/1(Port7)", "Eth7/2(Port7)"], + "4x25G": ["Eth7/1(Port7)", "Eth7/2(Port7)", "Eth7/3(Port7)", "Eth7/4(Port7)"], + "4x10G": ["Eth7/1(Port7)", "Eth7/2(Port7)", "Eth7/3(Port7)", "Eth7/4(Port7)"] + } + }, + + "Ethernet28": { + "index": "8,8,8,8", + "lanes": "77,78,79,80", + "breakout_modes": { + "1x100G[40G]": ["Eth8(Port8)"], + "2x50G": ["Eth8/1(Port8)", "Eth8/2(Port8)"], + "4x25G": ["Eth8/1(Port8)", "Eth8/2(Port8)", "Eth8/3(Port8)", "Eth8/4(Port8)"], + "4x10G": ["Eth8/1(Port8)", "Eth8/2(Port8)", "Eth8/3(Port8)", "Eth8/4(Port8)"] + } + }, + + "Ethernet32": { + "index": "9,9,9,9", + "lanes": "33,34,35,36", + "breakout_modes": { + "1x100G[40G]": ["Eth9(Port9)"], + "2x50G": ["Eth9/1(Port9)", "Eth9/2(Port9)"], + "4x25G": ["Eth9/1(Port9)", "Eth9/2(Port9)", "Eth9/3(Port9)", "Eth9/4(Port9)"], + "4x10G": ["Eth9/1(Port9)", "Eth9/2(Port9)", "Eth9/3(Port9)", "Eth9/4(Port9)"] + } + }, + + "Ethernet36": { + "index": "10,10,10,10", + "lanes": "37,38,39,40", + "breakout_modes": { + "1x100G[40G]": ["Eth10(Port10)"], + "2x50G": ["Eth10/1(Port10)", "Eth10/2(Port10)"], + "4x25G": ["Eth10/1(Port10)", "Eth10/2(Port10)", "Eth10/3(Port10)", "Eth10/4(Port10)"], + "4x10G": ["Eth10/1(Port10)", "Eth10/2(Port10)", "Eth10/3(Port10)", "Eth10/4(Port10)"] + } + }, + + "Ethernet40": { + "index": "11,11,11,11", + "lanes": "41,42,43,44", + "breakout_modes": { + "1x100G[40G]": ["Eth11(Port11)"], + "2x50G": ["Eth11/1(Port11)", "Eth11/2(Port11)"], + "4x25G": ["Eth11/1(Port11)", "Eth11/2(Port11)", "Eth11/3(Port11)", "Eth11/4(Port11)"], + "4x10G": ["Eth11/1(Port11)", "Eth11/2(Port11)", "Eth11/3(Port11)", "Eth11/4(Port11)"] + } + }, + + "Ethernet44": { + "index": "12,12,12,12", + "lanes": "45,46,47,48", + "breakout_modes": { + "1x100G[40G]": ["Eth12(Port12)"], + "2x50G": ["Eth12/1(Port12)", "Eth12/2(Port12)"], + "4x25G": ["Eth12/1(Port12)", "Eth12/2(Port12)", "Eth12/3(Port12)", "Eth12/4(Port12)"], + "4x10G": ["Eth12/1(Port12)", "Eth12/2(Port12)", "Eth12/3(Port12)", "Eth12/4(Port12)"] + } + }, + + "Ethernet48": { + "index": "13,13,13,13", + "lanes": "81,82,83,84", + "breakout_modes": { + "1x100G[40G]": ["Eth13(Port13)"], + "2x50G": ["Eth13/1(Port13)", "Eth13/2(Port13)"], + "4x25G": ["Eth13/1(Port13)", "Eth13/2(Port13)", "Eth13/3(Port13)", "Eth13/4(Port13)"], + "4x10G": ["Eth13/1(Port13)", "Eth13/2(Port13)", "Eth13/3(Port13)", "Eth13/4(Port13)"] + } + }, + + "Ethernet52": { + "index": "14,14,14,14", + "lanes": "85,86,87,88", + "breakout_modes": { + "1x100G[40G]": ["Eth14(Port14)"], + "2x50G": ["Eth14/1(Port14)", "Eth14/2(Port14)"], + "4x25G": ["Eth14/1(Port14)", "Eth14/2(Port14)", "Eth14/3(Port14)", "Eth14/4(Port14)"], + "4x10G": ["Eth14/1(Port14)", "Eth14/2(Port14)", "Eth14/3(Port14)", "Eth14/4(Port14)"] + } + }, + + "Ethernet56": { + "index": "15,15,15,15", + "lanes": "89,90,91,92", + "breakout_modes": { + "1x100G[40G]": ["Eth15(Port15)"], + "2x50G": ["Eth15/1(Port15)", "Eth15/2(Port15)"], + "4x25G": ["Eth15/1(Port15)", "Eth15/2(Port15)", "Eth15/3(Port15)", "Eth15/4(Port15)"], + "4x10G": ["Eth15/1(Port15)", "Eth15/2(Port15)", "Eth15/3(Port15)", "Eth15/4(Port15)"] + } + }, + + "Ethernet60": { + "index": "16,16,16,16", + "lanes": "93,94,95,96", + "breakout_modes": { + "1x100G[40G]": ["Eth16(Port16)"], + "2x50G": ["Eth16/1(Port16)", "Eth16/2(Port16)"], + "4x25G": ["Eth16/1(Port16)", "Eth16/2(Port16)", "Eth16/3(Port16)", "Eth16/4(Port16)"], + "4x10G": ["Eth16/1(Port16)", "Eth16/2(Port16)", "Eth16/3(Port16)", "Eth16/4(Port16)"] + } + }, + + "Ethernet64": { + "index": "17,17,17,17", + "lanes": "97,98,99,100", + "breakout_modes": { + "1x100G[40G]": ["Eth17(Port17)"], + "2x50G": ["Eth17/1(Port17)", "Eth17/2(Port17)"], + "4x25G": ["Eth17/1(Port17)", "Eth17/2(Port17)", "Eth17/3(Port17)", "Eth17/4(Port17)"], + "4x10G": ["Eth17/1(Port17)", "Eth17/2(Port17)", "Eth17/3(Port17)", "Eth17/4(Port17)"] + } + }, + + "Ethernet68": { + "index": "18,18,18,18", + "lanes": "101,102,103,104", + "breakout_modes": { + "1x100G[40G]": ["Eth18(Port18)"], + "2x50G": ["Eth18/1(Port18)", "Eth18/2(Port18)"], + "4x25G": ["Eth18/1(Port18)", "Eth18/2(Port18)", "Eth18/3(Port18)", "Eth18/4(Port18)"], + "4x10G": ["Eth18/1(Port18)", "Eth18/2(Port18)", "Eth18/3(Port18)", "Eth18/4(Port18)"] + } + }, + + "Ethernet72": { + "index": "19,19,19,19", + "lanes": "105,106,107,108", + "breakout_modes": { + "1x100G[40G]": ["Eth19(Port19)"], + "2x50G": ["Eth19/1(Port19)", "Eth19/2(Port19)"], + "4x25G": ["Eth19/1(Port19)", "Eth19/2(Port19)", "Eth19/3(Port19)", "Eth19/4(Port19)"], + "4x10G": ["Eth19/1(Port19)", "Eth19/2(Port19)", "Eth19/3(Port19)", "Eth19/4(Port19)"] + } + }, + + "Ethernet76": { + "index": "20,20,20,20", + "lanes": "109,110,111,112", + "breakout_modes": { + "1x100G[40G]": ["Eth20(Port20)"], + "2x50G": ["Eth20/1(Port20)", "Eth20/2(Port20)"], + "4x25G": ["Eth20/1(Port20)", "Eth20/2(Port20)", "Eth20/3(Port20)", "Eth20/4(Port20)"], + "4x10G": ["Eth20/1(Port20)", "Eth20/2(Port20)", "Eth20/3(Port20)", "Eth20/4(Port20)"] + } + }, + + "Ethernet80": { + "index": "21,21,21,21", + "lanes": "17,18,19,20", + "breakout_modes": { + "1x100G[40G]": ["Eth21(Port21)"], + "2x50G": ["Eth21/1(Port21)", "Eth21/2(Port21)"], + "4x25G": ["Eth21/1(Port21)", "Eth21/2(Port21)", "Eth21/3(Port21)", "Eth21/4(Port21)"], + "4x10G": ["Eth21/1(Port21)", "Eth21/2(Port21)", "Eth21/3(Port21)", "Eth21/4(Port21)"] + } + }, + + "Ethernet84": { + "index": "22,22,22,22", + "lanes": "21,22,23,24", + "breakout_modes": { + "1x100G[40G]": ["Eth22(Port22)"], + "2x50G": ["Eth22/1(Port22)", "Eth22/2(Port22)"], + "4x25G": ["Eth22/1(Port22)", "Eth22/2(Port22)", "Eth22/3(Port22)", "Eth22/4(Port22)"], + "4x10G": ["Eth22/1(Port22)", "Eth22/2(Port22)", "Eth22/3(Port22)", "Eth22/4(Port22)"] + } + }, + + "Ethernet88": { + "index": "23,23,23,23", + "lanes": "25,26,27,28", + "breakout_modes": { + "1x100G[40G]": ["Eth23(Port23)"], + "2x50G": ["Eth23/1(Port23)", "Eth23/2(Port23)"], + "4x25G": ["Eth23/1(Port23)", "Eth23/2(Port23)", "Eth23/3(Port23)", "Eth23/4(Port23)"], + "4x10G": ["Eth23/1(Port23)", "Eth23/2(Port23)", "Eth23/3(Port23)", "Eth23/4(Port23)"] + } + }, + + "Ethernet92": { + "index": "24,24,24,24", + "lanes": "29,30,31,32", + "breakout_modes": { + "1x100G[40G]": ["Eth24(Port24)"], + "2x50G": ["Eth24/1(Port24)", "Eth24/2(Port24)"], + "4x25G": ["Eth24/1(Port24)", "Eth24/2(Port24)", "Eth24/3(Port24)", "Eth24/4(Port24)"], + "4x10G": ["Eth24/1(Port24)", "Eth24/2(Port24)", "Eth24/3(Port24)", "Eth24/4(Port24)"] + } + }, + + "Ethernet96": { + "index": "25,25,25,25", + "lanes": "113,114,115,116", + "breakout_modes": { + "1x100G[40G]": ["Eth25(Port25)"], + "2x50G": ["Eth25/1(Port25)", "Eth25/2(Port25)"], + "4x25G": ["Eth25/1(Port25)", "Eth25/2(Port25)", "Eth25/3(Port25)", "Eth25/4(Port25)"], + "4x10G": ["Eth25/1(Port25)", "Eth25/2(Port25)", "Eth25/3(Port25)", "Eth25/4(Port25)"] + } + }, + + "Ethernet100": { + "index": "26,26,26,26", + "lanes": "117,118,119,120", + "breakout_modes": { + "1x100G[40G]": ["Eth26(Port26)"], + "2x50G": ["Eth26/1(Port26)", "Eth26/2(Port26)"], + "4x25G": ["Eth26/1(Port26)", "Eth26/2(Port26)", "Eth26/3(Port26)", "Eth26/4(Port26)"], + "4x10G": ["Eth26/1(Port26)", "Eth26/2(Port26)", "Eth26/3(Port26)", "Eth26/4(Port26)"] + } + }, + + "Ethernet104": { + "index": "27,27,27,27", + "lanes": "121,122,123,124", + "breakout_modes": { + "1x100G[40G]": ["Eth27(Port27)"], + "2x50G": ["Eth27/1(Port27)", "Eth27/2(Port27)"], + "4x25G": ["Eth27/1(Port27)", "Eth27/2(Port27)", "Eth27/3(Port27)", "Eth27/4(Port27)"], + "4x10G": ["Eth27/1(Port27)", "Eth27/2(Port27)", "Eth27/3(Port27)", "Eth27/4(Port27)"] + } + }, + + "Ethernet108": { + "index": "28,28,28,28", + "lanes": "125,126,127,128", + "breakout_modes": { + "1x100G[40G]": ["Eth28(Port28)"], + "2x50G": ["Eth28/1(Port28)", "Eth28/2(Port28)"], + "4x25G": ["Eth28/1(Port28)", "Eth28/2(Port28)", "Eth28/3(Port28)", "Eth28/4(Port28)"], + "4x10G": ["Eth28/1(Port28)", "Eth28/2(Port28)", "Eth28/3(Port28)", "Eth28/4(Port28)"] + } + }, + + "Ethernet112": { + "index": "29,29,29,29", + "lanes": "1,2,3,4", + "breakout_modes": { + "1x100G[40G]": ["Eth29(Port29)"], + "2x50G": ["Eth29/1(Port29)", "Eth29/2(Port29)"], + "4x25G": ["Eth29/1(Port29)", "Eth29/2(Port29)", "Eth29/3(Port29)", "Eth29/4(Port29)"], + "4x10G": ["Eth29/1(Port29)", "Eth29/2(Port29)", "Eth29/3(Port29)", "Eth29/4(Port29)"] + } + }, + + "Ethernet116": { + "index": "30,30,30,30", + "lanes": "5,6,7,8", + "breakout_modes": { + "1x100G[40G]": ["Eth30(Port30)"], + "2x50G": ["Eth30/1(Port30)", "Eth30/2(Port30)"], + "4x25G": ["Eth30/1(Port30)", "Eth30/2(Port30)", "Eth30/3(Port30)", "Eth30/4(Port30)"], + "4x10G": ["Eth30/1(Port30)", "Eth30/2(Port30)", "Eth30/3(Port30)", "Eth30/4(Port30)"] + } + }, + + "Ethernet120": { + "index": "31,31,31,31", + "lanes": "9,10,11,12", + "breakout_modes": { + "1x100G[40G]": ["Eth31(Port31)"], + "2x50G": ["Eth31/1(Port31)", "Eth31/2(Port31)"], + "4x25G": ["Eth31/1(Port31)", "Eth31/2(Port31)", "Eth31/3(Port31)", "Eth31/4(Port31)"], + "4x10G": ["Eth31/1(Port31)", "Eth31/2(Port31)", "Eth31/3(Port31)", "Eth31/4(Port31)"] + } + }, + + "Ethernet124": { + "index": "32,32,32,32", + "lanes": "13,14,15,16", + "breakout_modes": { + "1x100G[40G]": ["Eth32(Port32)"], + "2x50G": ["Eth32/1(Port32)", "Eth32/2(Port32)"], + "4x25G": ["Eth32/1(Port32)", "Eth32/2(Port32)", "Eth32/3(Port32)", "Eth32/4(Port32)"], + "4x10G": ["Eth32/1(Port32)", "Eth32/2(Port32)", "Eth32/3(Port32)", "Eth32/4(Port32)"] + } + } + } +} + diff --git a/device/accton/x86_64-accton_as7712_32x-r0/platform_components.json b/device/accton/x86_64-accton_as7712_32x-r0/platform_components.json new file mode 100644 index 00000000000..75be465c682 --- /dev/null +++ b/device/accton/x86_64-accton_as7712_32x-r0/platform_components.json @@ -0,0 +1,12 @@ +{ + "chassis": { + "7712-32X-O-AC-F": { + "component": { + "CPLD1": { }, + "CPLD2": { }, + "CPLD3": { }, + "BIOS": { } + } + } + } +} \ No newline at end of file diff --git a/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json index a3b204e20d8..44bad649422 100644 --- a/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as7712_32x-r0/pmon_daemon_control.json @@ -1,5 +1,4 @@ { - "skip_ledd": true, - "skip_pcied": true + "skip_ledd": true } diff --git a/device/accton/x86_64-accton_as7712_32x-r0/sensors.conf b/device/accton/x86_64-accton_as7712_32x-r0/sensors.conf index 39796a5c2d1..99b50e031bf 100644 --- a/device/accton/x86_64-accton_as7712_32x-r0/sensors.conf +++ b/device/accton/x86_64-accton_as7712_32x-r0/sensors.conf @@ -38,13 +38,13 @@ chip "as7712_32x_fan-*" chip "lm75-i2c-*-48" - label temp1 "Main Board Temperature" + label temp1 "MB_RearLeft_temp(0x48)" chip "lm75-i2c-*-49" - label temp1 "Main Board Temperature" + label temp1 "MB_FrontMiddle_temp(0x49)" chip "lm75-i2c-*-4a" - label temp1 "Main Board Temperature" + label temp1 "MB_MiddleLeft_temp(0x4A)" chip "lm75-i2c-*-4b" - label temp1 "CPU Board Temperature" + label temp1 "CB_temp(0x4B)" diff --git a/device/accton/x86_64-accton_as7712_32x-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as7712_32x-r0/system_health_monitoring_config.json new file mode 100644 index 00000000000..7e3fdbf9537 --- /dev/null +++ b/device/accton/x86_64-accton_as7712_32x-r0/system_health_monitoring_config.json @@ -0,0 +1,13 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "red", + "normal": "green", + "booting": "green" + } +} diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_psu_api.h b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_psu_api.h new file mode 120000 index 00000000000..a6b156930a8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_psu_api.h @@ -0,0 +1 @@ +../../common/modules/accton_psu_api.h \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_psu_defs.h b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_psu_defs.h new file mode 120000 index 00000000000..96202b3ead2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/modules/accton_psu_defs.h @@ -0,0 +1 @@ +../../common/modules/accton_psu_defs.h \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py index d2edce41166..bff78d07dac 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/chassis.py @@ -10,20 +10,27 @@ import sys from sonic_platform_pddf_base.pddf_chassis import PddfChassis from .event import SfpEvent + from .helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") NUM_COMPONENT = 4 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" class Chassis(PddfChassis): """ PDDF Platform-specific Chassis class """ + SYSLED_DEV_NAME = "DIAG_LED" + def __init__(self, pddf_data=None, pddf_plugin_data=None): PddfChassis.__init__(self, pddf_data, pddf_plugin_data) self.__initialize_components() self._sfpevent = SfpEvent(self.get_all_sfps()) + self._api_helper = APIHelper() def __initialize_components(self): from sonic_platform.component import Component @@ -57,3 +64,60 @@ def get_sfp(self, index): sys.stderr.write("SFP index {} out of range (1-{})\n".format( index, len(self._sfp_list))) return sfp + + def get_port_or_cage_type(self, port): + from sonic_platform_base.sfp_base import SfpBase + return SfpBase.SFP_PORT_TYPE_BIT_QSFP | SfpBase.SFP_PORT_TYPE_BIT_QSFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_QSFP28 + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file( + reboot_cause_path) or "Unknown" + + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + + def initizalize_system_led(self): + return + + def get_status_led(self): + return self.get_system_led(self.SYSLED_DEV_NAME) + + def set_status_led(self, color): + return self.set_system_led(self.SYSLED_DEV_NAME, color) + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return self._eeprom.revision_str() diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py index 148584216fc..ba562b2570c 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/component.py @@ -6,8 +6,10 @@ ############################################################################# try: - import subprocess + import os + import json from sonic_platform_base.component_base import ComponentBase + from sonic_py_common.general import getstatusoutput_noshell except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -35,22 +37,6 @@ def __init__(self, component_index=0): self.index = component_index self.name = self.get_name() - def __run_command(self, command): - # Run bash command and print output to stdout - try: - process = subprocess.Popen( - shlex.split(command), stdout=subprocess.PIPE) - while True: - output = process.stdout.readline() - if output == '' and process.poll() is not None: - break - rc = process.poll() - if rc != 0: - return False - except Exception: - return False - return True - def __get_bios_version(self): # Retrieves the BIOS firmware version try: @@ -64,8 +50,8 @@ def __get_cpld_version(self): # Retrieves the CPLD firmware version cpld_version = dict() for cpld_name in CPLD_ADDR_MAPPING: - cmd = "i2cget -f -y {0} {1} 0x1".format(CPLD_ADDR_MAPPING[cpld_name][0], CPLD_ADDR_MAPPING[cpld_name][1]) - status, value = subprocess.getstatusoutput(cmd) + cmd = ["i2cget", "-f", "-y", CPLD_ADDR_MAPPING[cpld_name][0], CPLD_ADDR_MAPPING[cpld_name][1], "0x1"] + status, value = getstatusoutput_noshell(cmd) if not status: cpld_version_raw = value.rstrip() cpld_version[cpld_name] = "{}".format(int(cpld_version_raw,16)) @@ -112,4 +98,86 @@ def install_firmware(self, image_path): Returns: A boolean, True if install successfully, False if not """ - raise NotImplementedError + ret, output = getstatusoutput_noshell(["tar", "-C", "/tmp", "-xzf", image_path ] ) + if ret != 0 : + print("Installation failed because of wrong image package") + return False + + if False == os.path.exists("/tmp/install.json") : + print("Installation failed without jsonfile") + return False + + input_file = open ('/tmp/install.json') + json_array = json.load(input_file) + ret = 1 + for item in json_array: + if item.get('id')==None or item.get('path')==None: + continue + if self.name == item['id'] and item['path'] and item.get('cpu'): + print( "Find", item['id'], item['path'], item['cpu'] ) + ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'], item['cpu'] ]) + if ret==0: + break + elif self.name == item['id'] and item['path']: + print( "Find", item['id'], item['path'] ) + ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'] ]) + if ret==0: + break + + if ret==0: + return True + else : + return False + + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py index d5dac6d7f7e..1a2f60dbb67 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/event.py @@ -1,11 +1,21 @@ try: import time from sonic_py_common.logger import Logger + from .sfp import Sfp except ImportError as e: raise ImportError(repr(e) + " - required module not found") POLL_INTERVAL_IN_SEC = 1 +# SFP errors that will block eeprom accessing +SFP_BLOCKING_ERRORS = [ + Sfp.SFP_ERROR_BIT_I2C_STUCK, + Sfp.SFP_ERROR_BIT_BAD_EEPROM, + Sfp.SFP_ERROR_BIT_UNSUPPORTED_CABLE, + Sfp.SFP_ERROR_BIT_HIGH_TEMP, + Sfp.SFP_ERROR_BIT_BAD_CABLE +] + class SfpEvent: ''' Listen to insert/remove sfp events ''' @@ -46,15 +56,54 @@ def get_sfp_event(self, timeout=2000): if changed_ports != 0: for sfp in self._sfp_list: i=sfp.get_position_in_parent() - 1 - if (changed_ports & (1 << i)): - if (bitmap & (1 << i)) == 0: - port_dict[i+1] = '0' - else: - port_dict[i+1] = '1' + if (changed_ports & (1 << i)) == 0: + continue + + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + # sfp.refresh_optoe_dev_class() + sfp_state_bits = self.get_sfp_state_bits(sfp, True) + sfp_state_bits = self.check_sfp_blocking_errors(sfp_state_bits) + port_dict[i+1] = str(sfp_state_bits) # Update the cache dict self._sfp_change_event_data['present'] = bitmap return True, change_dict else: return True, change_dict + + def get_sfp_state_bits(self, sfp, present): + sfp_state_bits = 0 + + if present is True: + sfp_state_bits |= Sfp.SFP_STATUS_BIT_INSERTED + else: + return sfp_state_bits + + status = sfp.validate_eeprom() + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + elif status is not True: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BAD_EEPROM + return sfp_state_bits + + status = sfp.validate_temperature() + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + elif status is not True: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_HIGH_TEMP + return sfp_state_bits + + return sfp_state_bits + + def check_sfp_blocking_errors(self, sfp_state_bits): + for i in SFP_BLOCKING_ERRORS: + if (i & sfp_state_bits) == 0: + continue + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BLOCKING + + return sfp_state_bits diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py index 34019ac9918..33c6d42da8c 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan.py @@ -6,6 +6,9 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") +FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", + "FAN-3F", "FAN-3R", "FAN-4F", "FAN-4R", + "FAN-5F", "FAN-5R", "FAN-6F", "FAN-6R"] class Fan(PddfFan): """PDDF Platform-Specific Fan class""" @@ -15,10 +18,56 @@ def __init__(self, tray_idx, fan_idx=0, pddf_data=None, pddf_plugin_data=None, i PddfFan.__init__(self, tray_idx, fan_idx, pddf_data, pddf_plugin_data, is_psu_fan, psu_index) # Provide the functions/variables below for which implementation is to be overwritten e.g. - #def get_name(self): - ## Since AS7712 has two fans in a tray, modifying this function to return proper name - #if self.is_psu_fan: - #return "PSU_FAN{}".format(self.fan_index) - #else: - #return "Fantray{}_{}".format(self.fantray_index, {1:'Front', 2:'Rear'}.get(self.fan_index,'none')) + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[(self.fantray_index-1)*2 + self.fan_index-1] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.fans_psu_index, self.fan_index) + return fan_name + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.is_psu_fan: + return super().get_speed() + else: + return super().get_target_speed() + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = super().get_direction() + if direction is not None and len(direction) > 0: + return direction + + return 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan_drawer.py index 3b9bb607f63..eae95191e19 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan_drawer.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/fan_drawer.py @@ -15,3 +15,26 @@ def __init__(self, tray_idx, pddf_data=None, pddf_plugin_data=None): PddfFanDrawer.__init__(self, tray_idx, pddf_data, pddf_plugin_data) # Provide the functions/variables below for which implementation is to be overwritten + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantray_index) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/helper.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/helper.py new file mode 100644 index 00000000000..f6adee30984 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/helper.py @@ -0,0 +1,368 @@ +import os +import struct +import json +import fcntl +from mmap import * +from sonic_py_common import device_info +from sonic_py_common import logger +from threading import Lock +from typing import cast +from sonic_py_common.general import getstatusoutput_noshell_pipe +from sonic_py_common.general import getstatusoutput_noshell + +HOST_CHK_CMD = ["docker"] +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + try: + status, output = getstatusoutput_noshell(HOST_CHK_CMD) + return status == 0 + except Exception: + return False + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + ret = data.strip() + if len(ret) > 0: + return ret + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'raw', str(netfn), str(cmd)]) + if err == [0]: + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + if (key is None): + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'fru', 'print', str(id)]) + else: + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'fru', 'print', str(id)], ['grep', str(key)]) + if err == [0] or err == [0, 0]: + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'sensor', 'thresh', str(id), str(threshold_key), str(value)]) + if err == [0]: + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + +class FileLock: + """ + Due to pmon docker not installing the py-filelock, this class + implements a simple file lock feature. + Ref: https://github.com/tox-dev/py-filelock/blob/main/src/filelock/ + """ + + def __init__(self, lock_file): + self._lock_file = lock_file + self._thread_lock = Lock() + self.is_locked = False + + def acquire(self): + with self._thread_lock: + if self.is_locked: + return + + fd = os.open(self._lock_file, flags=(os.O_RDWR | os.O_CREAT | os.O_TRUNC)) + fcntl.flock(fd, fcntl.LOCK_EX) + self._lock_file_fd = fd + self.is_locked = True + + def release(self): + with self._thread_lock: + if self.is_locked: + fd = cast(int, self._lock_file_fd) + self._lock_file_fd = None + fcntl.flock(fd, fcntl.LOCK_UN) + os.close(fd) + self.is_locked = False + + def __enter__(self): + self.acquire() + return self + + def __exit__(self, exc_type, exc_val, traceback): + self.release() + + def __del__(self): + self.release() + + +DEVICE_THRESHOLD_JSON_PATH = "/tmp/device_threshold.json" + +class DeviceThreshold: + HIGH_THRESHOLD = 'high_threshold' + LOW_THRESHOLD = 'low_threshold' + HIGH_CRIT_THRESHOLD = 'high_critical_threshold' + LOW_CRIT_THRESHOLD = 'low_critical_threshold' + NOT_AVAILABLE = 'N/A' + + def __init__(self, th_name = NOT_AVAILABLE): + self.flock = FileLock("{}.lock".format(DEVICE_THRESHOLD_JSON_PATH)) + self.name = th_name + self.__log = logger.Logger(log_identifier="DeviceThreshold") + + self.__db_data = {} + self.__db_mtime = 0 + + def __reload_db(self): + try: + db_data = {} + with self.flock: + with open(DEVICE_THRESHOLD_JSON_PATH, "r") as db_file: + db_data = json.load(db_file) + except Exception as e: + self.__log.log_warning('{}'.format(str(e))) + return None + + return db_data + + def __get_data(self, field): + """ + Retrieves data frome JSON file by field + + Args : + field: String + + Returns: + A string if getting is successfully, 'N/A' if not + """ + if os.path.exists(DEVICE_THRESHOLD_JSON_PATH): + new_mtime = os.path.getmtime(DEVICE_THRESHOLD_JSON_PATH) + if new_mtime != self.__db_mtime: + new_data = self.__reload_db() + if new_data is not None: + self.__db_data = new_data + self.__db_mtime = new_mtime + + if self.name not in self.__db_data.keys(): + return self.NOT_AVAILABLE + + if field not in self.__db_data[self.name].keys(): + return self.NOT_AVAILABLE + + return self.__db_data[self.name][field] + + def __set_data(self, field, new_val): + """ + Set data to JSON file by field + + Args : + field: String + new_val: String + + Returns: + A boolean, True if setting is set successfully, False if not + """ + if self.name not in self.__db_data.keys(): + self.__db_data[self.name] = {} + + old_val = self.__db_data[self.name].get(field, None) + if old_val is not None and old_val == new_val: + return True + + self.__db_data[self.name][field] = new_val + + try: + with self.flock: + db_data = {} + mode = "r+" if os.path.exists(DEVICE_THRESHOLD_JSON_PATH) else "w+" + with open(DEVICE_THRESHOLD_JSON_PATH, mode) as db_file: + if mode == "r+": + db_data = json.load(db_file) + + if self.name not in db_data.keys(): + db_data[self.name] = {} + + db_data[self.name][field] = new_val + + if mode == "r+": + db_file.seek(0) + # erase old data + db_file.truncate(0) + # write all data + json.dump(db_data, db_file, indent=4) + self.__db_mtime = os.path.getmtime(DEVICE_THRESHOLD_JSON_PATH) + except Exception as e: + self.__log.log_error('{}'.format(str(e))) + return False + + return True + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature from JSON file. + + Returns: + string : the high threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.HIGH_THRESHOLD) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.HIGH_THRESHOLD, temperature) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature from JSON file. + + Returns: + string : the low threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.LOW_THRESHOLD) + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.LOW_THRESHOLD, temperature) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature from JSON file. + + Returns: + string : the high critical threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.HIGH_CRIT_THRESHOLD) + + def set_high_critical_threshold(self, temperature): + """ + Sets the high critical threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.HIGH_CRIT_THRESHOLD, temperature) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature from JSON file. + + Returns: + string : the low critical threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.LOW_CRIT_THRESHOLD) + + def set_low_critical_threshold(self, temperature): + """ + Sets the low critical threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.LOW_CRIT_THRESHOLD, temperature) diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/pcie.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/pcie.py new file mode 100644 index 00000000000..73d3627dbf7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/pcie.py @@ -0,0 +1,19 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# Base PCIe class +############################################################################# + +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Pcie(PcieUtil): + """Edgecore Platform-specific PCIe class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py index 2450957e256..845025faf93 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/psu.py @@ -11,41 +11,103 @@ class Psu(PddfPsu): """PDDF Platform-Specific PSU class""" - PLATFORM_PSU_CAPACITY = 650 def __init__(self, index, pddf_data=None, pddf_plugin_data=None): PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) # Provide the functions/variables below for which implementation is to be overwritten - def get_capacity(self): + def get_name(self): + return "PSU-{}".format(self.psu_index) + + def get_revision(self): """ - Gets the capacity (maximum output power) of the PSU in watts + Retrieves the hardware revision of the device Returns: - An integer, the capacity of PSU + string: Revision value of device """ - return (self.PLATFORM_PSU_CAPACITY) + return 'N/A' - def get_type(self): + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - Gets the type of the PSU + threshold = super().get_temperature_high_threshold() + + for psu_thermal_idx in range(self.num_psu_thermals): + try: + tmp = self._thermal_list[psu_thermal_idx].get_high_threshold() + if threshold > tmp or threshold == 0.0: + threshold = tmp + except Exception: + pass + + return threshold + + def get_model(self): + """ + Retrieves the model number (or part number) of the device Returns: - A string, the type of PSU (AC/DC) - """ - ptype = "AC" - # Currently the platform supports only AC type of PSUs - try: - import sonic_platform.platform - ch=sonic_platform.platform.Platform().get_chassis() - e=ch.sys_eeprom.read_eeprom() - ret, prod_name = ch.sys_eeprom.get_tlv_field(e,0x21) - if ret: - prod_name = prod_name[2].decode('ascii') - #print "Product name is {}".format(prod_name) - if '48V' in prod_name: - ptype = 'DC' - except Exception as e: - print("Error while trying to read syseeprom to get PSU type - {}".format(repr(e))) - - return ptype + string: Model/part number of device + """ + model = super().get_model() + if model and model.strip() == "": + return None + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = super().get_serial() + if serial and serial.strip() == "": + return None + + return serial + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + if self.get_status() is not True: + return 0.0 + + return super().get_voltage() + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + if self.get_status() is not True: + return 0.0 + + return super().get_current() + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + if self.get_status() is not True: + return 0.0 + + return super().get_power() diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py index c9fb07d6364..2d4f13a2fcc 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/sfp.py @@ -1,7 +1,10 @@ #!/usr/bin/env python try: + import natsort from sonic_platform_pddf_base.pddf_sfp import PddfSfp + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from sonic_py_common import device_info except ImportError as e: raise ImportError (str(e) + "- required module not found") @@ -11,10 +14,220 @@ class Sfp(PddfSfp): PDDF Platform-Specific Sfp class """ + SFP_TYPE_CODE_LIST = [ + 0x03, # SFP/SFP+/SFP28 + 0x0b # DWDM-SFP/SFP+ + ] + QSFP_TYPE_CODE_LIST = [ + 0x0c, # QSFP + 0x0d, # QSFP+ or later + 0x11, # QSFP28 or later + 0xe1 # QSFP28 EDFA + ] + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + self.index = index + 1 # Provide the functions/variables below for which implementation is to be overwritten def get_position_in_parent(self): """Retrieves 1-based relative physical position in parent device.""" return self.port_index + + def __get_path_to_port_config_file(self): + platform, hwsku = device_info.get_platform_and_hwsku() + hwsku_path = "/".join(["/usr/share/sonic/platform",hwsku]) + return "/".join([hwsku_path, "port_config.ini"]) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + + logical_port_list = sfputil_helper.logical + logical_port_list = natsort.natsorted(logical_port_list) + name = logical_port_list[self.port_index-1] or "Unknown" + + return name + + def __validate_eeprom_sfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(0, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + checksum_test = 0 + eeprom_raw = self.read_eeprom(384, 96) + if eeprom_raw is None: + return None + + for i in range(0, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + return True + + def __validate_eeprom_qsfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(128, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + return True + + def validate_eeprom(self): + id_byte_raw = self.read_eeprom(0, 1) + if id_byte_raw is None: + return None + + id = id_byte_raw[0] + if id in self.QSFP_TYPE_CODE_LIST: + return self.__validate_eeprom_qsfp() + elif id in self.SFP_TYPE_CODE_LIST: + return self.__validate_eeprom_sfp() + else: + return False + + def validate_temperature(self): + temperature = self.get_temperature() + if temperature is None: + return None + + threshold_dict = self.get_transceiver_threshold_info() + if threshold_dict is None: + return None + + if isinstance(temperature, float) is not True: + return True + + if isinstance(threshold_dict['temphighalarm'], float) is not True: + return True + + return threshold_dict['temphighalarm'] > temperature + + def __get_error_description(self): + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + + err_stat = self.SFP_STATUS_BIT_INSERTED + + status = self.validate_eeprom() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_BAD_EEPROM) + + status = self.validate_temperature() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_HIGH_TEMP) + + if err_stat is self.SFP_STATUS_BIT_INSERTED: + return self.SFP_STATUS_OK + else: + err_desc = '' + cnt = 0 + for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT: + if (err_stat & key) != 0: + if cnt > 0: + err_desc = err_desc + "|" + cnt = cnt + 1 + err_desc = err_desc + self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT[key] + + return err_desc + + 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" + """ + try: + ret = super().get_error_description() + if ret is not None: + return ret + except NotImplementedError: + pass + return self.__get_error_description() + + def get_lpmode(self): + + lpmode = False + + if self.get_presence()==False: + return False + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_lpmode') + + if output: + status = int(output['status'].rstrip()) + + if status == 1: + lpmode = True + else: + lpmode = False + else: + xcvr_id = self._xcvr_api_factory._get_id() + + if xcvr_id is not None: + if xcvr_id == 0x18 or xcvr_id == 0x19 or xcvr_id == 0x1e: + # QSFP-DD or OSFP + # Use common SfpOptoeBase implementation for get_lpmode + lpmode = super().get_lpmode() + elif xcvr_id == 0x11 or xcvr_id == 0x0d or xcvr_id == 0x0c: + # QSFP28, QSFP+, QSFP + # get_power_set() is not defined in the optoe_base class + api = self.get_xcvr_api() + power_set = api.get_power_set() + power_override = self.get_power_override() + + return power_set if power_override else False + + return lpmode \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/thermal.py index 77d6ec7ae88..0b128b13c28 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/thermal.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/sonic_platform/thermal.py @@ -3,15 +3,280 @@ try: from sonic_platform_pddf_base.pddf_thermal import PddfThermal + from .helper import DeviceThreshold except ImportError as e: raise ImportError(str(e) + "- required module not found") +NOT_AVAILABLE = DeviceThreshold.NOT_AVAILABLE +HIGH_THRESHOLD = DeviceThreshold.HIGH_THRESHOLD +LOW_THRESHOLD = DeviceThreshold.LOW_THRESHOLD +HIGH_CRIT_THRESHOLD = DeviceThreshold.HIGH_CRIT_THRESHOLD +LOW_CRIT_THRESHOLD = DeviceThreshold.LOW_CRIT_THRESHOLD +DEFAULT_THRESHOLD = { + 'MB_RearLeft_temp(0x48)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'MB_FrontMiddle_temp(0x49)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'MB_MiddleLeft_temp(0x4A)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CB_temp(0x4B)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_0_temp' : { + HIGH_THRESHOLD : '98.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '98.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_1_temp' : { + HIGH_THRESHOLD : '98.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '98.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_2_temp' : { + HIGH_THRESHOLD : '98.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '98.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_3_temp' : { + HIGH_THRESHOLD : '98.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '98.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'PSU-1 temp sensor 1' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'PSU-2 temp sensor 1' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + } +} class Thermal(PddfThermal): """PDDF Platform-Specific Thermal class""" def __init__(self, index, pddf_data=None, pddf_plugin_data=None, is_psu_thermal=False, psu_index=0): PddfThermal.__init__(self, index, pddf_data, pddf_plugin_data, is_psu_thermal, psu_index) + # Threshold Configuration + self.__conf = DeviceThreshold(self.get_name()) + # Default threshold. + self.__default_threshold = DEFAULT_THRESHOLD[self.get_name()] + self.min_temperature = None + self.max_temperature = None + # Provide the functions/variables below for which implementation is to be overwritten + def get_name(self): + if self.is_psu_thermal: + return "PSU-{0} temp sensor 1".format(self.thermals_psu_index) + else: + if 'dev_attr' in self.thermal_obj.keys(): + if 'display_name' in self.thermal_obj['dev_attr']: + return str(self.thermal_obj['dev_attr']['display_name']) + + # In case of errors + return "Temp sensor {0}".format(self.thermal_index) + + def get_status(self): + get_temp=self.get_temperature() + + if get_temp is not None: + return True if get_temp else False + + def get_temperature(self): + current = super().get_temperature() + + if self.min_temperature is None or \ + current < self.min_temperature: + self.min_temperature = current + + if self.max_temperature is None or \ + current > self.max_temperature: + self.max_temperature = current + + return current + + def set_high_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be more than the default value. + default_value = self.__default_threshold[HIGH_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value > float(default_value): + return False + + try: + self.__conf.set_high_threshold(str(value)) + except Exception: + return False + + return True + + def get_high_threshold(self): + value = self.__conf.get_high_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[HIGH_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + return super().get_high_threshold() + + def set_low_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be less than the default value. + default_value = self.__default_threshold[LOW_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value < float(default_value): + return False + + try: + self.__conf.set_low_threshold(str(value)) + except Exception: + return False + + return True + + def get_low_threshold(self): + value = self.__conf.get_low_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[LOW_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def set_high_critical_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be more than the default value. + default_value = self.__default_threshold[HIGH_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value > float(default_value): + return False + + try: + self.__conf.set_high_critical_threshold(str(value)) + except Exception: + return False + + return True + + def get_high_critical_threshold(self): + value = self.__conf.get_high_critical_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[HIGH_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + return super().get_high_critical_threshold() + + def set_low_critical_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be less than the default value. + default_value = self.__default_threshold[LOW_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value < float(default_value): + return False + + try: + self.__conf.set_low_critical_threshold(str(value)) + except Exception: + return False + + return True + + def get_low_critical_threshold(self): + value = self.__conf.get_low_critical_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[LOW_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.min_temperature is None: + self.get_temperature() + + return self.min_temperature + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.max_temperature is None: + self.get_temperature() + + return self.max_temperature diff --git a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_util.py b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_util.py index c519525d6dd..3bdaecca340 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as7712-32x/utils/accton_as7712_util.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # Copyright (C) 2016 Accton Networks, Inc. # @@ -16,132 +16,163 @@ # along with this program. If not, see . """ -Usage: %(scriptName)s [options] command object - -options: - -h | --help : this help message - -d | --debug : run with debug mode - -f | --force : ignore error during installation or clean -command: - install : install drivers and generate related sysfs nodes - clean : uninstall drivers and remove related sysfs nodes - show : show all systen status - sff : dump SFP eeprom - set : change board setting with fan|led|sfp -""" +usage: accton_as7712_util.py [-h] [-d] [-f] {install,clean,threshold} ... + +AS7712-32X Platform Utility + +optional arguments: + -h, --help show this help message and exit + -d, --debug run with debug mode + -f, --force ignore error during installation or clean +Utility Command: + {install,clean,threshold} + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + threshold : modify thermal threshold +""" import subprocess -import getopt import sys import logging -import re import time - - - +import argparse +from sonic_py_common.general import getstatusoutput_noshell PROJECT_NAME = 'as7712_32x' version = '0.1.0' verbose = False DEBUG = False args = [] -ALL_DEVICE = {} -DEVICE_NO = {'led':5, 'fan':6,'thermal':4, 'psu':2, 'sfp':32} +ALL_DEVICE = {} + +i2c_prefix = '/sys/bus/i2c/devices/' +''' +i2c_bus = {'fan': ['2-0066'] , + 'thermal': ['3-0048','3-0049', '3-004a', '3-004b'] , + 'psu': ['10-0050','11-0053'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] , + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['module_present', 'sfp_tx_disable_all']} +''' + +sfp_map = [22,23,24,25,27,26,29,28, + 18,19,20,21,30,31,32,33, + 34,35,36,37,46,47,48,49, + 38,39,40,41,42,43,44,45] +mknod =[ +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-1/new_device' , +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device' , +'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-1/new_device' , +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device', + +'echo as7712_32x_fan 0x66 > /sys/bus/i2c/devices/i2c-2/new_device ', +'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-3/new_device', +'echo as7712_32x_psu1 0x53 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo ym2651 0x5b > /sys/bus/i2c/devices/i2c-11/new_device', +'echo as7712_32x_psu2 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', +'echo ym2651 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', +'echo cpld_as7712 0x60 > /sys/bus/i2c/devices/i2c-4/new_device', +'echo cpld_plain 0x62 > /sys/bus/i2c/devices/i2c-5/new_device', +'echo cpld_plain 0x64 > /sys/bus/i2c/devices/i2c-6/new_device'] + +mknod2 =[ +'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-0/new_device' , +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-0/new_device' , +'echo pca9548 0X73 > /sys/bus/i2c/devices/i2c-0/new_device' , +'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device', + +'echo as7712_32x_fan 0x66 > /sys/bus/i2c/devices/i2c-2/new_device ', +'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-3/new_device', +'echo as7712_32x_psu1 0x53 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo ym2651 0x5b > /sys/bus/i2c/devices/i2c-11/new_device', +'echo as7712_32x_psu2 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', +'echo ym2651 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', +'echo cpld_as7712 0x60 > /sys/bus/i2c/devices/i2c-4/new_device', +'echo cpld_plain 0x62 > /sys/bus/i2c/devices/i2c-5/new_device', +'echo cpld_plain 0x64 > /sys/bus/i2c/devices/i2c-6/new_device'] + FORCE = 0 -#logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) -#logging.basicConfig(level=logging.INFO) +logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +logging.basicConfig(level=logging.INFO) if DEBUG == True: print(sys.argv[0]) - print('ARGV :', sys.argv[1:]) + print('ARGV :', sys.argv[1:]) def main(): global DEBUG global args global FORCE - - if len(sys.argv)<2: - show_help() - - options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', - 'debug', - 'force', - ]) - if DEBUG == True: - print(options) + global THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH + + util_parser = argparse.ArgumentParser(description="AS7712-32X Platform Utility") + util_parser.add_argument("-d", "--debug", dest='debug', action='store_true', default=False, + help="run with debug mode") + util_parser.add_argument("-f", "--force", dest='force', action='store_true', default=False, + help="ignore error during installation or clean") + subcommand = util_parser.add_subparsers(dest='cmd', title='Utility Command', required=True) + subcommand.add_parser('install', help=': install drivers and generate related sysfs nodes') + subcommand.add_parser('clean', help=': uninstall drivers and remove related sysfs nodes') + threshold_parser = subcommand.add_parser('threshold', help=': modify thermal threshold') + threshold_parser.add_argument("-l", dest='list', action='store_true', default=False, + help="list avaliable thermal") + threshold_parser.add_argument("-t", dest='thermal', type=str, metavar='THERMAL_NAME', + help="thermal name, ex: -t 'Temp sensor 1'") + threshold_parser.add_argument("-ht", dest='high_threshold', type=restricted_float, + metavar='THRESHOLD_VALUE', + help="high threshold: %.1f ~ %.1f" % (THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH)) + threshold_parser.add_argument("-hct", dest='high_crit_threshold', type=restricted_float, + metavar='THRESHOLD_VALUE', + help="high critical threshold : %.1f ~ %.1f" % (THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH)) + args = util_parser.parse_args() + + if DEBUG == True: print(args) print(len(sys.argv)) - - for opt, arg in options: - if opt in ('-h', '--help'): - show_help() - elif opt in ('-d', '--debug'): - DEBUG = True - logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): - FORCE = 1 - else: - logging.info('no option') - for arg in args: - if arg == 'install': - do_install() - elif arg == 'clean': - do_uninstall() - elif arg == 'show': - device_traversal() - elif arg == 'sff': - if len(args)!=2: - show_eeprom_help() - elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: - show_eeprom_help() - else: - show_eeprom(args[1]) - return - elif arg == 'set': - if len(args)<3: - show_set_help() - else: - set_device(args[1:]) - return - else: - show_help() - + + DEBUG = args.debug + FORCE = 1 if args.force else 0 + + if args.cmd == 'install': + do_install() + elif args.cmd == 'clean': + do_uninstall() + elif args.cmd == 'threshold': + do_threshold() return 0 -def show_help(): - print(__doc__ % {'scriptName' : sys.argv[0].split("/")[-1]}) - sys.exit(0) - -def show_set_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(cmd +" [led|sfp|fan]") - print(" use \""+ cmd + " led 0-4 \" to set led color") - print(" use \""+ cmd + " fan 0-100\" to set fan duty percetage") - print(" use \""+ cmd + " sfp 1-32 {0|1}\" to set sfp# tx_disable") - sys.exit(0) - -def show_eeprom_help(): - cmd = sys.argv[0].split("/")[-1]+ " " + args[0] - print(" use \""+ cmd + " 1-32 \" to dump sfp# eeprom") - sys.exit(0) - + def my_log(txt): if DEBUG == True: - print("[ROY]"+txt) + print("[ACCTON DBG]: ",txt) return def log_os_system(cmd, show): logging.info('Run :'+cmd) - status, output = subprocess.getstatusoutput(cmd) + status, output = subprocess.getstatusoutput(cmd) my_log (cmd +"with result:" + str(status)) my_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: - print(('Failed :'+cmd)) + print('Failed :'+cmd) return status, output def driver_check(): @@ -156,7 +187,7 @@ def driver_check(): kos = [ 'modprobe i2c_dev', -'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe i2c_mux_pca954x', 'modprobe accton_i2c_cpld' , 'modprobe ym2651y' , 'modprobe accton_as7712_32x_fan' , @@ -171,7 +202,10 @@ def driver_install(): status, output = log_os_system(kos[i], 1) if status: if FORCE == 0: - return status + return status + + print("Done driver_install") + return 0 def driver_uninstall(): @@ -179,74 +213,18 @@ def driver_uninstall(): for i in range(0,len(kos)): rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") rm = rm.replace("insmod", "rmmod") + lst = rm.split(" ") + + if len(lst) > 3: + del(lst[3]) + rm = " ".join(lst) status, output = log_os_system(rm, 1) if status: if FORCE == 0: return status return 0 -led_prefix ='/sys/class/leds/accton_'+PROJECT_NAME+'_led::' -hwmon_types = {'led': ['diag','fan','loc','psu1','psu2']} -hwmon_nodes = {'led': ['brightness'] } -hwmon_prefix ={'led': led_prefix} - -i2c_prefix = '/sys/bus/i2c/devices/' -i2c_bus = {'fan': ['2-0066'] , - 'thermal': ['3-0048','3-0049', '3-004a', '3-004b'] , - 'psu': ['10-0050','11-0053'], - 'sfp': ['-0050']} -i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] , - 'thermal': ['hwmon/hwmon*/temp1_input'] , - 'psu': ['psu_present ', 'psu_power_good'] , - 'sfp': ['module_present', 'sfp_tx_disable_all']} - -sfp_map = [22,23,24,25,27,26,29,28, - 18,19,20,21,30,31,32,33, - 34,35,36,37,46,47,48,49, - 38,39,40,41,42,43,44,45] -mknod =[ -'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-0/new_device', -'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-1/new_device' , -'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-1/new_device' , -'echo pca9548 0x73 > /sys/bus/i2c/devices/i2c-1/new_device' , -'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-1/new_device', -'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-1/new_device', -'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device', - -'echo as7712_32x_fan 0x66 > /sys/bus/i2c/devices/i2c-2/new_device ', -'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-3/new_device', -'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-3/new_device', -'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-3/new_device', -'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-3/new_device', -'echo as7712_32x_psu1 0x53 > /sys/bus/i2c/devices/i2c-11/new_device', -'echo ym2651 0x5b > /sys/bus/i2c/devices/i2c-11/new_device', -'echo as7712_32x_psu2 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', -'echo ym2651 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', -'echo cpld_as7712 0x60 > /sys/bus/i2c/devices/i2c-4/new_device', -'echo cpld_plain 0x62 > /sys/bus/i2c/devices/i2c-5/new_device', -'echo cpld_plain 0x64 > /sys/bus/i2c/devices/i2c-6/new_device'] - -mknod2 =[ -'echo pca9548 0x76 > /sys/bus/i2c/devices/i2c-1/new_device', -'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-0/new_device' , -'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-0/new_device' , -'echo pca9548 0X73 > /sys/bus/i2c/devices/i2c-0/new_device' , -'echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-0/new_device', -'echo pca9548 0x75 > /sys/bus/i2c/devices/i2c-0/new_device', -'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device', -'echo as7712_32x_fan 0x66 > /sys/bus/i2c/devices/i2c-2/new_device ', -'echo lm75 0x48 > /sys/bus/i2c/devices/i2c-3/new_device', -'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-3/new_device', -'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-3/new_device', -'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-3/new_device', -'echo as7712_32x_psu1 0x53 > /sys/bus/i2c/devices/i2c-11/new_device', -'echo ym2651 0x5b > /sys/bus/i2c/devices/i2c-11/new_device', -'echo as7712_32x_psu2 0x50 > /sys/bus/i2c/devices/i2c-10/new_device', -'echo ym2651 0x58 > /sys/bus/i2c/devices/i2c-10/new_device', -'echo cpld_as7712 0x60 > /sys/bus/i2c/devices/i2c-4/new_device', -'echo cpld_plain 0x62 > /sys/bus/i2c/devices/i2c-5/new_device', -'echo cpld_plain 0x64 > /sys/bus/i2c/devices/i2c-6/new_device'] def i2c_order_check(): @@ -290,12 +268,22 @@ def device_install(): print(output) if FORCE == 0: return status + # set all pca954x idle_disconnect + cmd = 'echo -2 | tee /sys/bus/i2c/drivers/pca954x/*-00*/idle_state' + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status for i in range(0,len(sfp_map)): status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) if status: print(output) if FORCE == 0: return status + + print("Done device_install") + return def device_uninstall(): @@ -343,29 +331,29 @@ def system_ready(): def do_install(): print("Checking system....") if driver_check() == False: - print("No driver, installing....") + print("No driver, installing....") status = driver_install() if status: if FORCE == 0: return status else: - print(PROJECT_NAME.upper()+" drivers detected....") + print(PROJECT_NAME.upper()+" drivers detected....") if not device_exist(): - print("No device, installing....") + print("No device, installing....") status = device_install() if status: if FORCE == 0: return status else: - print(PROJECT_NAME.upper()+" devices detected....") + print(PROJECT_NAME.upper()+" devices detected....") return def do_uninstall(): print("Checking system....") if not device_exist(): - print(PROJECT_NAME.upper() +" has no device installed....") + print(PROJECT_NAME.upper() +" has no device installed....") else: - print("Removing device....") + print ("Removing device....") status = device_uninstall() if status: if FORCE == 0: @@ -382,188 +370,168 @@ def do_uninstall(): return -def devices_info(): - global DEVICE_NO - global ALL_DEVICE - global i2c_bus, hwmon_types - for key in DEVICE_NO: - ALL_DEVICE[key]= {} - for i in range(0,DEVICE_NO[key]): - ALL_DEVICE[key][key+str(i+1)] = [] - - for key in i2c_bus: - buses = i2c_bus[key] - nodes = i2c_nodes[key] - for i in range(0,len(buses)): - for j in range(0,len(nodes)): - if 'fan' == key: - for k in range(0,DEVICE_NO[key]): - node = key+str(k+1) - path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - elif 'sfp' == key: - for k in range(0,DEVICE_NO[key]): - node = key+str(k+1) - path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - else: - node = key+str(i+1) - path = i2c_prefix+ buses[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][node].append(path) - - for key in hwmon_types: - itypes = hwmon_types[key] - nodes = hwmon_nodes[key] - for i in range(0,len(itypes)): - for j in range(0,len(nodes)): - node = key+"_"+itypes[i] - path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] - my_log(node+": "+ path) - ALL_DEVICE[key][ key+str(i+1)].append(path) - - #show dict all in the order - if DEBUG == True: - for i in sorted(ALL_DEVICE.keys()): - print((i+": ")) - for j in sorted(ALL_DEVICE[i].keys()): - print((" "+j)) - for k in (ALL_DEVICE[i][j]): - print((" "+" "+k)) - return - -def show_eeprom(index): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] - node = node.replace(node.split("/")[-1], 'sfp_eeprom') - # check if got hexdump command in current environment - ret, log = log_os_system("which hexdump", 0) - ret, log2 = log_os_system("which busybox hexdump", 0) - if len(log): - hex_cmd = 'hexdump' - elif len(log2): - hex_cmd = ' busybox hexdump' - else: - log = 'Failed : no hexdump cmd!!' - logging.info(log) - print(log) - return 1 - - print(node + ":") - ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) - if ret==0: - print(log) - else: - print("**********device no found**********") - return - -def set_device(args): - global DEVICE_NO - global ALL_DEVICE - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - - if args[0]=='led': - if int(args[1])>4: - show_set_help() - return - #print ALL_DEVICE['led'] - for i in range(0,len(ALL_DEVICE['led'])): - for k in (ALL_DEVICE['led']['led'+str(i+1)]): - ret, log = log_os_system("echo "+args[1]+" >"+k, 1) - if ret: - return ret - elif args[0]=='fan': - if int(args[1])>100: - show_set_help() - return - #print ALL_DEVICE['fan'] - #fan1~6 is all fine, all fan share same setting - node = ALL_DEVICE['fan'] ['fan1'][0] - node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') - ret, log = log_os_system("cat "+ node, 1) - if ret==0: - print(("Previous fan duty: " + log.strip() +"%")) - ret, log = log_os_system("echo "+args[1]+" >"+node, 1) - if ret==0: - print(("Current fan duty: " + args[1] +"%")) - return ret - elif args[0]=='sfp': - if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: - show_set_help() - return - if len(args)<2: - show_set_help() - return - - if int(args[2])>1: - show_set_help() - return - - #print ALL_DEVICE[args[0]] - for i in range(0,len(ALL_DEVICE[args[0]])): - for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: - if j.find('tx_disable')!= -1: - ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) - if ret: - return ret - - return - -#get digits inside a string. -#Ex: 31 for "sfp31" -def get_value(input): - digit = re.findall('\d+', input) - return int(digit[0]) - -def device_traversal(): - if system_ready()==False: - print("System's not ready.") - print("Please install first!") - return - - if len(ALL_DEVICE)==0: - devices_info() - for i in sorted(ALL_DEVICE.keys()): - print("============================================") - print((i.upper()+": ")) - print("============================================") - - for j in sorted(list(ALL_DEVICE[i].keys()), key=get_value): - print(" "+j+":", end=' ') - for k in (ALL_DEVICE[i][j]): - ret, log = log_os_system("cat "+k, 0) - func = k.split("/")[-1].strip() - func = re.sub(j+'_','',func,1) - func = re.sub(i.lower()+'_','',func,1) - if ret==0: - print(func+"="+log+" ", end=' ') - else: - print(func+"="+"X"+" ", end=' ') - print() - print("----------------------------------------------------------------") - - - print() - return - + def device_exist(): ret1, log = log_os_system("ls "+i2c_prefix+"*0076", 0) ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) return not(ret1 or ret2) +THRESHOLD_RANGE_LOW = 30.0 +THRESHOLD_RANGE_HIGH = 110.0 +# Code to initialize chassis object +init_chassis_code = \ + "import sonic_platform.platform\n"\ + "platform = sonic_platform.platform.Platform()\n"\ + "chassis = platform.get_chassis()\n\n" + +# Looking for thermal +looking_for_thermal_code = \ + "thermal = None\n"\ + "all_thermals = chassis.get_all_thermals()\n"\ + "for psu in chassis.get_all_psus():\n"\ + " all_thermals += psu.get_all_thermals()\n"\ + "for tmp in all_thermals:\n"\ + " if '{}' == tmp.get_name():\n"\ + " thermal = tmp\n"\ + " break\n"\ + "if thermal == None:\n"\ + " print('{} not found!')\n"\ + " exit(1)\n\n" + +def avaliable_thermals(): + global init_chassis_code + + get_all_thermal_name_code = \ + "thermal_list = []\n"\ + "all_thermals = chassis.get_all_thermals()\n"\ + "for psu in chassis.get_all_psus():\n"\ + " all_thermals += psu.get_all_thermals()\n"\ + "for tmp in all_thermals:\n"\ + " thermal_list.append(tmp.get_name())\n"\ + "print(str(thermal_list)[1:-1])\n" + + all_code = "{}{}".format(init_chassis_code, get_all_thermal_name_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + if status != 0: + return "" + return output + +def restricted_float(x): + global THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH + + try: + x = float(x) + except ValueError: + raise argparse.ArgumentTypeError("%r not a floating-point literal" % (x,)) + + if x < THRESHOLD_RANGE_LOW or x > THRESHOLD_RANGE_HIGH: + raise argparse.ArgumentTypeError("%r not in range [%.1f ~ %.1f]" % + (x, THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH)) + + return x + +def get_high_threshold(name): + global init_chassis_code, looking_for_thermal_code + + get_high_threshold_code = \ + "try:\n"\ + " print(thermal.get_high_threshold())\n"\ + " exit(0)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the get_high_threshold method!')\n"\ + " exit(1)" + + all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(name, name), + get_high_threshold_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + if status == 1: + return None + + return float(output) + +def get_high_crit_threshold(name): + global init_chassis_code, looking_for_thermal_code + + get_high_crit_threshold_code = \ + "try:\n"\ + " print(thermal.get_high_critical_threshold())\n"\ + " exit(0)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the get_high_critical_threshold method!')\n"\ + " exit(1)" + + all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(name, name), + get_high_crit_threshold_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + if status == 1: + return None + + return float(output) + +def do_threshold(): + global args, init_chassis_code, looking_for_thermal_code + + if args.list: + print("Thermals: " + avaliable_thermals()) + return + + if args.thermal is None: + print("The following arguments are required: -t") + return + + set_threshold_code = "" + if args.high_threshold is not None: + if args.high_crit_threshold is not None and \ + args.high_threshold >= args.high_crit_threshold: + print("Invalid Threshold!(High threshold can not be more than " \ + "or equal to high critical threshold.)") + exit(1) + + high_crit = get_high_crit_threshold(args.thermal) + if high_crit is not None and \ + args.high_threshold >= high_crit: + print("Invalid Threshold!(High threshold can not be more than " \ + "or equal to high critical threshold.)") + exit(1) + + set_threshold_code += \ + "try:\n"\ + " if thermal.set_high_threshold({}) is False:\n"\ + " print('{}: set_high_threshold failure!')\n"\ + " exit(1)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the set_high_threshold method!')\n"\ + "print('Apply the new high threshold successfully.')\n"\ + "\n".format(args.high_threshold, args.thermal) + + if args.high_crit_threshold is not None: + high = get_high_threshold(args.thermal) + if high is not None and \ + args.high_crit_threshold <= high: + print("Invalid Threshold!(High critical threshold can not " \ + "be less than or equal to high threshold.)") + exit(1) + + set_threshold_code += \ + "try:\n"\ + " if thermal.set_high_critical_threshold({}) is False:\n"\ + " print('{}: set_high_critical_threshold failure!')\n"\ + " exit(1)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the set_high_critical_threshold method!')\n"\ + "print('Apply the new high critical threshold successfully.')\n"\ + "\n".format(args.high_crit_threshold, args.thermal) + + if set_threshold_code == "": + return + + all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(args.thermal, args.thermal), set_threshold_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + print(output) + if __name__ == "__main__": main() diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_api.h b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_api.h new file mode 100644 index 00000000000..d522979f1e8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_api.h @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Description: + * PSU driver related api declarations + */ + +#ifndef ACCTON_PSU_API_H +#define ACCTON_PSU_API_H + +#include "accton_psu_defs.h" + +/** Description: + * Register psu status entry, set entry as NULL to unregister + */ +extern int register_psu_status_entry(PSU_STATUS_ENTRY *entry); + +#endif /* ACCTON_PSU_API_H */ diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_defs.h b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_defs.h new file mode 100644 index 00000000000..11bb253a573 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_defs.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Description: + * Platform PSU defines/structures header file + */ + +#ifndef ACCTON_PSU_DEFS_H +#define ACCTON_PSU_DEFS_H + +typedef struct PSU_STATUS_ENTRY +{ + int (*get_presence)(void *client); + int (*get_powergood)(void *client); +} PSU_STATUS_ENTRY; + +#endif /* ACCTON_PSU_DEFS_H */ diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c index 20cef5d61a3..0180fa6d738 100755 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c @@ -31,29 +31,62 @@ #include #include #include +#include +#include +#include "accton_psu_defs.h" +#define __STDC_WANT_LIB_EXT1__ 1 +#include #define MAX_FAN_DUTY_CYCLE 100 +#define ACCESS_INTERVAL_MAX 120 +#define ACCESS_INTERVAL_YM1151D_DEFAULT 60 +#define REFRESH_INTERVAL_SECOND 3 +#define REFRESH_INTERVAL_MSEC (REFRESH_INTERVAL_SECOND * 1000) +#define REFRESH_INTERVAL_HZ (REFRESH_INTERVAL_SECOND * HZ) + +#define EXIT_IF_POWER_FAILED(c) \ + do { \ + if (ym2651y_is_powergood(c) != 1) \ + goto exit; \ + } while (0) + +#define SLEEP_IF_INTERVAL(pInterval) \ + do { \ + int interval = atomic_read(pInterval); \ + if (interval > 0) \ + msleep(interval); \ + } while (0) + +/* SLEEP_IF_INTERVAL should be called before EXIT_IF_POWER_FAILED. + * It is known that accessing PSU when power failed might cause problems. + * So it is better to do sleep before checking power status because it avoids + * the risk that power status changes to failed during the sleep period. + */ +#define VALIDATE_POWERGOOD_AND_INTERVAL(client, pInterval) \ + do { \ + SLEEP_IF_INTERVAL(pInterval); \ + EXIT_IF_POWER_FAILED(client); \ + } while (0) + +struct mutex entry_lock; +PSU_STATUS_ENTRY access_psu_status = { NULL, NULL }; /* Addresses scanned */ -static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x58, 0x59, 0x5b, I2C_CLIENT_END }; enum chips { YM2651, YM2401, YM2851, YM1401A, - YPEB1200AM + YPEB1200AM, + YM1151D, + UMEC_UPD150SA, + UMEC_UP1K21R }; -/* Each client has this additional data - */ -struct ym2651y_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 chip; /* chip id */ +struct pmbus_register_value { u8 capability; /* Register value */ u16 status_word; /* Register value */ u8 fan_fault; /* Register value */ @@ -62,7 +95,7 @@ struct ym2651y_data { u16 i_out; /* Register value */ u16 p_out; /* Register value */ u8 vout_mode; /* Register value */ - u16 temp; /* Register value */ + u16 temp_input[3]; /* Register value */ u16 fan_speed; /* Register value */ u16 fan_duty_cycle[2]; /* Register value */ u8 fan_dir[4]; /* Register value */ @@ -81,6 +114,21 @@ struct ym2651y_data { u16 mfr_vout_max; /* Register value */ }; +/* Each client has this additional data + */ +struct ym2651y_data { + struct device *hwmon_dev; + struct mutex update_lock; + struct task_struct *update_task; + struct completion update_stop; + atomic_t access_interval; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 chip; /* chip id */ + u8 mfr_serial_supported; + struct pmbus_register_value reg_val; +}; + static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_byte(struct device *dev, struct device_attribute *da, @@ -95,7 +143,14 @@ static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_ascii(struct device *dev, struct device_attribute *da, char *buf); -static struct ym2651y_data *ym2651y_update_device(struct device *dev); +static ssize_t show_interval(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_interval(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int mfr_serial_supported(u8 chip); +static int ym2651y_update_device(struct i2c_client *client, + struct pmbus_register_value *data); +static int ym2651y_update_thread(void *arg); static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); @@ -112,6 +167,8 @@ enum ym2651y_sysfs_attributes { PSU_P_OUT, PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/ PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, PSU_FAN1_SPEED, PSU_FAN1_DUTY_CYCLE, PSU_PMBUS_REVISION, @@ -127,7 +184,8 @@ enum ym2651y_sysfs_attributes { PSU_MFR_IIN_MAX, PSU_MFR_IOUT_MAX, PSU_MFR_PIN_MAX, - PSU_MFR_POUT_MAX + PSU_MFR_POUT_MAX, + PSU_ACCESS_INTERVAL }; /* sysfs attributes for hwmon @@ -141,6 +199,8 @@ static SENSOR_DEVICE_ATTR(psu_v_out, S_IRUGO, show_vout, NULL, PSU_V_OU static SENSOR_DEVICE_ATTR(psu_i_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); static SENSOR_DEVICE_ATTR(psu_p_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, show_linear, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, show_linear, NULL, PSU_TEMP3_INPUT); static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); static SENSOR_DEVICE_ATTR(psu_fan1_duty_cycle_percentage, S_IWUSR | S_IRUGO, show_linear, set_fan_duty_cycle, PSU_FAN1_DUTY_CYCLE); static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_ascii, NULL, PSU_FAN_DIRECTION); @@ -158,14 +218,19 @@ static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); +static SENSOR_DEVICE_ATTR(psu_access_interval, S_IWUSR | S_IRUGO, show_interval, set_interval, PSU_ACCESS_INTERVAL); /*Duplicate nodes for lm-sensors.*/ static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_vout, NULL, PSU_V_OUT); static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT); static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_linear, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_linear, NULL, PSU_TEMP3_INPUT); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_power_on.dev_attr.attr, @@ -177,6 +242,8 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_i_out.dev_attr.attr, &sensor_dev_attr_psu_p_out.dev_attr.attr, &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, &sensor_dev_attr_psu_fan_dir.dev_attr.attr, @@ -194,13 +261,18 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, + &sensor_dev_attr_psu_access_interval.dev_attr.attr, /*Duplicate nodes for lm-sensors.*/ &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_power2_input.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, NULL }; @@ -208,32 +280,59 @@ static ssize_t show_byte(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + u8 status = 0; - return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : - sprintf(buf, "0\n"); + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + + if (attr->index == PSU_PMBUS_REVISION) + status = data->reg_val.pmbus_revision; + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_word(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); u16 status = 0; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + switch (attr->index) { case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ - status = (data->status_word & 0x40) ? 0 : 1; + status = (data->reg_val.status_word & 0x40) ? 0 : 1; break; case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ - status = (data->status_word & 0x4) >> 2; + status = (data->reg_val.status_word & 0x4) >> 2; break; case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ - status = (data->status_word & 0x800) ? 0 : 1; + status = (data->reg_val.status_word & 0x800) ? 0 : 1; break; + default: + goto exit; } + mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static int two_complement_to_int(u16 data, u8 valid_bit, int mask) @@ -262,8 +361,8 @@ static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *d return -EINVAL; mutex_lock(&data->update_lock); - data->fan_duty_cycle[nr] = speed; - ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + data->reg_val.fan_duty_cycle[nr] = speed; + ym2651y_write_word(client, 0x3B + nr, data->reg_val.fan_duty_cycle[nr]); mutex_unlock(&data->update_lock); return count; @@ -273,151 +372,214 @@ static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); u16 value = 0; int exponent, mantissa; int multiplier = 1000; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + switch (attr->index) { case PSU_V_OUT: - value = data->v_out; + value = data->reg_val.v_out; break; case PSU_I_OUT: - value = data->i_out; + value = data->reg_val.i_out; break; case PSU_P_OUT_UV: multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/ /*Passing through*/ case PSU_P_OUT: - value = data->p_out; + value = data->reg_val.p_out; break; case PSU_TEMP1_INPUT: - value = data->temp; + case PSU_TEMP2_INPUT: + case PSU_TEMP3_INPUT: + value = data->reg_val.temp_input[attr->index - PSU_TEMP1_INPUT]; break; case PSU_FAN1_SPEED: - value = data->fan_speed; + value = data->reg_val.fan_speed; multiplier = 1; break; case PSU_FAN1_DUTY_CYCLE: - value = data->fan_duty_cycle[0]; + value = data->reg_val.fan_duty_cycle[0]; multiplier = 1; break; case PSU_MFR_VIN_MIN: - value = data->mfr_vin_min; + value = data->reg_val.mfr_vin_min; break; case PSU_MFR_VIN_MAX: - value = data->mfr_vin_max; + value = data->reg_val.mfr_vin_max; break; case PSU_MFR_VOUT_MIN: - value = data->mfr_vout_min; + value = data->reg_val.mfr_vout_min; break; case PSU_MFR_VOUT_MAX: - value = data->mfr_vout_max; + value = data->reg_val.mfr_vout_max; break; case PSU_MFR_PIN_MAX: - value = data->mfr_pin_max; + value = data->reg_val.mfr_pin_max; break; case PSU_MFR_POUT_MAX: - value = data->mfr_pout_max; + value = data->reg_val.mfr_pout_max; break; case PSU_MFR_IOUT_MAX: - value = data->mfr_iout_max; + value = data->reg_val.mfr_iout_max; break; case PSU_MFR_IIN_MAX: - value = data->mfr_iin_max; + value = data->reg_val.mfr_iin_max; break; + default: + goto exit; } + mutex_unlock(&data->update_lock); exponent = two_complement_to_int(value >> 11, 5, 0x1f); mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + u8 shift = 0; + u8 fan_fault = 0; - u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } - return sprintf(buf, "%d\n", data->fan_fault >> shift); + fan_fault = data->reg_val.fan_fault; + mutex_unlock(&data->update_lock); + + shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + return sprintf(buf, "%d\n", fan_fault >> shift); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, char *buf) { - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + u8 over_temp = 0; - return sprintf(buf, "%d\n", data->over_temp >> 7); + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + + over_temp = data->reg_val.over_temp; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", over_temp >> 7); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_ascii(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + ssize_t ret = 0; u8 *ptr = NULL; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + switch (attr->index) { case PSU_FAN_DIRECTION: /* psu_fan_dir */ if (data->chip==YPEB1200AM) { - memcpy(data->fan_dir, "F2B", 3); - data->fan_dir[3]='\0'; + #ifdef __STDC_LIB_EXT1__ + memcpy_s(data->reg_val.fan_dir, 3, "F2B", 3); + #else + memcpy(data->reg_val.fan_dir, "F2B", 3); + #endif + data->reg_val.fan_dir[3]='\0'; } - ptr = data->fan_dir; + ptr = data->reg_val.fan_dir; break; case PSU_MFR_SERIAL: /* psu_mfr_serial */ - ptr = data->mfr_serial+1; /* The first byte is the count byte of string. */ + ptr = data->reg_val.mfr_serial+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_ID: /* psu_mfr_id */ - ptr = data->mfr_id+1; /* The first byte is the count byte of string. */ + ptr = data->reg_val.mfr_id+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_MODEL: /* psu_mfr_model */ - ptr = data->mfr_model+1; /* The first byte is the count byte of string. */ + ptr = data->reg_val.mfr_model+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_REVISION: /* psu_mfr_revision */ - ptr = data->mfr_revsion+1; + ptr = data->reg_val.mfr_revsion+1; break; default: - return 0; + goto exit; } - return sprintf(buf, "%s\n", ptr); + ret = sprintf(buf, "%s\n", ptr); + +exit: + mutex_unlock(&data->update_lock); + return ret; } static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); int exponent, mantissa; int multiplier = 1000; + mutex_lock(&data->update_lock); if (!data->valid) { - return 0; + goto exit; } - exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + exponent = two_complement_to_int(data->reg_val.vout_mode, 5, 0x1f); switch (attr->index) { case PSU_MFR_VOUT_MIN: - mantissa = data->mfr_vout_min; + mantissa = data->reg_val.mfr_vout_min; break; case PSU_MFR_VOUT_MAX: - mantissa = data->mfr_vout_max; + mantissa = data->reg_val.mfr_vout_max; break; case PSU_V_OUT: - mantissa = data->v_out; + mantissa = data->reg_val.v_out; break; default: - return 0; + goto exit; } + mutex_unlock(&data->update_lock); return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_vout(struct device *dev, struct device_attribute *da, @@ -434,6 +596,34 @@ static ssize_t show_vout(struct device *dev, struct device_attribute *da, } } +static ssize_t show_interval(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&data->access_interval)); +} + +static ssize_t set_interval(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + long interval; + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + status = kstrtol(buf, 10, &interval); + if (status) + return status; + + if (interval < 0 || interval > ACCESS_INTERVAL_MAX) + return -EINVAL; + + atomic_set(&data->access_interval, (int)interval); + return count; +} + static const struct attribute_group ym2651y_group = { .attrs = ym2651y_attributes, }; @@ -461,6 +651,7 @@ static int ym2651y_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->chip = dev_id->driver_data; + data->mfr_serial_supported = mfr_serial_supported(data->chip); dev_info(&client->dev, "chip found\n"); /* Register sysfs hooks */ @@ -475,11 +666,26 @@ static int ym2651y_probe(struct i2c_client *client, goto exit_remove; } + /* create update thread */ + if (data->chip == YM1151D) + atomic_set(&data->access_interval, ACCESS_INTERVAL_YM1151D_DEFAULT); + else + atomic_set(&data->access_interval, 0); + + init_completion(&data->update_stop); + data->update_task = kthread_run(ym2651y_update_thread, client, "ym2651y_update_task"); + if (IS_ERR(data->update_task)) { + dev_dbg(&client->dev, "Failed to create ym2651y update task!\n"); + goto exit_hwmon; + } + dev_info(&client->dev, "%s: psu '%s'\n", dev_name(data->hwmon_dev), client->name); return 0; +exit_hwmon: + hwmon_device_unregister(data->hwmon_dev); exit_remove: sysfs_remove_group(&client->dev.kobj, &ym2651y_group); exit_free: @@ -493,6 +699,10 @@ static int ym2651y_remove(struct i2c_client *client) { struct ym2651y_data *data = i2c_get_clientdata(client); + /* Stop update task */ + kthread_stop(data->update_task); + wait_for_completion(&data->update_stop); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ym2651y_group); kfree(data); @@ -506,6 +716,9 @@ static const struct i2c_device_id ym2651y_id[] = { { "ym2851", YM2851 }, { "ym1401a",YM1401A}, { "ype1200am", YPEB1200AM }, + { "ym1151d", YM1151D }, + { "umec_upd150sa", UMEC_UPD150SA }, + { "umec_up1k21r", UMEC_UP1K21R }, {} }; MODULE_DEVICE_TABLE(i2c, ym2651y_id); @@ -521,6 +734,23 @@ static struct i2c_driver ym2651y_driver = { .address_list = normal_i2c, }; +static int ym2651y_is_powergood(struct i2c_client *client) +{ + int powergood = 0; + + mutex_lock(&entry_lock); + if (access_psu_status.get_powergood == NULL) { + powergood = 1; /* skip powergood validation if API is not registered */ + goto exit; + } + + powergood = access_psu_status.get_powergood(client); + +exit: + mutex_unlock(&entry_lock); + return powergood; +} + static int ym2651y_read_byte(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -539,8 +769,9 @@ static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, int data_len) { - int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + int result; + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); if (unlikely(result < 0)) goto abort; if (unlikely(result != data_len)) { @@ -564,15 +795,10 @@ struct reg_data_word { u16 *value; }; -static struct ym2651y_data *ym2651y_update_device(struct device *dev) +static int ym2651y_update_device(struct i2c_client *client, + struct pmbus_register_value *data) { - struct i2c_client *client = to_i2c_client(dev); - struct ym2651y_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); - - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { + struct ym2651y_data *driver_data = i2c_get_clientdata(client); int i, status, length; u8 command, buf; u8 fan_dir[5] = {0}; @@ -586,7 +812,9 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) {0x8b, &data->v_out}, {0x8c, &data->i_out}, {0x96, &data->p_out}, - {0x8d, &data->temp}, + {0x8d, &(data->temp_input[0])}, + {0x8e, &(data->temp_input[1])}, + {0x8f, &(data->temp_input[2])}, {0x3b, &(data->fan_duty_cycle[0])}, {0x3c, &(data->fan_duty_cycle[1])}, {0x90, &data->fan_speed}, @@ -604,8 +832,9 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) /* Read byte data */ for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { - status = ym2651y_read_byte(client, regs_byte[i].reg); + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_byte(client, regs_byte[i].reg); if (status < 0) { dev_dbg(&client->dev, "reg %d, err %d\n", @@ -620,10 +849,20 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) /* Read word data */ for (i = 0; i < ARRAY_SIZE(regs_word); i++) { - status = ym2651y_read_word(client, regs_word[i].reg); + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + + /* To prevent hardware errors, + access to temp2_input and temp3_input should be skipped + if the chip ID is not in the following list. */ + if (regs_word[i].reg == 0x8e || regs_word[i].reg == 0x8f) { + if (driver_data->chip != UMEC_UPD150SA && + driver_data->chip != UMEC_UP1K21R) { + continue; + } + } - if (status < 0) - { + status = ym2651y_read_word(client, regs_word[i].reg); + if (status < 0) { dev_dbg(&client->dev, "reg %d, err %d\n", regs_word[i].reg, status); *(regs_word[i].value) = 0; @@ -636,109 +875,178 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) /* Read fan_direction */ command = 0xC3; + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1); - - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - + if (status == 0) { strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + } /* Read mfr_id */ command = 0x99; + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, data->mfr_id, ARRAY_SIZE(data->mfr_id)-1); + if (status == 0) data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; - if (status < 0) - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - /* Read mfr_model */ command = 0x9a; length = 1; /* Read first byte to determine the length of data */ + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, &buf, length); - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } + if (status == 0 && buf != 0xFF) { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, data->mfr_model, buf+1); - + if (status == 0) { if ((buf+1) >= (ARRAY_SIZE(data->mfr_model)-1)) - { data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; - } else data->mfr_model[buf+1] = '\0'; - - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; + } } /*YM-1401A PSU doens't support to get serial_num, so ignore it. *It's vout doesn't support linear, so let it use show_vout_by_mode(). */ - if(!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A"))) - { - data->chip=YM1401A; + if (!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A"))) { + driver_data->chip=YM1401A; } - else - { + else if (driver_data->mfr_serial_supported) { /* Read mfr_serial */ command = 0x9e; length = 1; /* Read first byte to determine the length of data */ + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, &buf, length); - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } + if (status == 0 && buf != 0xFF) { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, data->mfr_serial, buf+1); - + if (status == 0) { if ((buf+1) >= (ARRAY_SIZE(data->mfr_serial)-1)) - { data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0'; - } else data->mfr_serial[buf+1] = '\0'; - - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; + } } } /* Read mfr_revsion */ command = 0x9b; + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, data->mfr_revsion, ARRAY_SIZE(data->mfr_revsion)-1); + if (status == 0) data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; + return 1; /* Return 1 for valid data, 0 for invalid */ + +exit: + return 0; } - data->last_updated = jiffies; +static int ym2651y_update_thread(void *arg) +{ + int valid = 0; + unsigned long start_time = 0; + unsigned long next_start_time = 0; /* expected next start time */ + struct i2c_client *client = arg; + struct ym2651y_data *data = i2c_get_clientdata(client); + + if (data == NULL) + return -EINVAL; + + while (!kthread_should_stop()) { + struct pmbus_register_value reg_val = { 0 }; + + start_time = jiffies; + valid = ym2651y_update_device(client, ®_val); + + mutex_lock(&data->update_lock); data->valid = 1; + if (valid) { + #ifdef __STDC_LIB_EXT1__ + memcpy_s(&data->reg_val, sizeof(reg_val), ®_val, sizeof(reg_val)); + #else + memcpy(&data->reg_val, ®_val, sizeof(reg_val)); + #endif + } else { + #ifdef __STDC_LIB_EXT1__ + memset_s(&data->reg_val, sizeof(reg_val), 0, sizeof(reg_val)); + #else + memset(&data->reg_val, 0, sizeof(reg_val)); + #endif + + /* PMBus STATUS_WORD(0x79): psu_power_on, low byte bit 6, 0=>ON, 1=>OFF */ + data->reg_val.status_word |= 0x40; + + /* PMBus STATUS_WORD(0x79): psu_power_good, high byte bit 3, 0=>OK, 1=>FAIL */ + data->reg_val.status_word |= 0x800; + + /* psu_power_good = failed, modified to return 1023 degree for python used. */ + data->reg_val.temp_input[0] = 0x3ff; + data->reg_val.temp_input[1] = 0x3ff; + data->reg_val.temp_input[2] = 0x3ff; + } + mutex_unlock(&data->update_lock); + + next_start_time = start_time + REFRESH_INTERVAL_HZ; + if (time_before(jiffies, next_start_time)) { + /* Sleep if time consumed is less than REFRESH_INTERVAL_SECOND */ + msleep(min(jiffies_to_msecs(next_start_time - jiffies), REFRESH_INTERVAL_MSEC)); + } } - exit: - mutex_unlock(&data->update_lock); + complete_all(&data->update_stop); + return 0; +} + +int register_psu_status_entry(PSU_STATUS_ENTRY *entry) +{ + mutex_lock(&entry_lock); + + if (entry) { + access_psu_status.get_presence = entry->get_presence; + access_psu_status.get_powergood = entry->get_powergood; + } + else { + access_psu_status.get_presence = NULL; + access_psu_status.get_powergood = NULL; + } + + mutex_unlock(&entry_lock); + return 0; +} +EXPORT_SYMBOL(register_psu_status_entry); - return data; +static int __init ym2651y_init(void) +{ + mutex_init(&entry_lock); + return i2c_add_driver(&ym2651y_driver); } -module_i2c_driver(ym2651y_driver); +static void __exit ym2651y_exit(void) +{ + i2c_del_driver(&ym2651y_driver); +} + +static int mfr_serial_supported(u8 chip) +{ + int i = 0; + u8 supported_chips[] = {}; + + for (i = 0; i < ARRAY_SIZE(supported_chips); i++) { + if (chip == supported_chips[i]) + return 1; +} + + return 0; +} MODULE_AUTHOR("Brandon Chuang "); MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); MODULE_LICENSE("GPL"); - +module_init(ym2651y_init); +module_exit(ym2651y_exit);