From ec8d1c346dade4925459048e854f4a5a732e8767 Mon Sep 17 00:00:00 2001 From: brandonchuang Date: Wed, 15 Feb 2023 15:19:39 +0800 Subject: [PATCH 1/6] [Edgecore][as4625-54p/54t] Add support for as4625-54p/54t platform Add 2 new platforms: Platform: x86_64-accton_as4625_54p-r0 HwSKU: Accton-AS4625-54P ASIC: broadcom Port Config: 48x1G + 6x10G Platform: x86_64-accton_as4625_54t-r0 HwSKU: Accton-AS4625-54T ASIC: broadcom Port Config: 48x1G + 6x10G Signed-off-by: Brandon Chuang --- .../Accton-AS4625-54P/port_config.ini | 55 ++ .../Accton-AS4625-54P/sai.profile | 1 + .../x86_64-accton_as4625_54p-r0/default_sku | 1 + .../installer.conf | 4 + .../x86_64-accton_as4625_54p-r0/pcie.yaml | 149 +++ .../x86_64-accton_as4625_54p-r0/platform.json | 860 ++++++++++++++++++ .../x86_64-accton_as4625_54p-r0/platform_asic | 1 + .../platform_components.json | 10 + .../plugins/ssd_util.py | 24 + .../pmon_daemon_control.json | 4 + .../x86_64-accton_as4625_54p-r0/sensors.conf | 50 + .../sonic_platform/__init__.py | 2 + .../sonic_platform/chassis.py | 253 ++++++ .../sonic_platform/component.py | 152 ++++ .../sonic_platform/eeprom.py | 134 +++ .../sonic_platform/event.py | 117 +++ .../sonic_platform/fan.py | 314 +++++++ .../sonic_platform/fan_drawer.py | 116 +++ .../sonic_platform/helper.py | 324 +++++++ .../sonic_platform/pcie.py | 19 + .../sonic_platform/platform.py | 20 + .../sonic_platform/psu.py | 334 +++++++ .../sonic_platform/sfp.py | 283 ++++++ .../sonic_platform/thermal.py | 540 +++++++++++ .../system_health_monitoring_config.json | 14 + .../Accton-AS4625-54T/port_config.ini | 55 ++ .../Accton-AS4625-54T/sai.profile | 1 + .../x86_64-accton_as4625_54t-r0/default_sku | 1 + .../installer.conf | 4 + .../x86_64-accton_as4625_54t-r0/pcie.yaml | 149 +++ .../x86_64-accton_as4625_54t-r0/platform.json | 860 ++++++++++++++++++ .../x86_64-accton_as4625_54t-r0/platform_asic | 1 + .../platform_components.json | 10 + .../plugins/ssd_util.py | 24 + .../pmon_daemon_control.json | 4 + .../x86_64-accton_as4625_54t-r0/sensors.conf | 50 + .../sonic_platform/__init__.py | 1 + .../sonic_platform/chassis.py | 1 + .../sonic_platform/component.py | 1 + .../sonic_platform/eeprom.py | 1 + .../sonic_platform/event.py | 1 + .../sonic_platform/fan.py | 1 + .../sonic_platform/fan_drawer.py | 1 + .../sonic_platform/helper.py | 1 + .../sonic_platform/pcie.py | 1 + .../sonic_platform/platform.py | 1 + .../sonic_platform/psu.py | 1 + .../sonic_platform/sfp.py | 1 + .../sonic_platform/thermal.py | 1 + .../system_health_monitoring_config.json | 14 + platform/broadcom/one-image.mk | 2 + platform/broadcom/platform-modules-accton.mk | 12 + .../as4625-54p/classes/__init__.py | 0 .../as4625-54p/modules/Makefile | 16 + .../modules/x86-64-accton-as4625-54p-cpld.c | 571 ++++++++++++ .../modules/x86-64-accton-as4625-54p-fan.c | 416 +++++++++ .../modules/x86-64-accton-as4625-54p-leds.c | 403 ++++++++ .../modules/x86-64-accton-as4625-54p-psu.c | 375 ++++++++ .../as4625-54p/modules/ym2651y.c | 1 + .../service/as4625-54p-platform-init.service | 17 + .../as4625-54p-platform-monitor.service | 16 + .../as4625-54p/setup.py | 14 + .../as4625-54p/sonic_platform_setup.py | 30 + .../utils/accton_as4625_54p_monitor.py | 275 ++++++ .../utils/accton_as4625_54p_util.py | 379 ++++++++ .../as4625-54t/classes/__init__.py | 0 .../as4625-54t/modules/Makefile | 16 + .../modules/x86-64-accton-as4625-54t-cpld.c | 1 + .../modules/x86-64-accton-as4625-54t-fan.c | 1 + .../modules/x86-64-accton-as4625-54t-leds.c | 1 + .../modules/x86-64-accton-as4625-54t-psu.c | 377 ++++++++ .../as4625-54t/modules/ym2651y.c | 1 + .../service/as4625-54t-platform-init.service | 17 + .../as4625-54t-platform-monitor.service | 16 + .../as4625-54t/setup.py | 14 + .../as4625-54t/sonic_platform_setup.py | 30 + .../utils/accton_as4625_54t_monitor.py | 307 +++++++ .../utils/accton_as4625_54t_util.py | 379 ++++++++ .../common/modules/ym2651y.c | 44 +- .../debian/control | 8 + .../debian/rules | 1 + .../sonic-platform-accton-as4625-54p.install | 1 + .../sonic-platform-accton-as4625-54t.install | 1 + 83 files changed, 8702 insertions(+), 7 deletions(-) create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/port_config.ini create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/sai.profile create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/default_sku create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/installer.conf create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/pcie.yaml create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/platform.json create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/platform_asic create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/platform_components.json create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/plugins/ssd_util.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/pmon_daemon_control.json create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sensors.conf create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/__init__.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/chassis.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/component.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/eeprom.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/event.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan_drawer.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/pcie.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/platform.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/sfp.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/thermal.py create mode 100644 device/accton/x86_64-accton_as4625_54p-r0/system_health_monitoring_config.json create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/port_config.ini create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/sai.profile create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/default_sku create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/installer.conf create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/pcie.yaml create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/platform.json create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/platform_asic create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/platform_components.json create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/plugins/ssd_util.py create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/pmon_daemon_control.json create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/sensors.conf create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/__init__.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/chassis.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/component.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/eeprom.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/event.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan_drawer.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/helper.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/pcie.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/platform.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/psu.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/sfp.py create mode 120000 device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/thermal.py create mode 100644 device/accton/x86_64-accton_as4625_54t-r0/system_health_monitoring_config.json create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/classes/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/Makefile create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-leds.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c create mode 120000 platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/ym2651y.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-init.service create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-monitor.service create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54p/sonic_platform_setup.py create mode 100755 platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/classes/__init__.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/Makefile create mode 120000 platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-cpld.c create mode 120000 platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-fan.c create mode 120000 platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-leds.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c create mode 120000 platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/ym2651y.c create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-init.service create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-monitor.service create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/setup.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/as4625-54t/sonic_platform_setup.py create mode 100755 platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py create mode 100755 platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py create mode 100644 platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54p.install create mode 100644 platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54t.install diff --git a/device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/port_config.ini b/device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/port_config.ini new file mode 100644 index 000000000000..a88d9f0d2357 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed autoneg +Ethernet0 25 Eth1(Port1) 1 1000 on +Ethernet1 26 Eth2(Port2) 2 1000 on +Ethernet2 27 Eth3(Port3) 3 1000 on +Ethernet3 28 Eth4(Port4) 4 1000 on +Ethernet4 29 Eth5(Port5) 5 1000 on +Ethernet5 30 Eth6(Port6) 6 1000 on +Ethernet6 31 Eth7(Port7) 7 1000 on +Ethernet7 32 Eth8(Port8) 8 1000 on +Ethernet8 33 Eth9(Port9) 9 1000 on +Ethernet9 34 Eth10(Port10) 10 1000 on +Ethernet10 35 Eth11(Port11) 11 1000 on +Ethernet11 36 Eth12(Port12) 12 1000 on +Ethernet12 37 Eth13(Port13) 13 1000 on +Ethernet13 38 Eth14(Port14) 14 1000 on +Ethernet14 39 Eth15(Port15) 15 1000 on +Ethernet15 40 Eth16(Port16) 16 1000 on +Ethernet16 41 Eth17(Port17) 17 1000 on +Ethernet17 42 Eth18(Port18) 18 1000 on +Ethernet18 43 Eth19(Port19) 19 1000 on +Ethernet19 44 Eth20(Port20) 20 1000 on +Ethernet20 49 Eth21(Port21) 21 1000 on +Ethernet21 50 Eth22(Port22) 22 1000 on +Ethernet22 51 Eth23(Port23) 23 1000 on +Ethernet23 52 Eth24(Port24) 24 1000 on +Ethernet24 1 Eth25(Port25) 25 1000 on +Ethernet25 2 Eth26(Port26) 26 1000 on +Ethernet26 3 Eth27(Port27) 27 1000 on +Ethernet27 4 Eth28(Port28) 28 1000 on +Ethernet28 5 Eth29(Port29) 29 1000 on +Ethernet29 6 Eth30(Port30) 30 1000 on +Ethernet30 7 Eth31(Port31) 31 1000 on +Ethernet31 8 Eth32(Port32) 32 1000 on +Ethernet32 9 Eth33(Port33) 33 1000 on +Ethernet33 10 Eth34(Port34) 34 1000 on +Ethernet34 11 Eth35(Port35) 35 1000 on +Ethernet35 12 Eth36(Port36) 36 1000 on +Ethernet36 13 Eth37(Port37) 37 1000 on +Ethernet37 14 Eth38(Port38) 38 1000 on +Ethernet38 15 Eth39(Port39) 39 1000 on +Ethernet39 16 Eth40(Port40) 40 1000 on +Ethernet40 17 Eth41(Port41) 41 1000 on +Ethernet41 18 Eth42(Port42) 42 1000 on +Ethernet42 19 Eth43(Port43) 43 1000 on +Ethernet43 20 Eth44(Port44) 44 1000 on +Ethernet44 21 Eth45(Port45) 45 1000 on +Ethernet45 22 Eth46(Port46) 46 1000 on +Ethernet46 23 Eth47(Port47) 47 1000 on +Ethernet47 24 Eth48(Port48) 48 1000 on +Ethernet48 57 Eth49(Port49) 49 10000 off +Ethernet49 58 Eth50(Port50) 50 10000 off +Ethernet50 59 Eth51(Port51) 51 10000 off +Ethernet51 60 Eth52(Port52) 52 10000 off +Ethernet52 61 Eth53(Port53) 53 10000 off +Ethernet53 62 Eth54(Port54) 54 10000 off diff --git a/device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/sai.profile b/device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/sai.profile new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/Accton-AS4625-54P/sai.profile @@ -0,0 +1 @@ + diff --git a/device/accton/x86_64-accton_as4625_54p-r0/default_sku b/device/accton/x86_64-accton_as4625_54p-r0/default_sku new file mode 100644 index 000000000000..cfcb3278f4ae --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/default_sku @@ -0,0 +1 @@ +Accton-AS4625-54P t1 diff --git a/device/accton/x86_64-accton_as4625_54p-r0/installer.conf b/device/accton/x86_64-accton_as4625_54p-r0/installer.conf new file mode 100644 index 000000000000..85bb317cc906 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" diff --git a/device/accton/x86_64-accton_as4625_54p-r0/pcie.yaml b/device/accton/x86_64-accton_as4625_54p-r0/pcie.yaml new file mode 100644 index 000000000000..b7482437b980 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/pcie.yaml @@ -0,0 +1,149 @@ +- bus: '00' + dev: '00' + fn: '0' + id: '1980' + name: 'Host bridge: Intel Corporation Atom Processor C3000 Series System Agent (rev + 11)' +- bus: '00' + dev: '04' + fn: '0' + id: 19a1 + name: 'Host bridge: Intel Corporation Atom Processor C3000 Series Error Registers + (rev 11)' +- bus: '00' + dev: '05' + fn: '0' + id: 19a2 + name: 'Generic system peripheral [0807]: Intel Corporation Atom Processor C3000 + Series Root Complex Event Collector (rev 11)' +- bus: '00' + dev: '06' + fn: '0' + id: 19a3 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated QAT + Root Port (rev 11)' +- bus: '00' + dev: 09 + fn: '0' + id: 19a4 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #0 (rev 11)' +- bus: '00' + dev: 0e + fn: '0' + id: 19a8 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #4 (rev 11)' +- bus: '00' + dev: 0f + fn: '0' + id: 19a9 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #5 (rev 11)' +- bus: '00' + dev: '12' + fn: '0' + id: 19ac + name: 'System peripheral: Intel Corporation Atom Processor C3000 Series SMBus Contoller + - Host (rev 11)' +- bus: '00' + dev: '14' + fn: '0' + id: 19c2 + name: 'SATA controller: Intel Corporation Atom Processor C3000 Series SATA Controller + 1 (rev 11)' +- bus: '00' + dev: '15' + fn: '0' + id: 19d0 + name: 'USB controller: Intel Corporation Atom Processor C3000 Series USB 3.0 xHCI + Controller (rev 11)' +- bus: '00' + dev: '16' + fn: '0' + id: 19d1 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated LAN + Root Port #0 (rev 11)' +- bus: '00' + dev: '17' + fn: '0' + id: 19d2 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated LAN + Root Port #1 (rev 11)' +- bus: '00' + dev: '18' + fn: '0' + id: 19d3 + name: 'Communication controller: Intel Corporation Atom Processor C3000 Series ME + HECI 1 (rev 11)' +- bus: '00' + dev: 1f + fn: '0' + id: 19dc + name: 'ISA bridge: Intel Corporation Atom Processor C3000 Series LPC or eSPI (rev + 11)' +- bus: '00' + dev: 1f + fn: '1' + id: 19dd + name: 'Memory controller: Intel Corporation Atom Processor C3000 Series Primary + to Side Band (P2SB) Bridge (rev 11)' +- bus: '00' + dev: 1f + fn: '2' + id: 19de + name: 'Memory controller: Intel Corporation Atom Processor C3000 Series Power Management + Controller (rev 11)' +- bus: '00' + dev: 1f + fn: '4' + id: 19df + name: 'SMBus: Intel Corporation Atom Processor C3000 Series SMBus controller (rev + 11)' +- bus: '00' + dev: 1f + fn: '5' + id: 19e0 + name: 'Serial bus controller [0c80]: Intel Corporation Atom Processor C3000 Series + SPI Controller (rev 11)' +- bus: '01' + dev: '00' + fn: '0' + id: 19e2 + name: 'Co-processor: Intel Corporation Atom Processor C3000 Series QuickAssist Technology + (rev 11)' +- bus: '02' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '03' + dev: '00' + fn: '0' + id: b277 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b277 (rev 02)' +- bus: '05' + dev: '00' + fn: '0' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '05' + dev: '00' + fn: '1' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '07' + dev: '00' + fn: '0' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '07' + dev: '00' + fn: '1' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' diff --git a/device/accton/x86_64-accton_as4625_54p-r0/platform.json b/device/accton/x86_64-accton_as4625_54p-r0/platform.json new file mode 100644 index 000000000000..67dfb273ad93 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/platform.json @@ -0,0 +1,860 @@ +{ + "chassis": { + "name": "AS4625-54P", + "thermal_manager": false, + "status_led": { + "controllable": true, + "colors": [ "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_GREEN_BLINKING" ] + }, + "components": [ + { + "name": "MB_CPLD" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + }, + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + }, + { + "name": "FAN-3", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray-1", + "num_fans" : 1, + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray-2", + "num_fans" : 1, + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray-3", + "num_fans" : 1, + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FAN-3", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU-1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-1 FAN-1", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false + } + } + ], + "thermals": [ + { + "name": "PSU-1 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "PSU-1 temp sensor 2", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "temperature": true, + "temperature_high_threshold": true + }, + { + "name": "PSU-2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-2 FAN-1", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false + } + } + ], + "thermals": [ + { + "name": "PSU-2 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "PSU-2 temp sensor 2", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "temperature": true, + "temperature_high_threshold": true + } + ], + "thermals": [ + { + "name": "MB_Temp(0x4a)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + + }, + { + "name": "MB_Temp(0x4b)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_Temp(0x4d)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_Temp(0x4e)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_Temp(0x4f)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name" : "CPU Package Temp", + "controllable": false, + "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": false + }, + { + "name" : "CPU Core 1 Temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name" : "CPU Core 2 Temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name" : "CPU Core 3 Temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "sfps": [ + { + "name": "Ethernet0" + }, + { + "name": "Ethernet1" + }, + { + "name": "Ethernet2" + }, + { + "name": "Ethernet3" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet5" + }, + { + "name": "Ethernet6" + }, + { + "name": "Ethernet7" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet9" + }, + { + "name": "Ethernet10" + }, + { + "name": "Ethernet11" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet13" + }, + { + "name": "Ethernet14" + }, + { + "name": "Ethernet15" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet17" + }, + { + "name": "Ethernet18" + }, + { + "name": "Ethernet19" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet21" + }, + { + "name": "Ethernet22" + }, + { + "name": "Ethernet23" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet25" + }, + { + "name": "Ethernet26" + }, + { + "name": "Ethernet27" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet29" + }, + { + "name": "Ethernet30" + }, + { + "name": "Ethernet31" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet33" + }, + { + "name": "Ethernet34" + }, + { + "name": "Ethernet35" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet37" + }, + { + "name": "Ethernet38" + }, + { + "name": "Ethernet39" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet41" + }, + { + "name": "Ethernet42" + }, + { + "name": "Ethernet43" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet45" + }, + { + "name": "Ethernet46" + }, + { + "name": "Ethernet47" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet49" + }, + { + "name": "Ethernet50" + }, + { + "name": "Ethernet51" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet53" + } + ] + }, + "interfaces": { + "Ethernet0": { + "index": "1", + "lanes": "25", + "breakout_modes": { + "1x1G": ["Eth1(Port1)"] + } + }, + + "Ethernet1": { + "index": "2", + "lanes": "26", + "breakout_modes": { + "1x1G": ["Eth2(Port2)"] + } + }, + + "Ethernet2": { + "index": "3", + "lanes": "27", + "breakout_modes": { + "1x1G": ["Eth3(Port3)"] + } + }, + + "Ethernet3": { + "index": "4", + "lanes": "28", + "breakout_modes": { + "1x1G": ["Eth4(Port4)"] + } + }, + + "Ethernet4": { + "index": "5", + "lanes": "29", + "breakout_modes": { + "1x1G": ["Eth5(Port5)"] + } + }, + + "Ethernet5": { + "index": "6", + "lanes": "30", + "breakout_modes": { + "1x1G": ["Eth6(Port6)"] + } + }, + + "Ethernet6": { + "index": "7", + "lanes": "31", + "breakout_modes": { + "1x1G": ["Eth7(Port7)"] + } + }, + + "Ethernet7": { + "index": "8", + "lanes": "32", + "breakout_modes": { + "1x1G": ["Eth8(Port8)"] + } + }, + + "Ethernet8": { + "index": "9", + "lanes": "33", + "breakout_modes": { + "1x1G": ["Eth9(Port9)"] + } + }, + + "Ethernet9": { + "index": "10", + "lanes": "34", + "breakout_modes": { + "1x1G": ["Eth10(Port10)"] + } + }, + + "Ethernet10": { + "index": "11", + "lanes": "35", + "breakout_modes": { + "1x1G": ["Eth11(Port11)"] + } + }, + + "Ethernet11": { + "index": "12", + "lanes": "36", + "breakout_modes": { + "1x1G": ["Eth12(Port12)"] + } + }, + + "Ethernet12": { + "index": "13", + "lanes": "37", + "breakout_modes": { + "1x1G": ["Eth13(Port13)"] + } + }, + + "Ethernet13": { + "index": "14", + "lanes": "38", + "breakout_modes": { + "1x1G": ["Eth14(Port14)"] + } + }, + + "Ethernet14": { + "index": "15", + "lanes": "39", + "breakout_modes": { + "1x1G": ["Eth15(Port15)"] + } + }, + + "Ethernet15": { + "index": "16", + "lanes": "40", + "breakout_modes": { + "1x1G": ["Eth16(Port16)"] + } + }, + + "Ethernet16": { + "index": "17", + "lanes": "41", + "breakout_modes": { + "1x1G": ["Eth17(Port17)"] + } + }, + + "Ethernet17": { + "index": "18", + "lanes": "42", + "breakout_modes": { + "1x1G": ["Eth18(Port18)"] + } + }, + + "Ethernet18": { + "index": "19", + "lanes": "43", + "breakout_modes": { + "1x1G": ["Eth19(Port19)"] + } + }, + + "Ethernet19": { + "index": "20", + "lanes": "44", + "breakout_modes": { + "1x1G": ["Eth20(Port20)"] + } + }, + + "Ethernet20": { + "index": "21", + "lanes": "49", + "breakout_modes": { + "1x1G": ["Eth21(Port21)"] + } + }, + + "Ethernet21": { + "index": "22", + "lanes": "50", + "breakout_modes": { + "1x1G": ["Eth22(Port22)"] + } + }, + + "Ethernet22": { + "index": "23", + "lanes": "51", + "breakout_modes": { + "1x1G": ["Eth23(Port23)"] + } + }, + + "Ethernet23": { + "index": "24", + "lanes": "52", + "breakout_modes": { + "1x1G": ["Eth24(Port24)"] + } + }, + + "Ethernet24": { + "index": "25", + "lanes": "1", + "breakout_modes": { + "1x1G": ["Eth25(Port25)"] + } + }, + + "Ethernet25": { + "index": "26", + "lanes": "2", + "breakout_modes": { + "1x1G": ["Eth26(Port26)"] + } + }, + + "Ethernet26": { + "index": "27", + "lanes": "3", + "breakout_modes": { + "1x1G": ["Eth27(Port27)"] + } + }, + + "Ethernet27": { + "index": "28", + "lanes": "4", + "breakout_modes": { + "1x1G": ["Eth28(Port28)"] + } + }, + + "Ethernet28": { + "index": "29", + "lanes": "5", + "breakout_modes": { + "1x1G": ["Eth29(Port29)"] + } + }, + + "Ethernet29": { + "index": "30", + "lanes": "6", + "breakout_modes": { + "1x1G": ["Eth30(Port30)"] + } + }, + + "Ethernet30": { + "index": "31", + "lanes": "7", + "breakout_modes": { + "1x1G": ["Eth31(Port31)"] + } + }, + + "Ethernet31": { + "index": "32", + "lanes": "8", + "breakout_modes": { + "1x1G": ["Eth32(Port32)"] + } + }, + + "Ethernet32": { + "index": "33", + "lanes": "9", + "breakout_modes": { + "1x1G": ["Eth33(Port33)"] + } + }, + + "Ethernet33": { + "index": "34", + "lanes": "10", + "breakout_modes": { + "1x1G": ["Eth34(Port34)"] + } + }, + + "Ethernet34": { + "index": "35", + "lanes": "11", + "breakout_modes": { + "1x1G": ["Eth35(Port35)"] + } + }, + + "Ethernet35": { + "index": "36", + "lanes": "12", + "breakout_modes": { + "1x1G": ["Eth36(Port36)"] + } + }, + + "Ethernet36": { + "index": "37", + "lanes": "13", + "breakout_modes": { + "1x1G": ["Eth37(Port37)"] + } + }, + + "Ethernet37": { + "index": "38", + "lanes": "14", + "breakout_modes": { + "1x1G": ["Eth38(Port38)"] + } + }, + + "Ethernet38": { + "index": "39", + "lanes": "15", + "breakout_modes": { + "1x1G": ["Eth39(Port39)"] + } + }, + + "Ethernet39": { + "index": "40", + "lanes": "16", + "breakout_modes": { + "1x1G": ["Eth40(Port40)"] + } + }, + + "Ethernet40": { + "index": "41", + "lanes": "17", + "breakout_modes": { + "1x1G": ["Eth41(Port41)"] + } + }, + + "Ethernet41": { + "index": "42", + "lanes": "18", + "breakout_modes": { + "1x1G": ["Eth42(Port42)"] + } + }, + + "Ethernet42": { + "index": "43", + "lanes": "19", + "breakout_modes": { + "1x1G": ["Eth43(Port43)"] + } + }, + + "Ethernet43": { + "index": "44", + "lanes": "20", + "breakout_modes": { + "1x1G": ["Eth44(Port44)"] + } + }, + + "Ethernet44": { + "index": "45", + "lanes": "21", + "breakout_modes": { + "1x1G": ["Eth45(Port45)"] + } + }, + + "Ethernet45": { + "index": "46", + "lanes": "22", + "breakout_modes": { + "1x1G": ["Eth46(Port46)"] + } + }, + + "Ethernet46": { + "index": "47", + "lanes": "23", + "breakout_modes": { + "1x1G": ["Eth47(Port47)"] + } + }, + + "Ethernet47": { + "index": "48", + "lanes": "24", + "breakout_modes": { + "1x1G": ["Eth48(Port48)"] + } + }, + + "Ethernet48": { + "index": "49", + "lanes": "57", + "breakout_modes": { + "1x10G[1G]": ["Eth49(Port49)"] + } + }, + + "Ethernet49": { + "index": "50", + "lanes": "58", + "breakout_modes": { + "1x10G[1G]": ["Eth50(Port50)"] + } + }, + + "Ethernet50": { + "index": "51", + "lanes": "59", + "breakout_modes": { + "1x10G[1G]": ["Eth51(Port51)"] + } + }, + + "Ethernet51": { + "index": "52", + "lanes": "60", + "breakout_modes": { + "1x10G[1G]": ["Eth52(Port52)"] + } + }, + + "Ethernet52": { + "index": "53", + "lanes": "61", + "breakout_modes": { + "1x10G[1G]": ["Eth53(Port53)"] + } + }, + + "Ethernet53": { + "index": "54", + "lanes": "62", + "breakout_modes": { + "1x10G[1G]": ["Eth54(Port54)"] + } + } + } +} diff --git a/device/accton/x86_64-accton_as4625_54p-r0/platform_asic b/device/accton/x86_64-accton_as4625_54p-r0/platform_asic new file mode 100644 index 000000000000..960467652765 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/accton/x86_64-accton_as4625_54p-r0/platform_components.json b/device/accton/x86_64-accton_as4625_54p-r0/platform_components.json new file mode 100644 index 000000000000..c22530cc124c --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/platform_components.json @@ -0,0 +1,10 @@ +{ + "chassis": { + "4625-54P-O-AC-F": { + "component": { + "MB_CPLD": { }, + "BIOS": { } + } + } + } +} diff --git a/device/accton/x86_64-accton_as4625_54p-r0/plugins/ssd_util.py b/device/accton/x86_64-accton_as4625_54p-r0/plugins/ssd_util.py new file mode 100644 index 000000000000..4b173c5e3890 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/plugins/ssd_util.py @@ -0,0 +1,24 @@ +# ssd_util.py +# +# Platform-specific SSD interface for SONiC +## + +try: + from sonic_platform_base.sonic_ssd.ssd_generic import SsdUtil as MainSsdUtil +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +NOT_AVAILABLE = "N/A" + +class SsdUtil(MainSsdUtil): + """Platform-specific SsdUtil class""" + + def __init__(self, diskdev): + super(SsdUtil, self).__init__(diskdev) + + # If it has no vendor tool to read SSD information, + # ssd_util.py will use generic SSD information + # for vendor SSD information. + if self.vendor_ssd_info == NOT_AVAILABLE: + self.vendor_ssd_info = self.ssd_info + diff --git a/device/accton/x86_64-accton_as4625_54p-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4625_54p-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..79344cad0bd9 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true, + "skip_xcvrd_cmis_mgr": true +} diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sensors.conf b/device/accton/x86_64-accton_as4625_54p-r0/sensors.conf new file mode 100644 index 000000000000..1f4571ec603b --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sensors.conf @@ -0,0 +1,50 @@ +# libsensors configuration file for as4625 +# ------------------------------------------------ +# +bus "i2c-3" "i2c-1-mux (chan_id 1)" +bus "i2c-8" "i2c-1-mux (chan_id 6)" +bus "i2c-9" "i2c-1-mux (chan_id 7)" + +chip "ym2651-i2c-*-58" + label in3 "PSU 1 Voltage" + label fan1 "PSU 1 Fan" + label temp1 "PSU 1 Temperature" + label power2 "PSU 1 Power" + label curr2 "PSU 1 Current" + +chip "ym2651-i2c-*-59" + label in3 "PSU 2 Voltage" + label fan1 "PSU 2 Fan" + label temp1 "PSU 2 Temperature" + label power2 "PSU 2 Power" + label curr2 "PSU 2 Current" + +chip "as4625_fan-*" + label fan1 "Fan 1" + label fan2 "Fan 2" + label fan3 "Fan 3" + +chip "lm75-i2c-*-4a" + label temp1 "MB_Temp(0x4a)" + +chip "lm75-i2c-*-4b" + label temp1 "MB_Temp(0x4b)" + +chip "lm75-i2c-*-4d" + label temp1 "MB_Temp(0x4d)" + +chip "lm75-i2c-*-4e" + label temp1 "MB_Temp(0x4e)" + +chip "lm75-i2c-*-4f" + label temp1 "MB_Temp(0x4f)" + +chip "coretemp-isa-0000" + label temp2 "Core 0" + label temp4 "Core 0" + label temp6 "Core 1" + label temp8 "Core 1" + label temp10 "Core 2" + label temp12 "Core 2" + label temp14 "Core 3" + label temp16 "Core 3" diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/__init__.py new file mode 100644 index 000000000000..cea4c512bfdd --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = [ 'platform', 'chassis', 'component', 'eeprom', 'psu', 'sfp', 'thermal', 'fan', 'fan_drawer' ] +from . import platform diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/chassis.py new file mode 100644 index 000000000000..fe8319089b7e --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/chassis.py @@ -0,0 +1,253 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# +import sys +import subprocess + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .event import SfpEvent +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 3 +NUM_FAN = 1 +NUM_PSU = 2 +NUM_THERMAL = 10 +PORT_START = 1 +PORT_END = 54 +NUM_COMPONENT = 2 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = ["which", "systemctl"] +SYSLED_FNODE= "/sys/class/leds/as4625_led::sys/brightness" + +SYSLED_MODES = { + "1" : "STATUS_LED_COLOR_GREEN", + "2" : "STATUS_LED_COLOR_GREEN_BLINKING", + "3" : "STATUS_LED_COLOR_AMBER" +} + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + for index in range(1, PORT_END+1): + sfp_module = Sfp(index, 'SFP') + self._sfp_list.append(sfp_module) + + self._sfpevent = SfpEvent(self._sfp_list) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, NUM_THERMAL): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __is_host(self): + return subprocess.call(HOST_CHK_CMD) == 0 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self._eeprom.get_product_name() + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + 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_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.get_mac() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.get_eeprom() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + + 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 get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + + return self._sfpevent.get_sfp_event(timeout) + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + # The index will start from 1 + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def initizalize_system_led(self): + return True + + def get_status_led(self): + val = self._api_helper.read_txt_file(SYSLED_FNODE) + return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN" + + def set_status_led(self, color): + mode = None + for key, val in SYSLED_MODES.items(): + if val == color: + mode = key + break + if mode is None: + return False + else: + return self._api_helper.write_txt_file(SYSLED_FNODE, mode) + + def get_port_or_cage_type(self, port): + from sonic_platform_base.sfp_base import SfpBase + if port in range(1, 49): + return SfpBase.SFP_PORT_TYPE_BIT_RJ45 + elif port in range(49, 55): + return SfpBase.SFP_PORT_TYPE_BIT_SFP | SfpBase.SFP_PORT_TYPE_BIT_SFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_SFP28 + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return 'N/A' diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/component.py new file mode 100644 index 000000000000..281913745614 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/component.py @@ -0,0 +1,152 @@ +############################################################################# +# Edgecore +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# +try: + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_PATH_MAPPING = { + "CPLD_MAJOR": "/sys/bus/i2c/devices/0-0064/version_major", + "CPLD_MINOR": "/sys/bus/i2c/devices/0-0064/version_minor" +} + +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("MB_CPLD", "Mainboard CPLD(0x64)"), + ("BIOS", "Basic Input/Output System") +] + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + return fd.read().strip() + except Exception as e: + print('Get exception when read bios') + return None + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_version = dict() + version_list = list() + for index, cpld_name in enumerate(CPLD_PATH_MAPPING): + try: + cpld_path = "{}".format(CPLD_PATH_MAPPING[cpld_name]) + cpld_version_raw = self._api_helper.read_txt_file(cpld_path) + version_list.append("{:x}".format(int(cpld_version_raw,10))) + except Exception as e: + print('Get exception when read cpld (%s)', cpld_path) + cpld_version["MB_CPLD"] = 'None' + return cpld_version + + cpld_version["MB_CPLD"] = version_list[0] + '.' + version_list[1] + return cpld_version + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "CPLD" in self.name: + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) + + return fw_version + + def install_firmware(self, image_path): + """ + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError + + 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/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/eeprom.py new file mode 100644 index 000000000000..b89e54d6bb7a --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/eeprom.py @@ -0,0 +1,134 @@ +try: + import os + import sys + import re + if sys.version_info[0] >= 3: + from io import StringIO + else: + from cStringIO import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' +NULL = 'N/A' + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/7-0051/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)(.+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + + def get_eeprom(self): + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) + + def get_serial(self): + return self._eeprom.get('0x23', NULL) + + def get_mac(self): + return self._eeprom.get('0x24', NULL) + + def get_product_name(self): + return self._eeprom.get('0x21', NULL) diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/event.py new file mode 100644 index 000000000000..6e8c08ce20fd --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/event.py @@ -0,0 +1,117 @@ +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 ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.get_position_in_parent() - 1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.get_position_in_parent() - 1 + if (changed_ports & (1 << i)) == 0: + continue + + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + 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.refresh() + if status is not True: + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + else: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BAD_EEPROM + 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/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan.py new file mode 100644 index 000000000000..b780ed8be1f0 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan.py @@ -0,0 +1,314 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# +import glob + +try: + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_FAN_MAX_RPM = 25500 +SPEED_TOLERANCE = 15 + +FAN_HWMON_I2C_PATH = "/sys/devices/platform/as4625_fan/hwmon/hwmon*/fan" + +I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_PMBUS_I2C_MAPPING = { + 0: { + "num": 8, + "addr": "58" + }, + 1: { + "num": 9, + "addr": "59" + } +} + +PSU_EEPROM_I2C_MAPPING = { + 0: { + "num": 8, + "addr": "50" + }, + 1: { + "num": 9, + "addr": "51" + } +} + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + + if not self.is_psu_fan: + self.hwmon_path = FAN_HWMON_I2C_PATH + else: + self.psu_index = psu_index + i2c_num = PSU_PMBUS_I2C_MAPPING[self.psu_index]['num'] + i2c_addr = PSU_PMBUS_I2C_MAPPING[self.psu_index]['addr'] + self.hwmon_path = I2C_PATH.format(i2c_num, i2c_addr) + + i2c_num = PSU_EEPROM_I2C_MAPPING[self.psu_index]['num'] + i2c_addr = PSU_EEPROM_I2C_MAPPING[self.psu_index]['addr'] + self.psu_eeprom_path = I2C_PATH.format(i2c_num, i2c_addr) + + FanBase.__init__(self) + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data = fd.readline().rstrip() + if len(data) > 0: + return data + except IOError as e: + pass + + return None + + def __write_txt_file(self, file_path, value): + for filename in glob.glob(file_path): + try: + with open(filename, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + if self.is_psu_fan: #For PSU + dir_str = "{}{}".format(self.psu_eeprom_path,'psu_fan_dir') + else: + dir_str = "{}{}{}".format(self.hwmon_path, self.fan_tray_index+1, '_dir') + + val = self.__read_txt_file(dir_str) + if val is not None: + if val == 'B2F': + direction = self.FAN_DIRECTION_INTAKE + else: + direction = self.FAN_DIRECTION_EXHAUST + else: + direction = self.FAN_DIRECTION_NOT_APPLICABLE + + return direction + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + + """ + speed = 0 + if self.is_psu_fan: + path = "{}{}".format(self.hwmon_path, 'fan1_input') + rpm = self.__read_txt_file(path) + if rpm is not None: + speed = (int(rpm, 10)) * 100 / PSU_FAN_MAX_RPM + if speed > 100: + speed = 100 + else: + return 0 + + else: + input_path = "{}{}{}".format(self.hwmon_path, self.fan_tray_index+1, '_input') + input = self.__read_txt_file(input_path) + target_rpm_path = "{}{}{}".format(self.hwmon_path, self.fan_tray_index+1, '_target_rpm') + target_rpm = self.__read_txt_file(target_rpm_path) + pwm = self.get_target_speed() + + if input is None or target_rpm is None or pwm is None: + return 0 + + if int(target_rpm) > 0: + speed = pwm * int(input) / int(target_rpm) + if speed > 100: + speed = 100 + + return int(speed) + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + + Note: + speed_pc = pwm_target/255*100 + + 0 : when PWM mode is use + pwm : when pwm mode is not use + """ + if not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}{}".format(self.hwmon_path, self.fan_tray_index+1, '_pwm') + speed = self.__read_txt_file(speed_path) + if speed is None: + return 0 + return int(speed) + else: + return self.get_speed() + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return SPEED_TOLERANCE + + def set_speed(self, speed): + """ + Sets the fan speed + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + A boolean, True if speed is set successfully, False if not + + """ + + if not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}{}".format(self.hwmon_path, self.fan_tray_index+1, '_pwm') + return self.__write_txt_file(speed_path, int(speed)) + + return False + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if not self.is_psu_fan: + return None + + if self.get_presence() is not True: + return None + + return { + True: self.STATUS_LED_COLOR_GREEN, + False: self.STATUS_LED_COLOR_AMBER + }.get(self.get_status(), self.STATUS_LED_COLOR_AMBER) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + if self.is_psu_fan: + return "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + + return "FAN-{}".format(self.fan_tray_index+1) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + if self.is_psu_fan: + present_path = "{}{}".format(self.psu_eeprom_path, 'psu_present') + val = self.__read_txt_file(present_path) + if val is not None: + return int(val, 10) == 1 + else: + return False + else: + return True + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: + if self.get_presence() is not True: + return None + + power_path = "{}{}".format(self.psu_eeprom_path, 'psu_power_good') + val = self.__read_txt_file(power_path) + if val is not None: + if int(val, 10) != 1: + return False + + psu_fan_path= "{}{}".format(self.hwmon_path, 'fan1_input') + val=self.__read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10) != 0 + else: + return False + else: + path = "{}{}{}".format(self.hwmon_path, self.fan_tray_index+1, '_fault') + val=self.__read_txt_file(path) + if val is not None: + return int(val, 10) == 0 + else: + return False + + 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 is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return (self.fan_tray_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..f07c67be0735 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,116 @@ +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 1 + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + FanDrawerBase.__init__(self) + self.fantrayindex = fantray_index + # FanTray is 0-based in platforms + self.__initialize_fan() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(self.fantrayindex, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray-{}".format(self.fantrayindex + 1) + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + from sonic_platform.fan import Fan + + for fan in self._fan_list: + if not fan.get_status(): + return False + + 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 self.fantrayindex+1 + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return { + True: self.STATUS_LED_COLOR_GREEN, + False: self.STATUS_LED_COLOR_AMBER + }.get(self.get_status(), self.STATUS_LED_COLOR_AMBER) + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False #Not supported + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py new file mode 100644 index 000000000000..28e01d6e458c --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py @@ -0,0 +1,324 @@ +import os +import struct +import json +import fcntl +from mmap import * +from sonic_py_common import device_info +from sonic_py_common.general import getstatusoutput_noshell +from sonic_py_common import logger +from threading import Lock +from typing import cast + +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, encoding='unicode_escape', 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)) + fd.flush() + except IOError: + return False + return True +class 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" +HIGH_THRESHOLD_FIELD = 'high_threshold' +LOW_THRESHOLD_FIELD = 'low_threshold' +HIGH_CRIT_THRESHOLD_FIELD = 'high_critical_threshold' +LOW_CRIT_THRESHOLD_FIELD = 'low_critical_threshold' +NOT_AVAILABLE = 'N/A' + +class DeviceThreshold: + + 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 = {} + try: + with self.flock: + with open(DEVICE_THRESHOLD_JSON_PATH, "r") as db_file: + self.__db_data = json.load(db_file) + except Exception as e: + pass + + @property + def HIGH_THRESHOLD_FIELD(self): + return HIGH_THRESHOLD_FIELD + + @property + def LOW_THRESHOLD_FIELD(self): + return LOW_THRESHOLD_FIELD + + @property + def HIGH_CRIT_THRESHOLD_FIELD(self): + return HIGH_CRIT_THRESHOLD_FIELD + + @property + def LOW_CRIT_THRESHOLD_FIELD(self): + return LOW_CRIT_THRESHOLD_FIELD + + @property + def NOT_AVAILABLE(self): + return NOT_AVAILABLE + + 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 self.name not in self.__db_data.keys(): + return NOT_AVAILABLE + + if field not in self.__db_data[self.name].keys(): + return 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 = "w+" + if os.path.exists(DEVICE_THRESHOLD_JSON_PATH): + mode = "r+" + 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) + 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(HIGH_THRESHOLD_FIELD) + + 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 != NOT_AVAILABLE: + tmp = float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(HIGH_THRESHOLD_FIELD, 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(LOW_THRESHOLD_FIELD) + + 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 != NOT_AVAILABLE: + tmp = float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(LOW_THRESHOLD_FIELD, 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(HIGH_CRIT_THRESHOLD_FIELD) + + 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 != NOT_AVAILABLE: + tmp = float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(HIGH_CRIT_THRESHOLD_FIELD, 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(LOW_CRIT_THRESHOLD_FIELD) + + 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 != NOT_AVAILABLE: + tmp = float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(LOW_CRIT_THRESHOLD_FIELD, temperature) \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/pcie.py new file mode 100644 index 000000000000..e4da32adf9f8 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/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) diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/platform.py new file mode 100644 index 000000000000..aa5ab500dd5b --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/platform.py @@ -0,0 +1,20 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py new file mode 100644 index 000000000000..08ca93625469 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py @@ -0,0 +1,334 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +#import sonic_platform + +try: + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.thermal import Thermal + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_PMBUS_I2C_MAPPING = { + 0: { + "num": 8, + "addr": "58" + }, + 1: { + "num": 9, + "addr": "59" + } +} + +PSU_EEPROM_I2C_MAPPING = { + 0: { + "num": 8, + "addr": "50" + }, + 1: { + "num": 9, + "addr": "51" + } +} + +PSU_NUM_FAN = [1, 1] +THERMAL_COUNT_PER_PSU = 2 + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self._api_helper = APIHelper() + self.index = psu_index + + self.i2c_num = PSU_PMBUS_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_PMBUS_I2C_MAPPING[self.index]["addr"] + self.pmbus_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.i2c_num = PSU_EEPROM_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_EEPROM_I2C_MAPPING[self.index]["addr"] + self.eeprom_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.__initialize_fan() + self.__initialize_thermal() + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) + + def __initialize_thermal(self): + from sonic_platform.thermal import Thermal + for thermal_id in range(0, THERMAL_COUNT_PER_PSU): + thermal = Thermal(thermal_index=thermal_id, is_psu=True, psu_index=self.index) + self._thermal_list.append(thermal) + + 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 None + + vout_path = "{}{}".format(self.pmbus_path, 'psu_v_out') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val) / 1000 + else: + return None + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + if self.get_status() is not True: + return None + + iout_path = "{}{}".format(self.pmbus_path, 'psu_i_out') + val = self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val) / 1000 + else: + return None + + 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 None + + pout_path = "{}{}".format(self.pmbus_path, 'psu_p_out') + val = self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val) / 1000 + else: + return None + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + + return True #Controlled by HW + + def get_status_led(self): + """ + Gets the state of the PSU status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_presence() is not True: + return None + + return { + True: self.STATUS_LED_COLOR_GREEN, + False: self.STATUS_LED_COLOR_AMBER + }.get(self.get_status(), None) + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + if self.get_status() is not True: + return None + + temp_path = "{}{}".format(self.pmbus_path, 'psu_temp2_input') + val = self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val) / 1000 + else: + return None + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + if self.get_status() is not True: + return None + + vout_path = "{}{}".format(self.pmbus_path, 'psu_mfr_vout_max') + vout_val = self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val) / 1000 + else: + return None + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + if self.get_status() is not True: + return None + + vout_path = "{}{}".format(self.pmbus_path, 'psu_mfr_vout_min') + vout_val = self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val) / 1000 + else: + return None + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + if self.get_status() is not True: + return None + + pout_path = "{}{}".format(self.pmbus_path, 'psu_mfr_pout_max') + val = self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val) / 1000 + else: + return None + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return "PSU-{}".format(self.index+1) + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_path = "{}{}".format(self.eeprom_path, 'psu_present') + val = self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path = "{}{}".format(self.eeprom_path, 'psu_power_good') + val = self._api_helper.read_txt_file(power_path) + if val is not None: + return int(val, 10) == 1 + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + if self.get_status() is not True: + return "N/A" + + model_path = "{}{}".format(self.eeprom_path, 'psu_model_name') + model = self._api_helper.read_txt_file(model_path) + + if model is None: + return "N/A" + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + if self.get_status() is not True: + return "N/A" + + serial_path = "{}{}".format(self.eeprom_path, 'psu_serial_numer') + serial = self._api_helper.read_txt_file(serial_path) + + if serial is None: + return "N/A" + return serial + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + 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 self.index+1 + + 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 + """ + return self._thermal_list[0].get_high_threshold() + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + revision_path = "{}{}".format(self.pmbus_path, 'psu_mfr_revision') + revision = self._api_helper.read_txt_file(revision_path) + if revision is not None: + return revision + else: + return 'N/A' diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/sfp.py new file mode 100644 index 000000000000..cc0afb5424d4 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/sfp.py @@ -0,0 +1,283 @@ +############################################################################# +# Edgecore +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# +import subprocess + +try: + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from sonic_py_common import device_info + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +#Edge-core definitions +CPLD1_I2C_PATH = "/sys/bus/i2c/devices/0-0064/" +I2C_EEPROM_PATH = '/sys/bus/i2c/devices/{0}-0050/eeprom' + +OPTOE1_TYPE_LIST = [ + 0x0D, # QSFP+ or later + 0x11 # QSFP28 or later +] +OPTOE2_TYPE_LIST = [ + 0x03 # SFP/SFP+/SFP28 and later +] +OPTOE3_TYPE_LIST = [ + 0x18, # QSFP-DD + 0x19, # OSFP + 0x1E # QSFP+ or later with CMIS +] + +class Sfp(SfpOptoeBase): + """Platform-specific Sfp class""" + HOST_CHK_CMD = ["which", "systemctl"] + + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + + SFP_PORT_START = 49 + SFP_PORT_END = 54 + + _port_to_i2c_mapping = { + 49: [10], + 50: [11], + 51: [12], + 52: [13], + 53: [14], + 54: [15] + } + + def __init__(self, sfp_index=1, sfp_name=None): + SfpOptoeBase.__init__(self) + self.index = sfp_index + self.port_num = self.index + self._api_helper = APIHelper() + self._name = sfp_name + + if self.SFP_PORT_START <= self.port_num <= self.SFP_PORT_END: + self.eeprom_path = I2C_EEPROM_PATH.format(self._port_to_i2c_mapping[self.port_num][0]) + SfpOptoeBase.__init__(self) + self.refresh() + + def get_eeprom_path(self): + return self.eeprom_path + + def __is_host(self): + return subprocess.call(self.HOST_CHK_CMD) == 0 + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + return False # SFP port doesn't support this feature + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + return False # SFP port doesn't support this feature + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + port_config_file_path = device_info.get_path_to_port_config_file() + sfputil_helper.read_porttab_mappings(port_config_file_path) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + if self.port_num < self.SFP_PORT_START: + return False + + present_path = "{}{}{}".format(CPLD1_I2C_PATH, '/module_present_', self.port_num) + val = self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10) == 1 + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() + + def refresh(self): + self.refresh_xcvr_api() + return True + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + return False + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + # SFP doesn't support this feature + return False + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + return False + + def get_position_in_parent(self): + """Retrieves 1-based relative physical position in parent device.""" + return self.port_num + + def is_replaceable(self): + """ + Retrieves if replaceable + Returns: + A boolean value, True if replaceable + """ + return True + + 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 + 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 + 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 + if checksum_test != eeprom_raw[95]: + return False + + return True + + def validate_eeprom(self): + id_byte_raw = self.read_eeprom(0, 1) + if id_byte_raw is None: + return None + + return self.validate_eeprom_sfp() + + 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 update_sfp_type(self): + """ + The sfp type would not change. + Don't need to update sfp type + """ + pass + + 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_state |= self.SFP_ERROR_BIT_BAD_EEPROM + + status = self.validate_temperature() + if status is not True: + err_state |= self.SFP_ERROR_BIT_HIGH_TEMP + + if err_stat is self.SFP_STATUS_BIT_INSERTED: + return self.SFP_STATUS_OK + else: + err_desc = str() + for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT: + if (err_stat & key) != 0: + if len(err_desc) > 0: + 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" + """ + if self.port_num < 49: + # RJ45 doesn't support this feature + return "Not implemented" + else: + api = self.get_xcvr_api() + if api is not None: + try: + return api.get_error_description() + except NotImplementedError: + return self.__get_error_description() + else: + return self.__get_error_description() diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/thermal.py new file mode 100644 index 000000000000..79d2813dd20b --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/thermal.py @@ -0,0 +1,540 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import os.path +import glob + +try: + from sonic_platform_base.thermal_base import ThermalBase + from .helper import APIHelper + from .helper import DeviceThreshold +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +THERMAL_COUNT_PER_PSU = 2 +THERMAL_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/hwmon/hwmon*/" +CPU_SYSFS_PATH = "/sys/devices/platform/coretemp.0/hwmon/hwmon*/" + +I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" +PSU_PMBUS_I2C_MAPPING = { + 0: { + "num": 8, + "addr": "58" + }, + 1: { + "num": 9, + "addr": "59" + } +} + +PSU_EEPROM_I2C_MAPPING = { + 0: { + "num": 8, + "addr": "50" + }, + 1: { + "num": 9, + "addr": "51" + } +} + +THERMAL_I2C_MAPPING = { + 0: { + "num": 3, + "addr": "4a" + }, + 1: { + "num": 3, + "addr": "4b" + }, + 2: { + "num": 3, + "addr": "4d" + }, + 3: { + "num": 3, + "addr": "4e" + }, + 4: { + "num": 3, + "addr": "4f" + } +} + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + THERMAL_NAME_LIST = [ + "MB_Temp(0x4a)", + "MB_Temp(0x4b)", + "MB_Temp(0x4d)", + "MB_Temp(0x4e)", + "MB_Temp(0x4f)", + "CPU Package Temp", + "CPU Core 0 Temp", + "CPU Core 1 Temp", + "CPU Core 2 Temp", + "CPU Core 3 Temp" + ] + + PSU_THERMAL_NAME_LIST = [ + "PSU-1 temp sensor 1", + "PSU-1 temp sensor 2", + "PSU-2 temp sensor 1", + "PSU-2 temp sensor 2" + ] + + def __init__(self, thermal_index=0, is_psu=False, psu_index=0): + self.index = thermal_index + self.is_psu = is_psu + self.psu_index = psu_index + self.is_cpu = False + self.min_temperature = None + self.max_temperature = None + self.pcb_id = self.__get_pcb_id() + + self.conf = DeviceThreshold(self.get_name()) + # Default thresholds + self.default_threshold = { + 0: { # PCB_ID 0: AS4625-54P + self.THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '67.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '72.0' }, + self.THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '67.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '72.0' }, + self.THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '73.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '78.0' }, + self.THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '80.0' }, + self.THERMAL_NAME_LIST[4] : { + self.conf.HIGH_THRESHOLD_FIELD : '69.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '74.0' }, + self.THERMAL_NAME_LIST[5] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[6] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[7] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[8] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[9] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.PSU_THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '70.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '90.0' }, + self.PSU_THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '70.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '101.0' }, + self.PSU_THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '70.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '90.0' }, + self.PSU_THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '70.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '101.0' } + }, + 1: { # PCB_ID 1: AS4625-54T-F2B + self.THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '70.0' }, + self.THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '70.0' }, + self.THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '62.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '67.0' }, + self.THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '70.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '75.0' }, + self.THERMAL_NAME_LIST[4] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '70.0' }, + self.THERMAL_NAME_LIST[5] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[6] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[7] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[8] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[9] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.PSU_THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '83.0' }, + self.PSU_THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '77.0' }, + self.PSU_THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '83.0' }, + self.PSU_THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '77.0' } + }, + 2: { # PCB_ID 2: AS4625-54T-B2F + self.THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '70.0' }, + self.THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '67.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '72.0' }, + self.THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '66.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '71.0' }, + self.THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '73.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '78.0' }, + self.THERMAL_NAME_LIST[4] : { + self.conf.HIGH_THRESHOLD_FIELD : '66.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '71.0' }, + self.THERMAL_NAME_LIST[5] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[6] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[7] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[8] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.THERMAL_NAME_LIST[9] : { + self.conf.HIGH_THRESHOLD_FIELD : '75.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '95.0' }, + self.PSU_THERMAL_NAME_LIST[0] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '83.0' }, + self.PSU_THERMAL_NAME_LIST[1] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '77.0' }, + self.PSU_THERMAL_NAME_LIST[2] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '83.0' }, + self.PSU_THERMAL_NAME_LIST[3] : { + self.conf.HIGH_THRESHOLD_FIELD : '65.0', + self.conf.HIGH_CRIT_THRESHOLD_FIELD : '77.0' } + }, + } + + if self.index in range(5,10): + self.is_cpu = True + + if self.is_psu: + self.i2c_num = PSU_PMBUS_I2C_MAPPING[self.psu_index]["num"] + self.i2c_addr = PSU_PMBUS_I2C_MAPPING[self.psu_index]["addr"] + self.pmbus_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.i2c_num = PSU_EEPROM_I2C_MAPPING[self.psu_index]["num"] + self.i2c_addr = PSU_EEPROM_I2C_MAPPING[self.psu_index]["addr"] + self.eeprom_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + elif self.is_cpu: + self.ss_index = 0 + coretemp_list = self.__get_coretemp_list() + if coretemp_list is not None and len(coretemp_list) >= 5: + self.ss_index = coretemp_list[self.index-5] + self.hwmon_path = CPU_SYSFS_PATH + else: + # Set sysfs path + self.i2c_num = THERMAL_I2C_MAPPING[self.index]["num"] + self.i2c_addr = THERMAL_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = THERMAL_I2C_PATH.format(self.i2c_num, self.i2c_addr) + + def __get_coretemp_list(self): + coretemp_path = "{}{}".format(CPU_SYSFS_PATH, "temp*_input") + coretemp_files = glob.glob(coretemp_path) + + for (idx, file) in enumerate(coretemp_files): + file = file[file.rfind("/")+1:] # Discard its directory, keep file name + file = file.strip("temp").strip("_input") # Discard temp_input, keep the index string + coretemp_files[idx] = int(file) + + coretemp_files.sort() + return coretemp_files + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data = fd.readline().rstrip() + if len(data) > 0: + return data + except IOError as e: + pass + + return None + + def __get_temp(self, path, temp_file): + file_path = os.path.join(path, temp_file) + raw_temp = self.__read_txt_file(file_path) + if raw_temp is not None: + return float(raw_temp) / 1000 + else: + return None + + def __set_threshold(self, path, file_name, temperature): + if self.is_psu: + return True + + file_path = os.path.join(path, file_name) + for filename in glob.glob(file_path): + try: + with open(filename, 'w') as fd: + fd.write(str(temperature)) + return True + except IOError as e: + print("IOError") + + def __get_pcb_id(self): + cpld_path = I2C_PATH.format('0', '64') + 'pcb_id' + pcb_id = self.__read_txt_file(cpld_path) + if pcb_id is not None: + return int(pcb_id) + + return None + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + if self.is_cpu: + ss_file = "temp{}_input".format(self.ss_index) + current = self.__get_temp(self.hwmon_path, ss_file) + elif self.is_psu: + if not self.get_presence(): + return None + + power_path = "{}{}".format(self.eeprom_path, 'psu_power_good') + val = self.__read_txt_file(power_path) + if val is not None: + if int(val, 10) != 1: + return None + + # The base index start from 2 since temp1_input is not used by the PSU + ss_file = "temp{}_input".format(self.index + 2) + current = self.__get_temp(self.pmbus_path, ss_file) + else: + current = self.__get_temp(self.hwmon_path, "temp1_input") + + if current is None: + return current + + 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 get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + value = self.conf.get_high_critical_threshold() + if value != self.conf.NOT_AVAILABLE: + return float(value) + + default_value = self.default_threshold[self.pcb_id][self.get_name()][self.conf.HIGH_CRIT_THRESHOLD_FIELD] + if default_value != self.conf.NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def set_high_critical_threshold(self, temperature): + """ + Sets the critical high threshold temperature of thermal + + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + + Returns: + A boolean, True if threshold is set successfully, False if not + """ + try: + value = float(temperature) + except: + return False + + try: + self.conf.set_high_critical_threshold(str(value)) + except: + return False + + return True + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + value = self.conf.get_high_threshold() + if value != self.conf.NOT_AVAILABLE: + return float(value) + + default_value = self.default_threshold[self.pcb_id][self.get_name()][self.conf.HIGH_THRESHOLD_FIELD] + if default_value != self.conf.NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + try: + value = float(temperature) + except: + return False + + try: + self.conf.set_high_threshold(str(value)) + except: + return False + + return True + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + if self.is_psu: + return self.PSU_THERMAL_NAME_LIST[self.index + self.psu_index * THERMAL_COUNT_PER_PSU] + else: + return self.THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + if self.is_cpu: + return True + elif self.is_psu: + path = "{}{}".format(self.eeprom_path, "psu_present") + val = self.__read_txt_file(path) + return int(val, 10) == 1 + else: + path = "{}{}".format(self.hwmon_path, "temp1_input") + val = self.__read_txt_file(path) + if val is not None: + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.is_cpu: + return True + elif self.is_psu: + if not self.get_presence(): + return None + + path = "{}{}".format(self.pmbus_path, "psu_temp_fault") + val = self.__read_txt_file(path) + if val is None: + return False + else: + return int(val, 10) == 0 + else: + if self.get_temperature() is None: + return False + else: + 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_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + 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/device/accton/x86_64-accton_as4625_54p-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4625_54p-r0/system_health_monitoring_config.json new file mode 100644 index 000000000000..7aa53bcf4d30 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54p-r0/system_health_monitoring_config.json @@ -0,0 +1,14 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN_BLINKING" + } +} diff --git a/device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/port_config.ini b/device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/port_config.ini new file mode 100644 index 000000000000..a88d9f0d2357 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed autoneg +Ethernet0 25 Eth1(Port1) 1 1000 on +Ethernet1 26 Eth2(Port2) 2 1000 on +Ethernet2 27 Eth3(Port3) 3 1000 on +Ethernet3 28 Eth4(Port4) 4 1000 on +Ethernet4 29 Eth5(Port5) 5 1000 on +Ethernet5 30 Eth6(Port6) 6 1000 on +Ethernet6 31 Eth7(Port7) 7 1000 on +Ethernet7 32 Eth8(Port8) 8 1000 on +Ethernet8 33 Eth9(Port9) 9 1000 on +Ethernet9 34 Eth10(Port10) 10 1000 on +Ethernet10 35 Eth11(Port11) 11 1000 on +Ethernet11 36 Eth12(Port12) 12 1000 on +Ethernet12 37 Eth13(Port13) 13 1000 on +Ethernet13 38 Eth14(Port14) 14 1000 on +Ethernet14 39 Eth15(Port15) 15 1000 on +Ethernet15 40 Eth16(Port16) 16 1000 on +Ethernet16 41 Eth17(Port17) 17 1000 on +Ethernet17 42 Eth18(Port18) 18 1000 on +Ethernet18 43 Eth19(Port19) 19 1000 on +Ethernet19 44 Eth20(Port20) 20 1000 on +Ethernet20 49 Eth21(Port21) 21 1000 on +Ethernet21 50 Eth22(Port22) 22 1000 on +Ethernet22 51 Eth23(Port23) 23 1000 on +Ethernet23 52 Eth24(Port24) 24 1000 on +Ethernet24 1 Eth25(Port25) 25 1000 on +Ethernet25 2 Eth26(Port26) 26 1000 on +Ethernet26 3 Eth27(Port27) 27 1000 on +Ethernet27 4 Eth28(Port28) 28 1000 on +Ethernet28 5 Eth29(Port29) 29 1000 on +Ethernet29 6 Eth30(Port30) 30 1000 on +Ethernet30 7 Eth31(Port31) 31 1000 on +Ethernet31 8 Eth32(Port32) 32 1000 on +Ethernet32 9 Eth33(Port33) 33 1000 on +Ethernet33 10 Eth34(Port34) 34 1000 on +Ethernet34 11 Eth35(Port35) 35 1000 on +Ethernet35 12 Eth36(Port36) 36 1000 on +Ethernet36 13 Eth37(Port37) 37 1000 on +Ethernet37 14 Eth38(Port38) 38 1000 on +Ethernet38 15 Eth39(Port39) 39 1000 on +Ethernet39 16 Eth40(Port40) 40 1000 on +Ethernet40 17 Eth41(Port41) 41 1000 on +Ethernet41 18 Eth42(Port42) 42 1000 on +Ethernet42 19 Eth43(Port43) 43 1000 on +Ethernet43 20 Eth44(Port44) 44 1000 on +Ethernet44 21 Eth45(Port45) 45 1000 on +Ethernet45 22 Eth46(Port46) 46 1000 on +Ethernet46 23 Eth47(Port47) 47 1000 on +Ethernet47 24 Eth48(Port48) 48 1000 on +Ethernet48 57 Eth49(Port49) 49 10000 off +Ethernet49 58 Eth50(Port50) 50 10000 off +Ethernet50 59 Eth51(Port51) 51 10000 off +Ethernet51 60 Eth52(Port52) 52 10000 off +Ethernet52 61 Eth53(Port53) 53 10000 off +Ethernet53 62 Eth54(Port54) 54 10000 off diff --git a/device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/sai.profile b/device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/sai.profile new file mode 100644 index 000000000000..8b137891791f --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/Accton-AS4625-54T/sai.profile @@ -0,0 +1 @@ + diff --git a/device/accton/x86_64-accton_as4625_54t-r0/default_sku b/device/accton/x86_64-accton_as4625_54t-r0/default_sku new file mode 100644 index 000000000000..2e1af1dd6f93 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/default_sku @@ -0,0 +1 @@ +Accton-AS4625-54T t1 diff --git a/device/accton/x86_64-accton_as4625_54t-r0/installer.conf b/device/accton/x86_64-accton_as4625_54t-r0/installer.conf new file mode 100644 index 000000000000..85bb317cc906 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" diff --git a/device/accton/x86_64-accton_as4625_54t-r0/pcie.yaml b/device/accton/x86_64-accton_as4625_54t-r0/pcie.yaml new file mode 100644 index 000000000000..b7482437b980 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/pcie.yaml @@ -0,0 +1,149 @@ +- bus: '00' + dev: '00' + fn: '0' + id: '1980' + name: 'Host bridge: Intel Corporation Atom Processor C3000 Series System Agent (rev + 11)' +- bus: '00' + dev: '04' + fn: '0' + id: 19a1 + name: 'Host bridge: Intel Corporation Atom Processor C3000 Series Error Registers + (rev 11)' +- bus: '00' + dev: '05' + fn: '0' + id: 19a2 + name: 'Generic system peripheral [0807]: Intel Corporation Atom Processor C3000 + Series Root Complex Event Collector (rev 11)' +- bus: '00' + dev: '06' + fn: '0' + id: 19a3 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated QAT + Root Port (rev 11)' +- bus: '00' + dev: 09 + fn: '0' + id: 19a4 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #0 (rev 11)' +- bus: '00' + dev: 0e + fn: '0' + id: 19a8 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #4 (rev 11)' +- bus: '00' + dev: 0f + fn: '0' + id: 19a9 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #5 (rev 11)' +- bus: '00' + dev: '12' + fn: '0' + id: 19ac + name: 'System peripheral: Intel Corporation Atom Processor C3000 Series SMBus Contoller + - Host (rev 11)' +- bus: '00' + dev: '14' + fn: '0' + id: 19c2 + name: 'SATA controller: Intel Corporation Atom Processor C3000 Series SATA Controller + 1 (rev 11)' +- bus: '00' + dev: '15' + fn: '0' + id: 19d0 + name: 'USB controller: Intel Corporation Atom Processor C3000 Series USB 3.0 xHCI + Controller (rev 11)' +- bus: '00' + dev: '16' + fn: '0' + id: 19d1 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated LAN + Root Port #0 (rev 11)' +- bus: '00' + dev: '17' + fn: '0' + id: 19d2 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series Integrated LAN + Root Port #1 (rev 11)' +- bus: '00' + dev: '18' + fn: '0' + id: 19d3 + name: 'Communication controller: Intel Corporation Atom Processor C3000 Series ME + HECI 1 (rev 11)' +- bus: '00' + dev: 1f + fn: '0' + id: 19dc + name: 'ISA bridge: Intel Corporation Atom Processor C3000 Series LPC or eSPI (rev + 11)' +- bus: '00' + dev: 1f + fn: '1' + id: 19dd + name: 'Memory controller: Intel Corporation Atom Processor C3000 Series Primary + to Side Band (P2SB) Bridge (rev 11)' +- bus: '00' + dev: 1f + fn: '2' + id: 19de + name: 'Memory controller: Intel Corporation Atom Processor C3000 Series Power Management + Controller (rev 11)' +- bus: '00' + dev: 1f + fn: '4' + id: 19df + name: 'SMBus: Intel Corporation Atom Processor C3000 Series SMBus controller (rev + 11)' +- bus: '00' + dev: 1f + fn: '5' + id: 19e0 + name: 'Serial bus controller [0c80]: Intel Corporation Atom Processor C3000 Series + SPI Controller (rev 11)' +- bus: '01' + dev: '00' + fn: '0' + id: 19e2 + name: 'Co-processor: Intel Corporation Atom Processor C3000 Series QuickAssist Technology + (rev 11)' +- bus: '02' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '03' + dev: '00' + fn: '0' + id: b277 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries Device b277 (rev 02)' +- bus: '05' + dev: '00' + fn: '0' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '05' + dev: '00' + fn: '1' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '07' + dev: '00' + fn: '0' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '07' + dev: '00' + fn: '1' + id: 15c3 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' diff --git a/device/accton/x86_64-accton_as4625_54t-r0/platform.json b/device/accton/x86_64-accton_as4625_54t-r0/platform.json new file mode 100644 index 000000000000..72a1b27bfae3 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/platform.json @@ -0,0 +1,860 @@ +{ + "chassis": { + "name": "AS4625-54T", + "thermal_manager": false, + "status_led": { + "controllable": true, + "colors": [ "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_GREEN_BLINKING" ] + }, + "components": [ + { + "name": "MB_CPLD" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + }, + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + }, + { + "name": "FAN-3", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray-1", + "num_fans" : 1, + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray-2", + "num_fans" : 1, + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ] + }, + { + "name": "FanTray-3", + "num_fans" : 1, + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "FAN-3", + "speed": { + "controllable": true, + "minimum": 25 + }, + "status_led": { + "available": false + } + } + ] + } + ], + "psus": [ + { + "name": "PSU-1", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-1 FAN-1", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false + } + } + ], + "thermals": [ + { + "name": "PSU-1 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "PSU-1 temp sensor 2", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "temperature": true, + "temperature_high_threshold": true + }, + { + "name": "PSU-2", + "status_led": { + "controllable": false + }, + "fans": [ + { + "name": "PSU-2 FAN-1", + "speed": { + "controllable": false + }, + "status_led": { + "controllable": false + } + } + ], + "thermals": [ + { + "name": "PSU-2 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "PSU-2 temp sensor 2", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "temperature": true, + "temperature_high_threshold": true + } + ], + "thermals": [ + { + "name": "MB_Temp(0x4a)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + + }, + { + "name": "MB_Temp(0x4b)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_Temp(0x4d)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_Temp(0x4e)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "MB_Temp(0x4f)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name" : "CPU Package Temp", + "controllable": false, + "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": false + }, + { + "name" : "CPU Core 1 Temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name" : "CPU Core 2 Temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name" : "CPU Core 3 Temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ], + "sfps": [ + { + "name": "Ethernet0" + }, + { + "name": "Ethernet1" + }, + { + "name": "Ethernet2" + }, + { + "name": "Ethernet3" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet5" + }, + { + "name": "Ethernet6" + }, + { + "name": "Ethernet7" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet9" + }, + { + "name": "Ethernet10" + }, + { + "name": "Ethernet11" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet13" + }, + { + "name": "Ethernet14" + }, + { + "name": "Ethernet15" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet17" + }, + { + "name": "Ethernet18" + }, + { + "name": "Ethernet19" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet21" + }, + { + "name": "Ethernet22" + }, + { + "name": "Ethernet23" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet25" + }, + { + "name": "Ethernet26" + }, + { + "name": "Ethernet27" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet29" + }, + { + "name": "Ethernet30" + }, + { + "name": "Ethernet31" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet33" + }, + { + "name": "Ethernet34" + }, + { + "name": "Ethernet35" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet37" + }, + { + "name": "Ethernet38" + }, + { + "name": "Ethernet39" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet41" + }, + { + "name": "Ethernet42" + }, + { + "name": "Ethernet43" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet45" + }, + { + "name": "Ethernet46" + }, + { + "name": "Ethernet47" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet49" + }, + { + "name": "Ethernet50" + }, + { + "name": "Ethernet51" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet53" + } + ] + }, + "interfaces": { + "Ethernet0": { + "index": "1", + "lanes": "25", + "breakout_modes": { + "1x1G": ["Eth1(Port1)"] + } + }, + + "Ethernet1": { + "index": "2", + "lanes": "26", + "breakout_modes": { + "1x1G": ["Eth2(Port2)"] + } + }, + + "Ethernet2": { + "index": "3", + "lanes": "27", + "breakout_modes": { + "1x1G": ["Eth3(Port3)"] + } + }, + + "Ethernet3": { + "index": "4", + "lanes": "28", + "breakout_modes": { + "1x1G": ["Eth4(Port4)"] + } + }, + + "Ethernet4": { + "index": "5", + "lanes": "29", + "breakout_modes": { + "1x1G": ["Eth5(Port5)"] + } + }, + + "Ethernet5": { + "index": "6", + "lanes": "30", + "breakout_modes": { + "1x1G": ["Eth6(Port6)"] + } + }, + + "Ethernet6": { + "index": "7", + "lanes": "31", + "breakout_modes": { + "1x1G": ["Eth7(Port7)"] + } + }, + + "Ethernet7": { + "index": "8", + "lanes": "32", + "breakout_modes": { + "1x1G": ["Eth8(Port8)"] + } + }, + + "Ethernet8": { + "index": "9", + "lanes": "33", + "breakout_modes": { + "1x1G": ["Eth9(Port9)"] + } + }, + + "Ethernet9": { + "index": "10", + "lanes": "34", + "breakout_modes": { + "1x1G": ["Eth10(Port10)"] + } + }, + + "Ethernet10": { + "index": "11", + "lanes": "35", + "breakout_modes": { + "1x1G": ["Eth11(Port11)"] + } + }, + + "Ethernet11": { + "index": "12", + "lanes": "36", + "breakout_modes": { + "1x1G": ["Eth12(Port12)"] + } + }, + + "Ethernet12": { + "index": "13", + "lanes": "37", + "breakout_modes": { + "1x1G": ["Eth13(Port13)"] + } + }, + + "Ethernet13": { + "index": "14", + "lanes": "38", + "breakout_modes": { + "1x1G": ["Eth14(Port14)"] + } + }, + + "Ethernet14": { + "index": "15", + "lanes": "39", + "breakout_modes": { + "1x1G": ["Eth15(Port15)"] + } + }, + + "Ethernet15": { + "index": "16", + "lanes": "40", + "breakout_modes": { + "1x1G": ["Eth16(Port16)"] + } + }, + + "Ethernet16": { + "index": "17", + "lanes": "41", + "breakout_modes": { + "1x1G": ["Eth17(Port17)"] + } + }, + + "Ethernet17": { + "index": "18", + "lanes": "42", + "breakout_modes": { + "1x1G": ["Eth18(Port18)"] + } + }, + + "Ethernet18": { + "index": "19", + "lanes": "43", + "breakout_modes": { + "1x1G": ["Eth19(Port19)"] + } + }, + + "Ethernet19": { + "index": "20", + "lanes": "44", + "breakout_modes": { + "1x1G": ["Eth20(Port20)"] + } + }, + + "Ethernet20": { + "index": "21", + "lanes": "49", + "breakout_modes": { + "1x1G": ["Eth21(Port21)"] + } + }, + + "Ethernet21": { + "index": "22", + "lanes": "50", + "breakout_modes": { + "1x1G": ["Eth22(Port22)"] + } + }, + + "Ethernet22": { + "index": "23", + "lanes": "51", + "breakout_modes": { + "1x1G": ["Eth23(Port23)"] + } + }, + + "Ethernet23": { + "index": "24", + "lanes": "52", + "breakout_modes": { + "1x1G": ["Eth24(Port24)"] + } + }, + + "Ethernet24": { + "index": "25", + "lanes": "1", + "breakout_modes": { + "1x1G": ["Eth25(Port25)"] + } + }, + + "Ethernet25": { + "index": "26", + "lanes": "2", + "breakout_modes": { + "1x1G": ["Eth26(Port26)"] + } + }, + + "Ethernet26": { + "index": "27", + "lanes": "3", + "breakout_modes": { + "1x1G": ["Eth27(Port27)"] + } + }, + + "Ethernet27": { + "index": "28", + "lanes": "4", + "breakout_modes": { + "1x1G": ["Eth28(Port28)"] + } + }, + + "Ethernet28": { + "index": "29", + "lanes": "5", + "breakout_modes": { + "1x1G": ["Eth29(Port29)"] + } + }, + + "Ethernet29": { + "index": "30", + "lanes": "6", + "breakout_modes": { + "1x1G": ["Eth30(Port30)"] + } + }, + + "Ethernet30": { + "index": "31", + "lanes": "7", + "breakout_modes": { + "1x1G": ["Eth31(Port31)"] + } + }, + + "Ethernet31": { + "index": "32", + "lanes": "8", + "breakout_modes": { + "1x1G": ["Eth32(Port32)"] + } + }, + + "Ethernet32": { + "index": "33", + "lanes": "9", + "breakout_modes": { + "1x1G": ["Eth33(Port33)"] + } + }, + + "Ethernet33": { + "index": "34", + "lanes": "10", + "breakout_modes": { + "1x1G": ["Eth34(Port34)"] + } + }, + + "Ethernet34": { + "index": "35", + "lanes": "11", + "breakout_modes": { + "1x1G": ["Eth35(Port35)"] + } + }, + + "Ethernet35": { + "index": "36", + "lanes": "12", + "breakout_modes": { + "1x1G": ["Eth36(Port36)"] + } + }, + + "Ethernet36": { + "index": "37", + "lanes": "13", + "breakout_modes": { + "1x1G": ["Eth37(Port37)"] + } + }, + + "Ethernet37": { + "index": "38", + "lanes": "14", + "breakout_modes": { + "1x1G": ["Eth38(Port38)"] + } + }, + + "Ethernet38": { + "index": "39", + "lanes": "15", + "breakout_modes": { + "1x1G": ["Eth39(Port39)"] + } + }, + + "Ethernet39": { + "index": "40", + "lanes": "16", + "breakout_modes": { + "1x1G": ["Eth40(Port40)"] + } + }, + + "Ethernet40": { + "index": "41", + "lanes": "17", + "breakout_modes": { + "1x1G": ["Eth41(Port41)"] + } + }, + + "Ethernet41": { + "index": "42", + "lanes": "18", + "breakout_modes": { + "1x1G": ["Eth42(Port42)"] + } + }, + + "Ethernet42": { + "index": "43", + "lanes": "19", + "breakout_modes": { + "1x1G": ["Eth43(Port43)"] + } + }, + + "Ethernet43": { + "index": "44", + "lanes": "20", + "breakout_modes": { + "1x1G": ["Eth44(Port44)"] + } + }, + + "Ethernet44": { + "index": "45", + "lanes": "21", + "breakout_modes": { + "1x1G": ["Eth45(Port45)"] + } + }, + + "Ethernet45": { + "index": "46", + "lanes": "22", + "breakout_modes": { + "1x1G": ["Eth46(Port46)"] + } + }, + + "Ethernet46": { + "index": "47", + "lanes": "23", + "breakout_modes": { + "1x1G": ["Eth47(Port47)"] + } + }, + + "Ethernet47": { + "index": "48", + "lanes": "24", + "breakout_modes": { + "1x1G": ["Eth48(Port48)"] + } + }, + + "Ethernet48": { + "index": "49", + "lanes": "57", + "breakout_modes": { + "1x10G[1G]": ["Eth49(Port49)"] + } + }, + + "Ethernet49": { + "index": "50", + "lanes": "58", + "breakout_modes": { + "1x10G[1G]": ["Eth50(Port50)"] + } + }, + + "Ethernet50": { + "index": "51", + "lanes": "59", + "breakout_modes": { + "1x10G[1G]": ["Eth51(Port51)"] + } + }, + + "Ethernet51": { + "index": "52", + "lanes": "60", + "breakout_modes": { + "1x10G[1G]": ["Eth52(Port52)"] + } + }, + + "Ethernet52": { + "index": "53", + "lanes": "61", + "breakout_modes": { + "1x10G[1G]": ["Eth53(Port53)"] + } + }, + + "Ethernet53": { + "index": "54", + "lanes": "62", + "breakout_modes": { + "1x10G[1G]": ["Eth54(Port54)"] + } + } + } +} diff --git a/device/accton/x86_64-accton_as4625_54t-r0/platform_asic b/device/accton/x86_64-accton_as4625_54t-r0/platform_asic new file mode 100644 index 000000000000..960467652765 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/platform_asic @@ -0,0 +1 @@ +broadcom diff --git a/device/accton/x86_64-accton_as4625_54t-r0/platform_components.json b/device/accton/x86_64-accton_as4625_54t-r0/platform_components.json new file mode 100644 index 000000000000..59e502d03962 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/platform_components.json @@ -0,0 +1,10 @@ +{ + "chassis": { + "4625-54T-O-AC-F": { + "component": { + "MB_CPLD": { }, + "BIOS": { } + } + } + } +} diff --git a/device/accton/x86_64-accton_as4625_54t-r0/plugins/ssd_util.py b/device/accton/x86_64-accton_as4625_54t-r0/plugins/ssd_util.py new file mode 100644 index 000000000000..4b173c5e3890 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/plugins/ssd_util.py @@ -0,0 +1,24 @@ +# ssd_util.py +# +# Platform-specific SSD interface for SONiC +## + +try: + from sonic_platform_base.sonic_ssd.ssd_generic import SsdUtil as MainSsdUtil +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +NOT_AVAILABLE = "N/A" + +class SsdUtil(MainSsdUtil): + """Platform-specific SsdUtil class""" + + def __init__(self, diskdev): + super(SsdUtil, self).__init__(diskdev) + + # If it has no vendor tool to read SSD information, + # ssd_util.py will use generic SSD information + # for vendor SSD information. + if self.vendor_ssd_info == NOT_AVAILABLE: + self.vendor_ssd_info = self.ssd_info + diff --git a/device/accton/x86_64-accton_as4625_54t-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4625_54t-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..79344cad0bd9 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true, + "skip_xcvrd_cmis_mgr": true +} diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sensors.conf b/device/accton/x86_64-accton_as4625_54t-r0/sensors.conf new file mode 100644 index 000000000000..1f4571ec603b --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sensors.conf @@ -0,0 +1,50 @@ +# libsensors configuration file for as4625 +# ------------------------------------------------ +# +bus "i2c-3" "i2c-1-mux (chan_id 1)" +bus "i2c-8" "i2c-1-mux (chan_id 6)" +bus "i2c-9" "i2c-1-mux (chan_id 7)" + +chip "ym2651-i2c-*-58" + label in3 "PSU 1 Voltage" + label fan1 "PSU 1 Fan" + label temp1 "PSU 1 Temperature" + label power2 "PSU 1 Power" + label curr2 "PSU 1 Current" + +chip "ym2651-i2c-*-59" + label in3 "PSU 2 Voltage" + label fan1 "PSU 2 Fan" + label temp1 "PSU 2 Temperature" + label power2 "PSU 2 Power" + label curr2 "PSU 2 Current" + +chip "as4625_fan-*" + label fan1 "Fan 1" + label fan2 "Fan 2" + label fan3 "Fan 3" + +chip "lm75-i2c-*-4a" + label temp1 "MB_Temp(0x4a)" + +chip "lm75-i2c-*-4b" + label temp1 "MB_Temp(0x4b)" + +chip "lm75-i2c-*-4d" + label temp1 "MB_Temp(0x4d)" + +chip "lm75-i2c-*-4e" + label temp1 "MB_Temp(0x4e)" + +chip "lm75-i2c-*-4f" + label temp1 "MB_Temp(0x4f)" + +chip "coretemp-isa-0000" + label temp2 "Core 0" + label temp4 "Core 0" + label temp6 "Core 1" + label temp8 "Core 1" + label temp10 "Core 2" + label temp12 "Core 2" + label temp14 "Core 3" + label temp16 "Core 3" diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/__init__.py new file mode 120000 index 000000000000..c7aee89566a4 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/__init__.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/__init__.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/chassis.py new file mode 120000 index 000000000000..4d6ee0c9d9f0 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/chassis.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/chassis.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/component.py new file mode 120000 index 000000000000..54bba41bdbfb --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/component.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/component.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/eeprom.py new file mode 120000 index 000000000000..43446f8898a5 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/eeprom.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/eeprom.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/event.py new file mode 120000 index 000000000000..cdd9015c49e7 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/event.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/event.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan.py new file mode 120000 index 000000000000..3fb15ca467fc --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/fan.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan_drawer.py new file mode 120000 index 000000000000..51f29dbb537b --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/fan_drawer.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/fan_drawer.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/helper.py new file mode 120000 index 000000000000..cbc0d3e4ab3b --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/helper.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/helper.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/pcie.py new file mode 120000 index 000000000000..908a466e681a --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/pcie.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/pcie.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/platform.py new file mode 120000 index 000000000000..8f613376ffca --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/platform.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/platform.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/psu.py new file mode 120000 index 000000000000..4c5a8cb13edc --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/psu.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/psu.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/sfp.py new file mode 120000 index 000000000000..8886af08e0b0 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/sfp.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/sfp.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/thermal.py new file mode 120000 index 000000000000..b26d132186ea --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/sonic_platform/thermal.py @@ -0,0 +1 @@ +../../x86_64-accton_as4625_54p-r0/sonic_platform/thermal.py \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4625_54t-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4625_54t-r0/system_health_monitoring_config.json new file mode 100644 index 000000000000..7aa53bcf4d30 --- /dev/null +++ b/device/accton/x86_64-accton_as4625_54t-r0/system_health_monitoring_config.json @@ -0,0 +1,14 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": [ + "asic", + "psu.temperature" + ], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN_BLINKING" + } +} diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 6c668ee6894d..b9f5922d0ff7 100755 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -45,6 +45,8 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ACCTON_AS5835_54T_PLATFORM_MODULE) \ $(ACCTON_AS7312_54XS_PLATFORM_MODULE) \ $(ACCTON_AS7315_27XB_PLATFORM_MODULE) \ + $(ACCTON_AS4625_54P_PLATFORM_MODULE) \ + $(ACCTON_AS4625_54T_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-accton.mk b/platform/broadcom/platform-modules-accton.mk index 85e7ff1f5641..f812fa92d5f1 100755 --- a/platform/broadcom/platform-modules-accton.mk +++ b/platform/broadcom/platform-modules-accton.mk @@ -20,6 +20,8 @@ ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS4625_54P_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS4625_54T_PLATFORM_MODULE_VERSION = 1.1 export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION @@ -41,6 +43,8 @@ export ACCTON_AS9726_32D_PLATFORM_MODULE_VERSION export ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION export ACCTON_AS7312_54XS_PLATFORM_MODULE_VERSION export ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION +export ACCTON_AS4625_54P_PLATFORM_MODULE_VERSION +export ACCTON_AS4625_54T_PLATFORM_MODULE_VERSION ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton @@ -123,3 +127,11 @@ $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS ACCTON_AS7315_27XB_PLATFORM_MODULE = sonic-platform-accton-as7315-27xb_$(ACCTON_AS7315_27XB_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7315_27XB_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as7315_27xb-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS7315_27XB_PLATFORM_MODULE))) + +ACCTON_AS4625_54P_PLATFORM_MODULE = sonic-platform-accton-as4625-54p_$(ACCTON_AS4625_54P_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS4625_54P_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4625_54p-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4625_54P_PLATFORM_MODULE))) + +ACCTON_AS4625_54T_PLATFORM_MODULE = sonic-platform-accton-as4625-54t_$(ACCTON_AS4625_54T_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS4625_54T_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as4625_54t-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS4625_54T_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/classes/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/Makefile new file mode 100644 index 000000000000..d8965ece86be --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/Makefile @@ -0,0 +1,16 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= x86-64-accton-as4625-54p-cpld.o x86-64-accton-as4625-54p-fan.o \ + x86-64-accton-as4625-54p-psu.o x86-64-accton-as4625-54p-leds.o ym2651y.o + +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c new file mode 100644 index 000000000000..5c5ff42b2d92 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c @@ -0,0 +1,571 @@ +/* + * Copyright (C) Brandon Chuang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as4625 CPLD1/CPLD2/CPLD3 + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as4625_cpld1 +}; + +struct as4625_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; +}; + +static const struct i2c_device_id as4625_cpld_id[] = { + { "as4625_cpld1", as4625_cpld1 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as4625_cpld_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_TXDISABLE_ATTR_ID(index) MODULE_TXDISABLE_##index +#define TRANSCEIVER_RXLOS_ATTR_ID(index) MODULE_RXLOS_##index +#define TRANSCEIVER_TXFAULT_ATTR_ID(index) MODULE_TXFAULT_##index + +enum as4625_cpld_sysfs_attributes { + VERSION_MAJOR, + VERSION_MINOR, + PCB_ID, + PCB_VERSION, + POWER_ENABLE_MAINBOARD, + POWER_ENABLE_POE, + ACCESS, + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_TXDISABLE_ATTR_ID(49), + TRANSCEIVER_TXDISABLE_ATTR_ID(50), + TRANSCEIVER_TXDISABLE_ATTR_ID(51), + TRANSCEIVER_TXDISABLE_ATTR_ID(52), + TRANSCEIVER_TXDISABLE_ATTR_ID(53), + TRANSCEIVER_TXDISABLE_ATTR_ID(54), + TRANSCEIVER_RXLOS_ATTR_ID(49), + TRANSCEIVER_RXLOS_ATTR_ID(50), + TRANSCEIVER_RXLOS_ATTR_ID(51), + TRANSCEIVER_RXLOS_ATTR_ID(52), + TRANSCEIVER_RXLOS_ATTR_ID(53), + TRANSCEIVER_RXLOS_ATTR_ID(54), + TRANSCEIVER_TXFAULT_ATTR_ID(49), + TRANSCEIVER_TXFAULT_ATTR_ID(50), + TRANSCEIVER_TXFAULT_ATTR_ID(51), + TRANSCEIVER_TXFAULT_ATTR_ID(52), + TRANSCEIVER_TXFAULT_ATTR_ID(53), + TRANSCEIVER_TXFAULT_ATTR_ID(54) +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as4625_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as4625_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/* transceiver attributes */ +#define DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_disable_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_TXDISABLE_##index); \ + static SENSOR_DEVICE_ATTR(module_rx_los_##index, S_IRUGO, show_status, NULL, MODULE_RXLOS_##index); \ + static SENSOR_DEVICE_ATTR(module_tx_fault_##index, S_IRUGO, show_status, NULL, MODULE_TXFAULT_##index) +#define DECLARE_SFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_present_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_disable_##index.dev_attr.attr, \ + &sensor_dev_attr_module_rx_los_##index.dev_attr.attr, \ + &sensor_dev_attr_module_tx_fault_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version_major, S_IRUGO, show_version, NULL, VERSION_MAJOR); +static SENSOR_DEVICE_ATTR(version_minor, S_IRUGO, show_version, NULL, VERSION_MINOR); +static SENSOR_DEVICE_ATTR(pcb_id, S_IRUGO, show_version, NULL, PCB_ID); +static SENSOR_DEVICE_ATTR(pcb_version, S_IRUGO, show_version, NULL, PCB_VERSION); +static SENSOR_DEVICE_ATTR(pwr_enable_mb, S_IRUGO | S_IWUSR, show_status, set_control, POWER_ENABLE_MAINBOARD); +static SENSOR_DEVICE_ATTR(pwr_enable_poe, S_IRUGO | S_IWUSR, show_status, set_control, POWER_ENABLE_POE); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); + +/* transceiver attributes */ +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_SFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); + +static struct attribute *as4625_cpld1_attributes[] = { + &sensor_dev_attr_version_major.dev_attr.attr, + &sensor_dev_attr_version_minor.dev_attr.attr, + &sensor_dev_attr_pcb_id.dev_attr.attr, + &sensor_dev_attr_pcb_version.dev_attr.attr, + &sensor_dev_attr_pwr_enable_mb.dev_attr.attr, + &sensor_dev_attr_pwr_enable_poe.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + DECLARE_SFP_TRANSCEIVER_ATTR(49), + DECLARE_SFP_TRANSCEIVER_ATTR(50), + DECLARE_SFP_TRANSCEIVER_ATTR(51), + DECLARE_SFP_TRANSCEIVER_ATTR(52), + DECLARE_SFP_TRANSCEIVER_ATTR(53), + DECLARE_SFP_TRANSCEIVER_ATTR(54), + NULL +}; + +static const struct attribute_group as4625_cpld1_group = { + .attrs = as4625_cpld1_attributes, +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as4625_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, reverse = 0; + + switch (attr->index) { + case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_54: + reg = 0x5; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_49); + break; + case MODULE_PRESENT_49 ... MODULE_PRESENT_54: + reg = 0x6; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + reverse = 1; + break; + case MODULE_RXLOS_49 ... MODULE_RXLOS_54: + reg = 0x7; + mask = 0x1 << (attr->index - MODULE_RXLOS_49); + break; + case MODULE_TXFAULT_49 ... MODULE_TXFAULT_54: + reg = 0x8; + mask = 0x1 << (attr->index - MODULE_TXFAULT_49); + break; + case POWER_ENABLE_MAINBOARD: + reg = 0x3; + mask = 0x1; + reverse = 1; + break; + case POWER_ENABLE_POE: + reg = 0x21; + mask = 0x1; + break; + default: + return 0; + } + + mutex_lock(&data->update_lock); + status = as4625_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", reverse ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as4625_cpld_data *data = i2c_get_clientdata(client); + long value; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &value); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_TXDISABLE_49 ... MODULE_TXDISABLE_54: + reg = 0x5; + mask = 0x1 << (attr->index - MODULE_TXDISABLE_49); + break; + case POWER_ENABLE_MAINBOARD: + reg = 0x3; + mask = 0x1; + value = !value; + break; + case POWER_ENABLE_POE: + reg = 0x21; + mask = 0x1; + break; + default: + return -EINVAL; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as4625_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update tx_disable status */ + if (value) + status |= mask; + else + status &= ~mask; + + status = as4625_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as4625_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as4625_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as4625_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as4625_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + int val = 0, reg = 0; + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + switch (attr->index) { + case PCB_ID: + case PCB_VERSION: + reg = 0x0; + break; + case VERSION_MAJOR: + reg = 0x1; + break; + case VERSION_MINOR: + reg = 0x2; + break; + default: + break; + } + + val = i2c_smbus_read_byte_data(client, reg); + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", + client->addr, val); + return val; + } + + if (attr->index == PCB_ID) + val = (val >> 3) & 0x7; /* bit 3-5 */ + else if (attr->index == PCB_VERSION) + val &= 0x7; /* bit 0-2 */ + + return sprintf(buf, "%d\n", val); +} + +/* + * I2C init/probing/exit functions + */ +static int as4625_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as4625_cpld_data *data; + int ret = -ENODEV; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as4625_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) { + case as4625_cpld1: + group = &as4625_cpld1_group; + break; + default: + break; + } + + if (group) { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as4625_cpld_add_client(client); + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as4625_cpld_remove(struct i2c_client *client) +{ + struct as4625_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as4625_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) { + case as4625_cpld1: + group = &as4625_cpld1_group; + break; + default: + break; + } + + if (group) { + sysfs_remove_group(&client->dev.kobj, group); + } + + kfree(data); + return 0; +} + +static int as4625_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as4625_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as4625_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as4625_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as4625_cpld_read); + +int as4625_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as4625_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as4625_cpld_write); + +static struct i2c_driver as4625_cpld_driver = { + .driver = { + .name = "as4625_cpld", + .owner = THIS_MODULE, + }, + .probe = as4625_cpld_probe, + .remove = as4625_cpld_remove, + .id_table = as4625_cpld_id, +}; + +static int __init as4625_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as4625_cpld_driver); +} + +static void __exit as4625_cpld_exit(void) +{ + i2c_del_driver(&as4625_cpld_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton I2C CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as4625_cpld_init); +module_exit(as4625_cpld_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c new file mode 100644 index 000000000000..7bc0d5b8388f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c @@ -0,0 +1,416 @@ +/* + * A hwmon driver for the Accton as4625 fan + * + * Copyright (C) 2016 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as4625_fan" + +#define FAN_STATUS_I2C_ADDR 0x64 + +static struct as4625_fan_data *as4625_fan_update_device(struct device *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +extern int as4625_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as4625_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x40, /* fan-1 PWM */ + 0x41, /* fan-2 PWM */ + 0x42, /* fan-3 PWM */ + 0x46, /* fan-1 speed(rpm) */ + 0x47, /* fan-2 speed(rpm) */ + 0x48, /* fan-3 speed(rpm) */ + 0x00 /* fan direction, 001: AS4625-54T (F2B), 010: AS4625-54T (B2F) */ +}; + +static const int fan_target_speed_f2b[] = { + 0, 1350, 2550, 3900, 6450, 7800, 9150, 10500, + 11850, 13050, 14400, 15600, 16950, 18150, 19650, 23000 +}; + +static const int fan_target_speed_b2f[] = { + 0, 3150, 5850, 8100, 12150, 13650, 15000, 16350, + 17850, 19050, 19950, 20700, 21450, 22200, 22800, 23400 +}; + +/* fan data */ +struct as4625_fan_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ +}; + +struct as4625_fan_data *data = NULL; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID +}; + +enum sysfs_fan_attributes { + FAN1_PWM, + FAN2_PWM, + FAN3_PWM, + FAN1_INPUT, + FAN2_INPUT, + FAN3_INPUT, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN1_DIR, + FAN2_DIR, + FAN3_DIR, + FAN1_TARGET_RPM, + FAN2_TARGET_RPM, + FAN3_TARGET_RPM +}; + +/* Define attributes + */ +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index) &sensor_dev_attr_fan##index##_fault.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_pwm, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_PWM) +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_pwm.dev_attr.attr + +#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_INPUT) +#define DECLARE_FAN_SPEED_RPM_ATTR(index) &sensor_dev_attr_fan##index##_input.dev_attr.attr + +#define DECLARE_FAN_DIR_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_dir, S_IRUGO, fan_show_value, NULL, FAN##index##_DIR) +#define DECLARE_FAN_DIR_ATTR(index) &sensor_dev_attr_fan##index##_dir.dev_attr.attr + +#define DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_target_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_TARGET_RPM) +#define DECLARE_FAN_TARGET_RPM_ATTR(index) &sensor_dev_attr_fan##index##_target_rpm.dev_attr.attr + +/* 3 fan fault attributes in this platform */ +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3); + +/* 3 fan speed(rpm) attributes in this platform */ +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3); + +/* 3 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(3); + +/* 3 fan direction attribute in this platform */ +DECLARE_FAN_DIR_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIR_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIR_SENSOR_DEV_ATTR(3); + +/* 3 fan target speed attribute in this platform */ +DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(1); +DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(2); +DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(3); + +static struct attribute *as4625_fan_attributes[] = { + /* fan related attributes */ + DECLARE_FAN_FAULT_ATTR(1), + DECLARE_FAN_FAULT_ATTR(2), + DECLARE_FAN_FAULT_ATTR(3), + DECLARE_FAN_DUTY_CYCLE_ATTR(1), + DECLARE_FAN_DUTY_CYCLE_ATTR(2), + DECLARE_FAN_DUTY_CYCLE_ATTR(3), + DECLARE_FAN_SPEED_RPM_ATTR(1), + DECLARE_FAN_SPEED_RPM_ATTR(2), + DECLARE_FAN_SPEED_RPM_ATTR(3), + DECLARE_FAN_DIR_ATTR(1), + DECLARE_FAN_DIR_ATTR(2), + DECLARE_FAN_DIR_ATTR(3), + DECLARE_FAN_TARGET_RPM_ATTR(1), + DECLARE_FAN_TARGET_RPM_ATTR(2), + DECLARE_FAN_TARGET_RPM_ATTR(3), + NULL +}; + +#define FAN_DUTY_CYCLE_REG_MASK 0x0F +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 150 + +static int as4625_fan_read_value(u8 reg) +{ + return as4625_cpld_read(FAN_STATUS_I2C_ADDR, reg); +} + +static int as4625_fan_write_value(u8 reg, u8 value) +{ + return as4625_cpld_write(FAN_STATUS_I2C_ADDR, reg, value); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + reg_val &= FAN_DUTY_CYCLE_REG_MASK; + return (u32)(reg_val+1) * 625 / 100; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + if (duty_cycle == 0) { + return 0; + } + else if (duty_cycle > FAN_MAX_DUTY_CYCLE) { + duty_cycle = FAN_MAX_DUTY_CYCLE; + } + + return ((u32)duty_cycle * 100 / 625) - 1; +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 is_fan_fault(struct as4625_fan_data *data, enum fan_id id) +{ + return !reg_val_to_speed_rpm(data->reg_val[FAN1_INPUT + id]); +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value, reg; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < 0 || value > FAN_MAX_DUTY_CYCLE) + return -EINVAL; + + mutex_lock(&data->update_lock); + + reg = fan_reg[attr->index - FAN1_PWM]; + as4625_fan_write_value(reg, duty_cycle_to_reg_val(value)); + data->valid = 0; + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + ssize_t ret = 0; + + mutex_lock(&data->update_lock); + + data = as4625_fan_update_device(dev); + if (data->valid) { + switch (attr->index) { + case FAN1_PWM: + case FAN2_PWM: + case FAN3_PWM: + { + u32 duty_cycle; + duty_cycle = reg_val_to_duty_cycle(data->reg_val[attr->index]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + } + case FAN1_INPUT: + case FAN2_INPUT: + case FAN3_INPUT: + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); + break; + case FAN1_DIR: + case FAN2_DIR: + case FAN3_DIR: + { + u8 board_id = (data->reg_val[6] >> 3) & 0x7; + ret = sprintf(buf, "%s\n", (board_id == 2) ? "B2F" : "F2B"); + break; + } + case FAN1_TARGET_RPM: + case FAN2_TARGET_RPM: + case FAN3_TARGET_RPM: + { + u8 board_id = (data->reg_val[6] >> 3) & 0x7; + const int *target = NULL; + int pwm_index = FAN1_PWM + (attr->index - FAN1_TARGET_RPM); + target = (board_id == 2) ? fan_target_speed_b2f : fan_target_speed_f2b; + ret = sprintf(buf, "%d\n", target[data->reg_val[pwm_index] & 0xF]); + break; + } + default: + break; + } + } + + mutex_unlock(&data->update_lock); + + return ret; +} + +static const struct attribute_group as4625_fan_group = { + .attrs = as4625_fan_attributes, +}; + +static struct as4625_fan_data *as4625_fan_update_device(struct device *dev) +{ + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&data->pdev->dev, "Starting as4625_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + int status = as4625_fan_read_value(fan_reg[i]); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&data->pdev->dev, "reg %d, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + return data; +} + +static int as4625_fan_probe(struct platform_device *pdev) +{ + int status; + + data->hwmon_dev = hwmon_device_register_with_info(&pdev->dev, + DRVNAME, NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + return status; + } + + /* Register sysfs hooks */ + status = sysfs_create_group(&data->hwmon_dev->kobj, &as4625_fan_group); + if (status) + goto exit_remove; + + dev_info(&pdev->dev, "device created\n"); + return 0; + +exit_remove: + hwmon_device_unregister(data->hwmon_dev); + return status; +} + +static int as4625_fan_remove(struct platform_device *pdev) +{ + sysfs_remove_group(&data->hwmon_dev->kobj, &as4625_fan_group); + hwmon_device_unregister(data->hwmon_dev); + return 0; +} + +static struct platform_driver as4625_fan_driver = { + .probe = as4625_fan_probe, + .remove = as4625_fan_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init as4625_fan_init(void) +{ + int ret; + + data = kzalloc(sizeof(struct as4625_fan_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto alloc_err; + } + + mutex_init(&data->update_lock); + data->valid = 0; + + ret = platform_driver_register(&as4625_fan_driver); + if (ret < 0) + goto dri_reg_err; + + data->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(data->pdev)) { + ret = PTR_ERR(data->pdev); + goto dev_reg_err; + } + + return 0; + +dev_reg_err: + platform_driver_unregister(&as4625_fan_driver); +dri_reg_err: + kfree(data); +alloc_err: + return ret; +} + +static void __exit as4625_fan_exit(void) +{ + platform_device_unregister(data->pdev); + platform_driver_unregister(&as4625_fan_driver); + kfree(data); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as4625_fan driver"); +MODULE_LICENSE("GPL"); + +module_init(as4625_fan_init); +module_exit(as4625_fan_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-leds.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-leds.c new file mode 100644 index 000000000000..dfb638859883 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-leds.c @@ -0,0 +1,403 @@ +/* + * A LED driver for the as4625_led + * + * Copyright (C) 2016 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as4625_led" + +extern int as4625_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as4625_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +struct as4625_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[2]; /* Register value, 0 = System/LOC/PSU0 LED + 1 = PSU1/FAN/POE LED */ +}; + +static struct as4625_led_data *ledctl = NULL; + +#define LED_CNTRLER_I2C_ADDRESS (0x64) + +#define LED_TYPE_SYS_REG_MASK (0xF0) +#define LED_MODE_SYS_GREEN_BLINK_VALUE (0x60) +#define LED_MODE_SYS_GREEN_VALUE (0x20) +#define LED_MODE_SYS_AMBER_VALUE (0x80) +#define LED_MODE_SYS_AMBER_BLINK_VALUE (0x90) +#define LED_MODE_SYS_OFF_VALUE (0x00) + +#define LED_TYPE_LOC_REG_MASK (0x0C) +#define LED_MODE_LOC_GREEN_VALUE (0x04) +#define LED_MODE_LOC_AMBER_VALUE (0x08) +#define LED_MODE_LOC_OFF_VALUE (0x00) +#define LED_MODE_LOC_OFF_VALUE_1 (0x0C) + +#define LED_TYPE_POE_REG_MASK (0x03) +#define LED_MODE_POE_OFF_VALUE (0x00) +#define LED_MODE_POE_OFF_VALUE_1 (0x03) +#define LED_MODE_POE_GREEN_VALUE (0x01) +#define LED_MODE_POE_AMBER_VALUE (0x02) + +static const u8 led_reg[] = { + 0x30, /* System/LOC/PSU0 LED */ + 0x31 /* PSU1/FAN/POE LED */ +}; + +enum led_type { + LED_TYPE_SYS, + LED_TYPE_LOC, + LED_TYPE_PSU1, + LED_TYPE_PSU2, + LED_TYPE_FAN, + LED_TYPE_POE +}; + +/* FAN/PSU/DIAG/RELEASE led mode */ +enum led_light_mode { + LED_MODE_OFF = 0, + LED_MODE_GREEN, + LED_MODE_GREEN_BLINK, + LED_MODE_AMBER, + LED_MODE_AMBER_BLINK, + LED_MODE_RED, + LED_MODE_RED_BLINK, + LED_MODE_BLUE, + LED_MODE_BLUE_BLINK, + LED_MODE_AUTO, + LED_MODE_UNKNOWN +}; + +struct led_type_mode { + enum led_type type; + enum led_light_mode mode; + int type_mask; + int mode_value; +}; + +static struct led_type_mode led_type_mode_data[] = { + {LED_TYPE_SYS, LED_MODE_GREEN_BLINK, LED_TYPE_SYS_REG_MASK, LED_MODE_SYS_GREEN_BLINK_VALUE}, + {LED_TYPE_SYS, LED_MODE_GREEN, LED_TYPE_SYS_REG_MASK, LED_MODE_SYS_GREEN_VALUE}, + {LED_TYPE_SYS, LED_MODE_AMBER_BLINK, LED_TYPE_SYS_REG_MASK, LED_MODE_SYS_AMBER_BLINK_VALUE}, + {LED_TYPE_SYS, LED_MODE_AMBER, LED_TYPE_SYS_REG_MASK, LED_MODE_SYS_AMBER_VALUE}, + {LED_TYPE_SYS, LED_MODE_OFF, LED_TYPE_SYS_REG_MASK, LED_MODE_SYS_OFF_VALUE}, + {LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE}, + {LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE_1}, + {LED_TYPE_LOC, LED_MODE_GREEN, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_GREEN_VALUE}, + {LED_TYPE_LOC, LED_MODE_AMBER, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_VALUE}, + {LED_TYPE_POE, LED_MODE_OFF, LED_TYPE_POE_REG_MASK, LED_MODE_POE_OFF_VALUE}, + {LED_TYPE_POE, LED_MODE_OFF, LED_TYPE_POE_REG_MASK, LED_MODE_POE_OFF_VALUE_1}, + {LED_TYPE_POE, LED_MODE_GREEN, LED_TYPE_POE_REG_MASK, LED_MODE_POE_GREEN_VALUE}, + {LED_TYPE_POE, LED_MODE_AMBER, LED_TYPE_POE_REG_MASK, LED_MODE_POE_AMBER_VALUE} +}; + +static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + if (type != led_type_mode_data[i].type) { + continue; + } + + if ((led_type_mode_data[i].type_mask & reg_val) == + led_type_mode_data[i].mode_value) { + return led_type_mode_data[i].mode; + } + } + + return LED_MODE_UNKNOWN; +} + +static u8 led_light_mode_to_reg_val(enum led_type type, + enum led_light_mode mode, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + int type_mask, mode_value; + + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + type_mask = led_type_mode_data[i].type_mask; + mode_value = led_type_mode_data[i].mode_value; + reg_val = (reg_val & ~type_mask) | mode_value; + } + + return reg_val; +} + +static int as4625_led_read_value(u8 reg) +{ + return as4625_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); +} + +static int as4625_led_write_value(u8 reg, u8 value) +{ + return as4625_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); +} + +static void as4625_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting as4625_led update\n"); + ledctl->valid = 0; + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = as4625_led_read_value(led_reg[i]); + + if (status < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status); + goto exit; + } + else { + ledctl->reg_val[i] = status; + } + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void as4625_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + int reg_val; + + mutex_lock(&ledctl->update_lock); + reg_val = as4625_led_read_value(reg); + + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + as4625_led_write_value(reg, reg_val); + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void as4625_led_auto_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ +} + +static enum led_brightness as4625_led_auto_get(struct led_classdev *cdev) +{ + return LED_MODE_AUTO; +} + +static void as4625_led_sys_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as4625_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_SYS); +} + +static enum led_brightness as4625_led_sys_get(struct led_classdev *cdev) +{ + as4625_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_SYS, ledctl->reg_val[0]); +} + +static enum led_brightness as4625_led_loc_get(struct led_classdev *cdev) +{ + as4625_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]); +} + +static void as4625_led_loc_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as4625_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC); +} + +static enum led_brightness as4625_led_poe_get(struct led_classdev *cdev) +{ + as4625_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_POE, ledctl->reg_val[1]); +} + +static void as4625_led_poe_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as4625_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_POE); +} + +static struct led_classdev as4625_leds[] = { + [LED_TYPE_SYS] = { + .name = "as4625_led::sys", + .default_trigger = "unused", + .brightness_set = as4625_led_sys_set, + .brightness_get = as4625_led_sys_get, + .max_brightness = LED_MODE_AMBER_BLINK, + }, + [LED_TYPE_LOC] = { + .name = "as4625_led::loc", + .default_trigger = "unused", + .brightness_set = as4625_led_loc_set, + .brightness_get = as4625_led_loc_get, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_PSU1] = { + .name = "as4625_led::psu1", + .default_trigger = "unused", + .brightness_set = as4625_led_auto_set, + .brightness_get = as4625_led_auto_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "as4625_led::psu2", + .default_trigger = "unused", + .brightness_set = as4625_led_auto_set, + .brightness_get = as4625_led_auto_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN] = { + .name = "as4625_led::fan", + .default_trigger = "unused", + .brightness_set = as4625_led_auto_set, + .brightness_get = as4625_led_auto_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_POE] = { + .name = "as4625_led::poe", + .default_trigger = "unused", + .brightness_set = as4625_led_poe_set, + .brightness_get = as4625_led_poe_get, + .max_brightness = LED_MODE_AMBER, + } +}; + +static int as4625_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(as4625_leds); i++) { + ret = led_classdev_register(&pdev->dev, &as4625_leds[i]); + + if (ret < 0) { + break; + } + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(as4625_leds)){ + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&as4625_leds[i]); + } + } + + return ret; +} + +static int as4625_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(as4625_leds); i++) { + led_classdev_unregister(&as4625_leds[i]); + } + + return 0; +} + +static struct platform_driver as4625_led_driver = { + .probe = as4625_led_probe, + .remove = as4625_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init as4625_led_init(void) +{ + int ret; + + ret = platform_driver_register(&as4625_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct as4625_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + goto exit_driver; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + goto exit_free; + } + + return 0; + +exit_free: + kfree(ledctl); +exit_driver: + platform_driver_unregister(&as4625_led_driver); +exit: + return ret; +} + +static void __exit as4625_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&as4625_led_driver); + kfree(ledctl); +} + +late_initcall(as4625_led_init); +module_exit(as4625_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as4625_led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c new file mode 100644 index 000000000000..3592a31fda29 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c @@ -0,0 +1,375 @@ +/* + * An hwmon driver for accton as4625_54p Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as4625_54p_psu" + +#define PSU_STATUS_I2C_ADDR 0x64 +#define PSU_STATUS_I2C_REG_OFFSET 0x4 + +#define MODEL_NAME_LEN 13 +#define MODEL_NAME_REG_OFFSET 0x15 + +#define SERIAL_NUM_LEN 9 +#define SERIAL_NUM_REG_OFFSET 0x35 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4+2))) +#define IS_PRESENT(id, value) (!(value & BIT(id*4))) + +#define FAN_DIR_LEN 3 +const char FAN_DIR_F2B[] = "F2B"; +const char FAN_DIR_B2F[] = "B2F"; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +extern int as4625_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as4625_54p_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MODEL_NAME_LEN+1]; /* Model name, read from eeprom */ + char serial[SERIAL_NUM_LEN+1]; /* Serial number, read from eeprom*/ + char fan_dir[FAN_DIR_LEN+1]; +}; + +static struct as4625_54p_psu_data *as4625_54p_psu_update_device(struct device *dev); + +enum as4625_54p_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER, + PSU_FAN_DIR +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_numer, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); +static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_string, NULL, PSU_FAN_DIR); + +static struct attribute *as4625_54p_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_numer.dev_attr.attr, + &sensor_dev_attr_psu_fan_dir.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4625_54p_psu_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u8 status = 0; + + mutex_lock(&data->update_lock); + + data = as4625_54p_psu_update_device(dev); + if (!data->valid) { + mutex_unlock(&data->update_lock); + return sprintf(buf, "0\n"); + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4625_54p_psu_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + char *ptr = NULL; + int ret = 0; + + mutex_lock(&data->update_lock); + + data = as4625_54p_psu_update_device(dev); + if (!data->valid) { + ret = -EIO; + goto exit; + } + + switch (attr->index) { + case PSU_MODEL_NAME: + ptr = data->model_name; + break; + case PSU_SERIAL_NUMBER: + ptr = data->serial; + break; + case PSU_FAN_DIR: + ptr = data->fan_dir; + break; + default: + ret = -EINVAL; + goto exit; + } + + ret = sprintf(buf, "%s\n", ptr); + +exit: + mutex_unlock(&data->update_lock); + return ret; +} + +static const struct attribute_group as4625_54p_psu_group = { + .attrs = as4625_54p_psu_attributes, +}; + +static int as4625_54p_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as4625_54p_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as4625_54p_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as4625_54p_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, + DRVNAME, NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as4625_54p_psu_group); +exit_free: + kfree(data); +exit: + return status; +} + +static int as4625_54p_psu_remove(struct i2c_client *client) +{ + struct as4625_54p_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as4625_54p_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as4625_54p_psu1, + as4625_54p_psu2 +}; + +static const struct i2c_device_id as4625_54p_psu_id[] = { + { "as4625_54p_psu1", as4625_54p_psu1 }, + { "as4625_54p_psu2", as4625_54p_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as4625_54p_psu_id); + +static struct i2c_driver as4625_54p_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as4625_54p_psu_probe, + .remove = as4625_54p_psu_remove, + .id_table = as4625_54p_psu_id, + .address_list = normal_i2c, +}; + +static int as4625_54p_psu_read_byte(struct i2c_client *client, u8 command, u8 *data) +{ + int status = 0; + int retry_count = 5; + + while (retry_count) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(10); + retry_count--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + +abort: + return status; +} + +static int as4625_54p_psu_read_bytes(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int ret = 0; + + while (data_len) { + ssize_t status; + + status = as4625_54p_psu_read_byte(client, command, data); + if (status <= 0) { + ret = status; + break; + } + + data += 1; + command += 1; + data_len -= 1; + } + + return ret; +} + +static struct as4625_54p_psu_data *as4625_54p_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4625_54p_psu_data *data = i2c_get_clientdata(client); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + + dev_dbg(&client->dev, "Starting as4625_54p update\n"); + data->valid = 0; + + /* Read psu status */ + status = as4625_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial, 0, sizeof(data->serial)); + memset(data->fan_dir, 0, sizeof(data->fan_dir)); + + if (IS_POWER_GOOD(data->index, data->status)) { + /* Read model name */ + status = as4625_54p_psu_read_bytes(client, MODEL_NAME_REG_OFFSET, data->model_name, + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + goto exit; + } + + /* Read serial number */ + status = as4625_54p_psu_read_bytes(client, SERIAL_NUM_REG_OFFSET, data->serial, + ARRAY_SIZE(data->serial)-1); + if (status < 0) { + data->serial[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial number from (0x%x)\n", client->addr); + goto exit; + } + else { + data->serial[ARRAY_SIZE(data->serial)-1] = '\0'; + } + + if (strncmp(data->model_name, "UP1K21R-1085G", ARRAY_SIZE(data->model_name)-1) == 0) + memcpy(data->fan_dir, FAN_DIR_F2B, sizeof(FAN_DIR_F2B)); + else + data->fan_dir[0] = '\0'; + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + return data; +} + +module_i2c_driver(as4625_54p_psu_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as4625_54p_psu driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/ym2651y.c new file mode 120000 index 000000000000..f4d67640ccc3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-init.service new file mode 100644 index 000000000000..2912050a962d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-init.service @@ -0,0 +1,17 @@ +[Unit] +Description=Accton AS4625-54P Platform initialization service +Before=pmon.service determine-reboot-cause.service system-health.service +After=sysinit.target +DefaultDependencies=no + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/accton_as4625_54p_util.py install +ExecStop=/usr/local/bin/accton_as4625_54p_util.py clean + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-monitor.service new file mode 100644 index 000000000000..02985c241687 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/service/as4625-54p-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4625-54P Platform Monitoring service +Before=pmon.service +After=as4625-54p-platform-init.service +Requires=as4625-54p-platform-init.service + +[Service] +ExecStart=/usr/local/bin/accton_as4625_54p_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/setup.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/setup.py new file mode 100644 index 000000000000..2e97a7fa8de3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/setup.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='as4625_54p', + version='1.0', + description='Module to initialize Accton AS4625-54P platforms', + + packages=['as4625_54p'], + package_dir={'as4625_54p': 'as4625-54p/classes'}, +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/sonic_platform_setup.py new file mode 100644 index 000000000000..98c962923a3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/sonic_platform_setup.py @@ -0,0 +1,30 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as4625_54p-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py new file mode 100755 index 000000000000..5899acee1b8f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py @@ -0,0 +1,275 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -* +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# ------------------------------------------------------------------ + +try: + import sys + import logging + import logging.config + import logging.handlers + import time + import sonic_platform.platform + from sonic_platform.helper import APIHelper +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4625_54p_monitor' +I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" + +FAN_SPEED_DEFAULT = 38 +FAN_SPEED_MAX = 100 + +ERROR_CONFIG_LOGGING = 1 +ERROR_CHASSIS_LOAD = 2 +ERROR_DEVICE_MONITOR_LOAD = 3 + +global log_file +global log_level + +platform_chassis = None + +def configure_logging(log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S') + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter( + '%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler( + address='/dev/log') + sys_handler.setLevel(logging.WARNING) + logging.getLogger('').addHandler(sys_handler) + +# Instantiate platform-specific Chassis class +def load_platform_chassis(): + global platform_chassis + + # Load new platform api class + if platform_chassis: + return True + + try: + platform_chassis = sonic_platform.platform.Platform().get_chassis() + except Exception as e: + logging.error("Failed to instantiate Chassis: %s", repr(e)) + + if not platform_chassis: + return False + + return True + +THERMAL_1_ON_MAIN_BROAD = '0x4a' +THERMAL_2_ON_MAIN_BROAD = '0x4b' +THERMAL_3_ON_MAIN_BROAD = '0x4d' +THERMAL_5_ON_MAIN_BROAD = '0x4f' + +# Temperature Policy +class device_monitor(object): + PWM_STATE_NORMAL = 0 + PWM_STATE_CRITICAL = 1 + + def __init__(self, chassis): + self._api_helper = APIHelper() + self.chassis = chassis + self.warning = False + self.shutdown = False + self.fan_failed = False + self.pwm_state = self.PWM_STATE_NORMAL + + self._set_all_fan_speed(self._get_default_speed()) + + def _set_all_fan_speed(self, speed): + ret = True + + for drawer_index, drawer in enumerate(self.chassis.get_all_fan_drawers()): + for fan_index, fan in enumerate(drawer.get_all_fans()): + if fan.set_speed(speed) is not True: + logging.error("fan.set_speed error, drawer(%d)-fan(%d)", drawer_index, fan_index) + ret = False + + return ret + + def _get_default_speed(self): + return FAN_SPEED_DEFAULT + + def _get_fan_speed(self): + return { + self.PWM_STATE_NORMAL: FAN_SPEED_DEFAULT, + self.PWM_STATE_CRITICAL: FAN_SPEED_MAX + }.get(self.pwm_state, self._get_default_speed()) + + def _get_system_temperature(self): + sys_thermals = [ + THERMAL_1_ON_MAIN_BROAD, + THERMAL_2_ON_MAIN_BROAD, + THERMAL_3_ON_MAIN_BROAD, + THERMAL_5_ON_MAIN_BROAD + ] + + sys_temp = 0 + for thermal in self.chassis.get_all_thermals(): + for item in sys_thermals: + if item in thermal.get_name(): + sys_temp += thermal.get_temperature() + break + + return sys_temp + + def _get_system_low_threshold(self): + return 135 + + def _get_system_high_threshold(self): + return 202 + + def _refresh_thermal_status(self): + # check if current state is valid + if (self.pwm_state < self.PWM_STATE_NORMAL or + self.pwm_state > self.PWM_STATE_CRITICAL): + self.pwm_state = self.PWM_STATE_NORMAL + + # check system temperature + temperature = self._get_system_temperature() + if temperature > self._get_system_high_threshold(): + self.warning = True + else: + self.warning = False + + if self.pwm_state == self.PWM_STATE_CRITICAL: + if temperature < self._get_system_low_threshold(): + self.pwm_state = self.PWM_STATE_NORMAL + else: + if temperature > self._get_system_high_threshold(): + self.pwm_state = self.PWM_STATE_CRITICAL + logging.warning("system temperature(%d) reach high threshold(%d)", + temperature, self._get_system_high_threshold()) + + # check temperature of each thermal + for thermal in self.chassis.get_all_thermals(): + temperature = thermal.get_temperature() + + if temperature >= thermal.get_high_critical_threshold(): + self.warning = True + self.shutdown = True + logging.critical("thermal(%s) temperature(%d) reach shutdown threshold(%d)", + thermal.get_name(), temperature, + thermal.get_high_critical_threshold()) + elif temperature >= thermal.get_high_threshold(): + self.warning = True + logging.warning("thermal(%s) temperature(%d) reach high threshold(%d)", + thermal.get_name(), temperature, + thermal.get_high_threshold()) + + if self.warning is True or self.shutdown is True: + self.pwm_state = self.PWM_STATE_CRITICAL + + return True + + def _refresh_fan_status(self): + self.fan_failed = False + for drawer_index, drawer in enumerate(self.chassis.get_all_fan_drawers()): + for fan_index, fan in enumerate(drawer.get_all_fans()): + if fan.get_presence() is not True: + self.fan_failed = True + logging.error("drawer(%d)-fan(%d) is not present", + drawer_index, fan_index) + break + + if fan.get_status() is not True: + self.fan_failed = True + logging.error("drawer(%d)-fan(%d) is not operational ", + drawer_index, fan_index) + break + + return True + + def manage_fans(self): + try: + prev_warning = self.warning + self._refresh_fan_status() + self._refresh_thermal_status() + except: + self._set_all_fan_speed(FAN_SPEED_MAX) + logging.error("Error occurred while updating fan and thermal status") + return + + if self.fan_failed is True: + self._set_all_fan_speed(FAN_SPEED_MAX) + else: + self._set_all_fan_speed(self._get_fan_speed()) + + if prev_warning != self.warning: + if self.warning is True: + logging.warning('Alarm for temperature high is detected') + else: + logging.info('Alarm for temperature high is cleared') + + if self.shutdown is True: + # critical case*/ + logging.critical( + 'Alarm-Critical for temperature critical is detected, disable PoE') + path = I2C_PATH.format('0', '64') + 'pwr_enable_poe' + self._api_helper.write_txt_file(path, 0) + + logging.critical( + 'Alarm-Critical for temperature critical is detected, shutdown DUT') + path = I2C_PATH.format('0', '64') + 'pwr_enable_mb' + time.sleep(2) + self._api_helper.write_txt_file(path, 0) + + return + +def main(argv): + global platform_chassis + + # configure logging + try: + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + configure_logging(log_file, log_level) + except: + print("Failed to configure logging") + sys.exit(ERROR_CONFIG_LOGGING) + + # Load platform-specific Chassis class + if not load_platform_chassis(): + sys.exit(ERROR_CHASSIS_LOAD) + + try: + monitor = device_monitor(platform_chassis) + except: + logging.error("Failed to instantiate device_monitor") + sys.exit(ERROR_DEVICE_MONITOR_LOAD) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) # 10sec + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py new file mode 100755 index 000000000000..22d5a66615d7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py @@ -0,0 +1,379 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import subprocess +import getopt +import sys +import logging +import time +import os + +PROJECT_NAME = 'as4625_54p' +DEBUG = False +ARGS = [] +FORCE = 0 + +def main(): + global DEBUG + global ARGS + global FORCE + + if len(sys.argv) < 2: + return 0 + + (options, ARGS) = getopt.getopt(sys.argv[1:], 'hdf', + ['help','debug', 'force']) + if DEBUG == True: + print(options) + print(ARGS) + print(len(sys.argv)) + + for arg in ARGS: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() + return 0 + +def log_os_system(cmd, show): + logging.info('Run :' + cmd) + status, output = subprocess.getstatusoutput(cmd) + if status: + logging.info('Failed :' + cmd) + if show: + print('Failed :' + cmd) + return (status, output) + +def driver_check(): + ret, lsmod = log_os_system("ls /sys/module/*accton*", 0) + logging.info('mods:'+lsmod) + if ret : + return False + else : + return True + +def new_device(driver, addr, bus, devdir): + if not os.path.exists(os.path.join(bus, devdir)): + try: + with open("%s/new_device" % bus, "w") as f: + f.write("%s 0x%x\n" % (driver, addr)) + f.flush() + except Exception as e: + print("Unexpected error initialize device %s:0x%x:%s: %s" % (driver, addr, bus, e)) + return None + + if not os.path.exists(os.path.join(bus, devdir)): + return False + elif driver.find('pca954') != -1: + if not os.path.exists(os.path.join(bus, devdir, "channel-0")): + delete_device(addr, bus, devdir) + return False + elif os.path.exists(os.path.join(bus, devdir, "idle_state")): + try: + with open(os.path.join(bus, devdir, "idle_state"), "w") as f: + f.write("-2\n") + except Exception as e: + return False + else: + print("Device %s:%x:%s already exists." % (driver, addr, bus)) + return False + + return True + +def delete_device(addr, bus, devdir): + if os.path.exists(os.path.join(bus, devdir)): + try: + with open("%s/delete_device" % bus, "w") as f: + f.write("%s\n" % addr) + f.flush() + except Exception as e: + print("Unexpected error delete device 0x%x:%s: %s" % (addr, bus, e)) + return None + else: + print("Device %x:%s does not exist." % (addr, bus)) + return True + + return True + +def new_i2c_device(driver, addr, bus_number): + bus = '/sys/bus/i2c/devices/i2c-%d' % bus_number + devdir = "%d-%4.4x" % (bus_number, addr) + return new_device(driver, addr, bus, devdir) + +def delete_i2c_device(addr, bus_number): + bus = '/sys/bus/i2c/devices/i2c-%d' % bus_number + devdir = "%d-%4.4x" % (bus_number, addr) + return delete_device(addr, bus, devdir) + +def new_i2c_devices(new_device_list): + for (driver, addr, bus_number) in new_device_list: + for i in range(0, 30): + if new_i2c_device(driver, addr, bus_number) is not True: + time.sleep(1) + continue + else: + break + else: + return False + + return True + +def new_sfp_devices(sfp_bus_list, driver): + for bus_number in sfp_bus_list: + for i in range(0, 30): + if new_i2c_device(driver, 0x50, bus_number) is not True: + time.sleep(1) + continue + else: + break + else: + return False + + return True + +def delete_i2c_devices(delete_device_list): + ret = True + + for (driver, addr, bus_number) in delete_device_list: + if delete_i2c_device(addr, bus_number) is not True: + ret = False + continue + + return ret + +def delete_sfp_devices(sfp_bus_list): + ret = True + + for bus_number in sfp_bus_list: + if delete_i2c_device(0x50, bus_number) is not True: + ret = False + continue + + return ret + +kos = [ + 'depmod -ae', + 'modprobe i2c_dev', + 'modprobe i2c_i801', + 'modprobe i2c_ismt', + 'modprobe i2c_mux_pca954x', + 'modprobe x86-64-accton-as4625-54p-cpld', + 'modprobe x86-64-accton-as4625-54p-fan', + 'modprobe x86-64-accton-as4625-54p-leds', + 'modprobe x86-64-accton-as4625-54p-psu', + 'modprobe optoe', + 'modprobe ym2651y'] + +def driver_install(): + global FORCE + + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in reversed(range(0,len(kos))): + rm = kos[i].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 + +def write_txt_file(file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(value) + except IOError as e: + print("Error write value to file: %s" % str(e)) + return False + return True + +i2c_prefix = '/sys/bus/i2c/devices/' + +i2c_device_list = [ + # initialize multiplexer (PCA9548) + ('pca9548', 0x70, 1), + ('pca9548', 0x71, 1), + + # initialize CPLD + ('as4625_cpld1', 0x64, 0), + + # initiate PSU-1 AC Power + ('as4625_54p_psu1', 0x50, 8), + ('umec_up1k21r', 0x58, 8), + + # initiate PSU-2 AC Power + ('as4625_54p_psu2', 0x51, 9), + ('umec_up1k21r', 0x59, 9), + + # inititate LM75 + ('lm75', 0x4A, 3), + ('lm75', 0x4B, 3), + ('lm75', 0x4D, 3), + ('lm75', 0x4E, 3), + ('lm75', 0x4F, 3), + + # initiate IDPROM + ('24c02', 0x51, 7) +] + +sfp_bus_list = [ 10, 11, 12, 13, 14, 15 ] + +def device_install(): + global FORCE + + if new_i2c_devices(i2c_device_list) is not True: + return 1 + + if new_sfp_devices(sfp_bus_list, 'optoe2') is not True: + return 1 + + for p in range(len(sfp_bus_list)): + path = "/sys/bus/i2c/devices/{0}-0050/port_name".format(sfp_bus_list[p]) + if write_txt_file(path, 'port{0}'.format(p+49)) is not True: + return 1 + + return + +def device_uninstall(): + global FORCE + + if delete_sfp_devices(sfp_bus_list) is not True: + return 1 + + if delete_i2c_devices(i2c_device_list[::-1]) is not True: + return 1 + + return + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_install(): + print('Checking system....') + if driver_check() is False: + print('No driver, installing....') + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' drivers detected....') + if not device_exist(): + print('No device, installing....') + status = device_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' devices detected....') + + do_sonic_platform_install() + + return + +def do_uninstall(): + print('Checking system....') + if not device_exist(): + print(PROJECT_NAME.upper() + ' has no device installed....') + else: + print('Removing device....') + status = device_uninstall() + if status and FORCE == 0: + return status + + if driver_check() is False: + print(PROJECT_NAME.upper() + ' has no driver installed....') + else: + print('Removing installed driver....') + status = driver_uninstall() + if status and FORCE == 0: + return status + + do_sonic_platform_clean() + + return None + +def device_exist(): + ret1 = log_os_system('ls ' + i2c_prefix + '*0070', 0) + ret2 = log_os_system('ls ' + i2c_prefix + 'i2c-2', 0) + return not (ret1[0] or ret2[0]) + +if __name__ == '__main__': + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/classes/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/Makefile new file mode 100644 index 000000000000..2e596deaa272 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/Makefile @@ -0,0 +1,16 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= x86-64-accton-as4625-54t-cpld.o x86-64-accton-as4625-54t-fan.o \ + x86-64-accton-as4625-54t-psu.o x86-64-accton-as4625-54t-leds.o ym2651y.o + +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-cpld.c new file mode 120000 index 000000000000..d944bb8b29a7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-cpld.c @@ -0,0 +1 @@ +../../as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-fan.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-fan.c new file mode 120000 index 000000000000..9b73f7a09c07 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-fan.c @@ -0,0 +1 @@ +../../as4625-54p/modules/x86-64-accton-as4625-54p-fan.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-leds.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-leds.c new file mode 120000 index 000000000000..e5303ebb4f09 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-leds.c @@ -0,0 +1 @@ +../../as4625-54p/modules/x86-64-accton-as4625-54p-leds.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c new file mode 100644 index 000000000000..63f7eb80c061 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c @@ -0,0 +1,377 @@ +/* + * An hwmon driver for accton as4625_54t Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as4625_54t_psu" + +#define PSU_STATUS_I2C_ADDR 0x64 +#define PSU_STATUS_I2C_REG_OFFSET 0x4 + +#define MODEL_NAME_LEN 15 +#define MODEL_NAME_REG_OFFSET 0x15 + +#define SERIAL_NUM_LEN 9 +#define SERIAL_NUM_REG_OFFSET 0x35 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4+2))) +#define IS_PRESENT(id, value) (!(value & BIT(id*4))) + +#define FAN_DIR_LEN 3 +const char FAN_DIR_F2B[] = "F2B"; +const char FAN_DIR_B2F[] = "B2F"; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +extern int as4625_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as4625_54t_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MODEL_NAME_LEN+1]; /* Model name, read from eeprom */ + char serial[SERIAL_NUM_LEN+1]; /* Serial number, read from eeprom*/ + char fan_dir[FAN_DIR_LEN+1]; +}; + +static struct as4625_54t_psu_data *as4625_54t_psu_update_device(struct device *dev); + +enum as4625_54t_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER, + PSU_FAN_DIR +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_numer, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); +static SENSOR_DEVICE_ATTR(psu_fan_dir, S_IRUGO, show_string, NULL, PSU_FAN_DIR); + +static struct attribute *as4625_54t_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_numer.dev_attr.attr, + &sensor_dev_attr_psu_fan_dir.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4625_54t_psu_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u8 status = 0; + + mutex_lock(&data->update_lock); + + data = as4625_54t_psu_update_device(dev); + if (!data->valid) { + mutex_unlock(&data->update_lock); + return sprintf(buf, "0\n"); + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4625_54t_psu_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + char *ptr = NULL; + int ret = 0; + + mutex_lock(&data->update_lock); + + data = as4625_54t_psu_update_device(dev); + if (!data->valid) { + ret = -EIO; + goto exit; + } + + switch (attr->index) { + case PSU_MODEL_NAME: + ptr = data->model_name; + break; + case PSU_SERIAL_NUMBER: + ptr = data->serial; + break; + case PSU_FAN_DIR: + ptr = data->fan_dir; + break; + default: + ret = -EINVAL; + goto exit; + } + + ret = sprintf(buf, "%s\n", ptr); + +exit: + mutex_unlock(&data->update_lock); + return ret; +} + +static const struct attribute_group as4625_54t_psu_group = { + .attrs = as4625_54t_psu_attributes, +}; + +static int as4625_54t_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as4625_54t_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as4625_54t_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + i2c_set_clientdata(client, data); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as4625_54t_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, + DRVNAME, NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as4625_54t_psu_group); +exit_free: + kfree(data); +exit: + return status; +} + +static int as4625_54t_psu_remove(struct i2c_client *client) +{ + struct as4625_54t_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as4625_54t_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as4625_54t_psu1, + as4625_54t_psu2 +}; + +static const struct i2c_device_id as4625_54t_psu_id[] = { + { "as4625_54t_psu1", as4625_54t_psu1 }, + { "as4625_54t_psu2", as4625_54t_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as4625_54t_psu_id); + +static struct i2c_driver as4625_54t_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as4625_54t_psu_probe, + .remove = as4625_54t_psu_remove, + .id_table = as4625_54t_psu_id, + .address_list = normal_i2c, +}; + +static int as4625_54t_psu_read_byte(struct i2c_client *client, u8 command, u8 *data) +{ + int status = 0; + int retry_count = 5; + + while (retry_count) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(10); + retry_count--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + +abort: + return status; +} + +static int as4625_54t_psu_read_bytes(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int ret = 0; + + while (data_len) { + ssize_t status; + + status = as4625_54t_psu_read_byte(client, command, data); + if (status <= 0) { + ret = status; + break; + } + + data += 1; + command += 1; + data_len -= 1; + } + + return ret; +} + +static struct as4625_54t_psu_data *as4625_54t_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as4625_54t_psu_data *data = i2c_get_clientdata(client); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + + dev_dbg(&client->dev, "Starting as4625_54t update\n"); + data->valid = 0; + + /* Read psu status */ + status = as4625_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial, 0, sizeof(data->serial)); + memset(data->fan_dir, 0, sizeof(data->fan_dir)); + + if (IS_POWER_GOOD(data->index, data->status)) { + /* Read model name */ + status = as4625_54t_psu_read_bytes(client, MODEL_NAME_REG_OFFSET, data->model_name, + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + goto exit; + } + + /* Read serial number */ + status = as4625_54t_psu_read_bytes(client, SERIAL_NUM_REG_OFFSET, data->serial, + ARRAY_SIZE(data->serial)-1); + if (status < 0) { + data->serial[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial number from (0x%x)\n", client->addr); + goto exit; + } + else { + data->serial[ARRAY_SIZE(data->serial)-1] = '\0'; + } + + if (strncmp(data->model_name, "UPD1501SA-1179G", ARRAY_SIZE(data->model_name)-1) == 0) + memcpy(data->fan_dir, FAN_DIR_F2B, sizeof(FAN_DIR_F2B)); + else if (strncmp(data->model_name, "UPD1501SA-1279G", ARRAY_SIZE(data->model_name)-1) == 0) + memcpy(data->fan_dir, FAN_DIR_B2F, sizeof(FAN_DIR_B2F)); + else + data->fan_dir[0] = '\0'; + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + return data; +} + +module_i2c_driver(as4625_54t_psu_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as4625_54t_psu driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/ym2651y.c new file mode 120000 index 000000000000..f4d67640ccc3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-init.service b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-init.service new file mode 100644 index 000000000000..cf7abbfb93a8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-init.service @@ -0,0 +1,17 @@ +[Unit] +Description=Accton AS4625-54T Platform initialization service +Before=pmon.service determine-reboot-cause.service system-health.service +After=sysinit.target +DefaultDependencies=no + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/accton_as4625_54t_util.py install +ExecStop=/usr/local/bin/accton_as4625_54t_util.py clean + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-monitor.service new file mode 100644 index 000000000000..5e31a85fada0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/service/as4625-54t-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4625-54T Platform Monitoring service +Before=pmon.service +After=as4625-54t-platform-init.service +Requires=as4625-54t-platform-init.service + +[Service] +ExecStart=/usr/local/bin/accton_as4625_54t_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/setup.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/setup.py new file mode 100644 index 000000000000..941f53b5429b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/setup.py @@ -0,0 +1,14 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='as4625_54t', + version='1.0', + description='Module to initialize Accton AS4625-54T platforms', + + packages=['as4625_54t'], + package_dir={'as4625_54t': 'as4625-54t/classes'}, +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/sonic_platform_setup.py new file mode 100644 index 000000000000..7b6debe777d1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/sonic_platform_setup.py @@ -0,0 +1,30 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as4625_54t-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + packages=['sonic_platform'], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py new file mode 100755 index 000000000000..ab479a759597 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py @@ -0,0 +1,307 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -* +# Copyright (c) 2019 Edgecore Networks Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +# +# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR +# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT +# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS +# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. +# +# See the Apache Version 2.0 License for specific language governing +# permissions and limitations under the License. +# ------------------------------------------------------------------ + +try: + import sys + import logging + import logging.config + import logging.handlers + import time + import sonic_platform.platform + from sonic_platform.helper import APIHelper +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as4625_54t_monitor' +I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" + +FAN_SPEED_DEFAULT_F2B = 38 +FAN_SPEED_DEFAULT_B2F = 25 +FAN_SPEED_MAX = 100 + +ERROR_CONFIG_LOGGING = 1 +ERROR_CHASSIS_LOAD = 2 +ERROR_DEVICE_MONITOR_LOAD = 3 + +global log_file +global log_level + +platform_chassis = None + +def configure_logging(log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format='[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S') + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter( + '%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler( + address='/dev/log') + sys_handler.setLevel(logging.WARNING) + logging.getLogger('').addHandler(sys_handler) + +# Instantiate platform-specific Chassis class +def load_platform_chassis(): + global platform_chassis + + # Load new platform api class + if platform_chassis: + return True + + try: + platform_chassis = sonic_platform.platform.Platform().get_chassis() + except Exception as e: + logging.error("Failed to instantiate Chassis: %s", repr(e)) + + if not platform_chassis: + return False + + return True + +THERMAL_1_ON_MAIN_BROAD = '0x4a' +THERMAL_2_ON_MAIN_BROAD = '0x4b' +THERMAL_3_ON_MAIN_BROAD = '0x4d' +THERMAL_5_ON_MAIN_BROAD = '0x4f' + +# Temperature Policy +class device_monitor(object): + PWM_STATE_NORMAL = 0 + PWM_STATE_CRITICAL = 1 + + PCB_ID_AS4625_54T_F2B = 1 + PCB_ID_AS4625_54T_B2F = 2 + + def __init__(self, chassis): + self._api_helper = APIHelper() + self.chassis = chassis + self.warning = False + self.shutdown = False + self.fan_failed = False + self.pwm_state = self.PWM_STATE_NORMAL + + self.pcb_id = self._get_pcb_id() + if (self.pcb_id < self.PCB_ID_AS4625_54T_F2B or + self.pcb_id > self.PCB_ID_AS4625_54T_B2F): + self.pcb_id = self.PCB_ID_AS4625_54T_F2B + + self._set_all_fan_speed(self._get_default_speed()) + + def _get_pcb_id(self): + cpld_path = I2C_PATH.format('0', '64') + 'pcb_id' + pcb_id = self._api_helper.read_txt_file(cpld_path) + if pcb_id is not None: + return int(pcb_id) + + return None + + def _set_all_fan_speed(self, speed): + ret = True + + for drawer_index, drawer in enumerate(self.chassis.get_all_fan_drawers()): + for fan_index, fan in enumerate(drawer.get_all_fans()): + if fan.set_speed(speed) is not True: + logging.error("fan.set_speed error, drawer(%d)-fan(%d)", drawer_index, fan_index) + ret = False + + return ret + + def _get_default_speed(self): + return { + self.PCB_ID_AS4625_54T_F2B: FAN_SPEED_DEFAULT_F2B, + self.PCB_ID_AS4625_54T_B2F: FAN_SPEED_DEFAULT_B2F + }.get(self.pcb_id, max(FAN_SPEED_DEFAULT_F2B, FAN_SPEED_DEFAULT_B2F)) + + def _get_fan_speed(self): + speed_dict = { + self.PCB_ID_AS4625_54T_F2B: { + self.PWM_STATE_NORMAL: FAN_SPEED_DEFAULT_F2B, + self.PWM_STATE_CRITICAL: FAN_SPEED_MAX + }, + self.PCB_ID_AS4625_54T_B2F: { + self.PWM_STATE_NORMAL: FAN_SPEED_DEFAULT_B2F, + self.PWM_STATE_CRITICAL: FAN_SPEED_MAX + } + } + return speed_dict[self.pcb_id].get(self.pwm_state, self._get_default_speed()) + + def _get_system_temperature(self): + sys_thermals = [ + THERMAL_1_ON_MAIN_BROAD, + THERMAL_2_ON_MAIN_BROAD, + THERMAL_3_ON_MAIN_BROAD, + THERMAL_5_ON_MAIN_BROAD + ] + + sys_temp = 0 + for thermal in self.chassis.get_all_thermals(): + for item in sys_thermals: + if item in thermal.get_name(): + sys_temp += thermal.get_temperature() + break + + return sys_temp + + def _get_system_low_threshold(self): + LOW_THRESHOLD_F2B = 111 + LOW_THRESHOLD_B2F = 116 + return { + self.PCB_ID_AS4625_54T_F2B: LOW_THRESHOLD_F2B, + self.PCB_ID_AS4625_54T_B2F: LOW_THRESHOLD_B2F + }.get(self.pcb_id, min(LOW_THRESHOLD_F2B, LOW_THRESHOLD_B2F)) + + def _get_system_high_threshold(self): + HIGH_THRESHOLD_F2B = 186 + HIGH_THRESHOLD_B2F = 184 + return { + self.PCB_ID_AS4625_54T_F2B: HIGH_THRESHOLD_F2B, + self.PCB_ID_AS4625_54T_B2F: HIGH_THRESHOLD_B2F + }.get(self.pcb_id, min(HIGH_THRESHOLD_F2B, HIGH_THRESHOLD_B2F)) + + def _refresh_thermal_status(self): + # check if current state is valid + if (self.pwm_state < self.PWM_STATE_NORMAL or + self.pwm_state > self.PWM_STATE_CRITICAL): + self.pwm_state = self.PWM_STATE_NORMAL + + # check system temperature + temperature = self._get_system_temperature() + if temperature > self._get_system_high_threshold(): + self.warning = True + else: + self.warning = False + + if self.pwm_state == self.PWM_STATE_CRITICAL: + if temperature < self._get_system_low_threshold(): + self.pwm_state = self.PWM_STATE_NORMAL + else: + if temperature > self._get_system_high_threshold(): + self.pwm_state = self.PWM_STATE_CRITICAL + logging.warning("system temperature(%d) reach high threshold(%d)", + temperature, self._get_system_high_threshold()) + + # check temperature of each thermal + for thermal in self.chassis.get_all_thermals(): + temperature = thermal.get_temperature() + + if temperature >= thermal.get_high_critical_threshold(): + self.warning = True + self.shutdown = True + logging.critical("thermal(%s) temperature(%d) reach shutdown threshold(%d)", + thermal.get_name(), temperature, + thermal.get_high_critical_threshold()) + elif temperature >= thermal.get_high_threshold(): + self.warning = True + logging.warning("thermal(%s) temperature(%d) reach high threshold(%d)", + thermal.get_name(), temperature, + thermal.get_high_threshold()) + + if self.warning is True or self.shutdown is True: + self.pwm_state = self.PWM_STATE_CRITICAL + + return True + + def _refresh_fan_status(self): + self.fan_failed = False + for drawer_index, drawer in enumerate(self.chassis.get_all_fan_drawers()): + for fan_index, fan in enumerate(drawer.get_all_fans()): + if fan.get_presence() is not True: + self.fan_failed = True + logging.error("drawer(%d)-fan(%d) is not present", + drawer_index, fan_index) + break + + if fan.get_status() is not True: + self.fan_failed = True + logging.error("drawer(%d)-fan(%d) is not operational ", + drawer_index, fan_index) + break + + return True + + def manage_fans(self): + try: + prev_warning = self.warning + self._refresh_fan_status() + self._refresh_thermal_status() + except: + self._set_all_fan_speed(FAN_SPEED_MAX) + logging.error("Error occurred while updating fan and thermal status") + return + + if self.fan_failed is True: + self._set_all_fan_speed(FAN_SPEED_MAX) + else: + self._set_all_fan_speed(self._get_fan_speed()) + + if prev_warning != self.warning: + if self.warning is True: + logging.warning('Alarm for temperature high is detected') + else: + logging.info('Alarm for temperature high is cleared') + + if self.shutdown is True: + # critical case*/ + logging.critical( + 'Alarm-Critical for temperature critical is detected, shutdown DUT') + path = I2C_PATH.format('0', '64') + 'pwr_enable_mb' + time.sleep(2) + self._api_helper.write_txt_file(path, 0) + + return + +def main(argv): + global platform_chassis + + # configure logging + try: + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + configure_logging(log_file, log_level) + except: + print("Failed to configure logging") + sys.exit(ERROR_CONFIG_LOGGING) + + # Load platform-specific Chassis class + if not load_platform_chassis(): + sys.exit(ERROR_CHASSIS_LOAD) + + try: + monitor = device_monitor(platform_chassis) + except: + logging.error("Failed to instantiate device_monitor") + sys.exit(ERROR_DEVICE_MONITOR_LOAD) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) # 10sec + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py new file mode 100755 index 000000000000..82e88294069d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py @@ -0,0 +1,379 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import subprocess +import getopt +import sys +import logging +import time +import os + +PROJECT_NAME = 'as4625_54t' +DEBUG = False +ARGS = [] +FORCE = 0 + +def main(): + global DEBUG + global ARGS + global FORCE + + if len(sys.argv) < 2: + return 0 + + (options, ARGS) = getopt.getopt(sys.argv[1:], 'hdf', + ['help','debug', 'force']) + if DEBUG == True: + print(options) + print(ARGS) + print(len(sys.argv)) + + for arg in ARGS: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() + return 0 + +def log_os_system(cmd, show): + logging.info('Run :' + cmd) + status, output = subprocess.getstatusoutput(cmd) + if status: + logging.info('Failed :' + cmd) + if show: + print('Failed :' + cmd) + return (status, output) + +def driver_check(): + ret, lsmod = log_os_system("ls /sys/module/*accton*", 0) + logging.info('mods:'+lsmod) + if ret : + return False + else : + return True + +def new_device(driver, addr, bus, devdir): + if not os.path.exists(os.path.join(bus, devdir)): + try: + with open("%s/new_device" % bus, "w") as f: + f.write("%s 0x%x\n" % (driver, addr)) + f.flush() + except Exception as e: + print("Unexpected error initialize device %s:0x%x:%s: %s" % (driver, addr, bus, e)) + return None + + if not os.path.exists(os.path.join(bus, devdir)): + return False + elif driver.find('pca954') != -1: + if not os.path.exists(os.path.join(bus, devdir, "channel-0")): + delete_device(addr, bus, devdir) + return False + elif os.path.exists(os.path.join(bus, devdir, "idle_state")): + try: + with open(os.path.join(bus, devdir, "idle_state"), "w") as f: + f.write("-2\n") + except Exception as e: + return False + else: + print("Device %s:%x:%s already exists." % (driver, addr, bus)) + return False + + return True + +def delete_device(addr, bus, devdir): + if os.path.exists(os.path.join(bus, devdir)): + try: + with open("%s/delete_device" % bus, "w") as f: + f.write("%s\n" % addr) + f.flush() + except Exception as e: + print("Unexpected error delete device 0x%x:%s: %s" % (addr, bus, e)) + return None + else: + print("Device %x:%s does not exist." % (addr, bus)) + return True + + return True + +def new_i2c_device(driver, addr, bus_number): + bus = '/sys/bus/i2c/devices/i2c-%d' % bus_number + devdir = "%d-%4.4x" % (bus_number, addr) + return new_device(driver, addr, bus, devdir) + +def delete_i2c_device(addr, bus_number): + bus = '/sys/bus/i2c/devices/i2c-%d' % bus_number + devdir = "%d-%4.4x" % (bus_number, addr) + return delete_device(addr, bus, devdir) + +def new_i2c_devices(new_device_list): + for (driver, addr, bus_number) in new_device_list: + for i in range(0, 30): + if new_i2c_device(driver, addr, bus_number) is not True: + time.sleep(1) + continue + else: + break + else: + return False + + return True + +def new_sfp_devices(sfp_bus_list, driver): + for bus_number in sfp_bus_list: + for i in range(0, 30): + if new_i2c_device(driver, 0x50, bus_number) is not True: + time.sleep(1) + continue + else: + break + else: + return False + + return True + +def delete_i2c_devices(delete_device_list): + ret = True + + for (driver, addr, bus_number) in delete_device_list: + if delete_i2c_device(addr, bus_number) is not True: + ret = False + continue + + return ret + +def delete_sfp_devices(sfp_bus_list): + ret = True + + for bus_number in sfp_bus_list: + if delete_i2c_device(0x50, bus_number) is not True: + ret = False + continue + + return ret + +kos = [ + 'depmod -ae', + 'modprobe i2c_dev', + 'modprobe i2c_i801', + 'modprobe i2c_ismt', + 'modprobe i2c_mux_pca954x', + 'modprobe x86-64-accton-as4625-54t-cpld', + 'modprobe x86-64-accton-as4625-54t-fan', + 'modprobe x86-64-accton-as4625-54t-leds', + 'modprobe x86-64-accton-as4625-54t-psu', + 'modprobe optoe', + 'modprobe ym2651y'] + +def driver_install(): + global FORCE + + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in reversed(range(0,len(kos))): + rm = kos[i].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 + +def write_txt_file(file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(value) + except IOError as e: + print("Error write value to file: %s" % str(e)) + return False + return True + +i2c_prefix = '/sys/bus/i2c/devices/' + +i2c_device_list = [ + # initialize multiplexer (PCA9548) + ('pca9548', 0x70, 1), + ('pca9548', 0x71, 1), + + # initialize CPLD + ('as4625_cpld1', 0x64, 0), + + # initiate PSU-1 AC Power + ('as4625_54t_psu1', 0x50, 8), + ('umec_upd150sa', 0x58, 8), + + # initiate PSU-2 AC Power + ('as4625_54t_psu2', 0x51, 9), + ('umec_upd150sa', 0x59, 9), + + # inititate LM75 + ('lm75', 0x4A, 3), + ('lm75', 0x4B, 3), + ('lm75', 0x4D, 3), + ('lm75', 0x4E, 3), + ('lm75', 0x4F, 3), + + # initiate IDPROM + ('24c02', 0x51, 7) +] + +sfp_bus_list = [ 10, 11, 12, 13, 14, 15 ] + +def device_install(): + global FORCE + + if new_i2c_devices(i2c_device_list) is not True: + return 1 + + if new_sfp_devices(sfp_bus_list, 'optoe2') is not True: + return 1 + + for p in range(len(sfp_bus_list)): + path = "/sys/bus/i2c/devices/{0}-0050/port_name".format(sfp_bus_list[p]) + if write_txt_file(path, 'port{0}'.format(p+49)) is not True: + return 1 + + return + +def device_uninstall(): + global FORCE + + if delete_sfp_devices(sfp_bus_list) is not True: + return 1 + + if delete_i2c_devices(i2c_device_list[::-1]) is not True: + return 1 + + return + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + + #Check API2.0 on py whl file + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = log_os_system("pip3 install "+ SONIC_PLATFORM_BSP_WHL_PKG_PY3, 1) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + +def do_sonic_platform_clean(): + status, output = log_os_system("pip3 show sonic-platform > /dev/null 2>&1", 0) + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = log_os_system("pip3 uninstall sonic-platform -y", 0) + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + return + +def do_install(): + print('Checking system....') + if driver_check() is False: + print('No driver, installing....') + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' drivers detected....') + if not device_exist(): + print('No device, installing....') + status = device_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' devices detected....') + + do_sonic_platform_install() + + return + +def do_uninstall(): + print('Checking system....') + if not device_exist(): + print(PROJECT_NAME.upper() + ' has no device installed....') + else: + print('Removing device....') + status = device_uninstall() + if status and FORCE == 0: + return status + + if driver_check() is False: + print(PROJECT_NAME.upper() + ' has no driver installed....') + else: + print('Removing installed driver....') + status = driver_uninstall() + if status and FORCE == 0: + return status + + do_sonic_platform_clean() + + return None + +def device_exist(): + ret1 = log_os_system('ls ' + i2c_prefix + '*0070', 0) + ret2 = log_os_system('ls ' + i2c_prefix + 'i2c-2', 0) + return not (ret1[0] or ret2[0]) + +if __name__ == '__main__': + main() 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 20cef5d61a38..66e7ad118658 100755 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c @@ -43,7 +43,9 @@ enum chips { YM2401, YM2851, YM1401A, - YPEB1200AM + YPEB1200AM, + UMEC_UPD150SA, + UMEC_UP1K21R }; /* Each client has this additional data @@ -62,7 +64,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 */ @@ -112,6 +114,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, @@ -141,6 +145,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); @@ -164,8 +170,12 @@ 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 +187,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, @@ -199,8 +211,12 @@ static struct attribute *ym2651y_attributes[] = { &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 }; @@ -293,7 +309,9 @@ static ssize_t show_linear(struct device *dev, struct device_attribute *da, value = data->p_out; break; case PSU_TEMP1_INPUT: - value = data->temp; + case PSU_TEMP2_INPUT: + case PSU_TEMP3_INPUT: + value = data->temp_input[attr->index - PSU_TEMP1_INPUT]; break; case PSU_FAN1_SPEED: value = data->fan_speed; @@ -506,6 +524,8 @@ static const struct i2c_device_id ym2651y_id[] = { { "ym2851", YM2851 }, { "ym1401a",YM1401A}, { "ype1200am", YPEB1200AM }, + { "umec_upd150sa", UMEC_UPD150SA }, + { "umec_up1k21r", UMEC_UP1K21R }, {} }; MODULE_DEVICE_TABLE(i2c, ym2651y_id); @@ -586,7 +606,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}, @@ -620,10 +642,18 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) /* Read word data */ for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + /* 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 (data->chip != UMEC_UPD150SA && + data->chip != UMEC_UP1K21R) { + continue; + } + } status = ym2651y_read_word(client, regs_word[i].reg); - if (status < 0) - { + if (status < 0) { dev_dbg(&client->dev, "reg %d, err %d\n", regs_word[i].reg, status); *(regs_word[i].value) = 0; @@ -667,7 +697,7 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) status = ym2651y_read_block(client, command, data->mfr_model, buf+1); if ((buf+1) >= (ARRAY_SIZE(data->mfr_model)-1)) - { + { data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; } else diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index 4410a2f07796..1d9f3c85cf9e 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -84,3 +84,11 @@ Description: kernel modules for platform devices such as fan, led, sfp Package: sonic-platform-accton-as7315-27xb Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-accton-as4625-54p +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-accton-as4625-54t +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index 8cd7611bb6e3..c47aa3b3e672 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -22,6 +22,7 @@ MOD_SRC_DIR:= $(shell pwd) MODULE_DIRS := as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x MODULE_DIRS += as7326-56x as6712-32x as7726-32x as4630-54pe as4630-54te minipack as5812-54x MODULE_DIRS += as5835-54x as9716-32d as9726-32d as5835-54t as7312-54xs as7315-27xb as5812-54t +MODULE_DIRS += as4625-54p as4625-54t MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54p.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54p.install new file mode 100644 index 000000000000..77cc3234f2f9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54p.install @@ -0,0 +1 @@ +as4625-54p/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4625_54p-r0 diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54t.install b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54t.install new file mode 100644 index 000000000000..811c0f4cfbca --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4625-54t.install @@ -0,0 +1 @@ +as4625-54t/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as4625_54t-r0 From 58fd8d0cdf2345e9a701d9d99dd5d7c4bd8642f1 Mon Sep 17 00:00:00 2001 From: roger530-ho Date: Mon, 14 Aug 2023 07:25:21 +0000 Subject: [PATCH 2/6] Read the data when the PSU is in the power-good state. --- .../x86_64-accton_as4625_54p-r0/sonic_platform/psu.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py index 08ca93625469..28c021a613bf 100644 --- a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/psu.py @@ -80,7 +80,7 @@ def get_voltage(self): e.g. 12.1 """ if self.get_status() is not True: - return None + return 0 vout_path = "{}{}".format(self.pmbus_path, 'psu_v_out') vout_val=self._api_helper.read_txt_file(vout_path) @@ -96,7 +96,7 @@ def get_current(self): A float number, the electric current in amperes, e.g 15.4 """ if self.get_status() is not True: - return None + return 0 iout_path = "{}{}".format(self.pmbus_path, 'psu_i_out') val = self._api_helper.read_txt_file(iout_path) @@ -112,7 +112,7 @@ def get_power(self): A float number, the power in watts, e.g. 302.6 """ if self.get_status() is not True: - return None + return 0 pout_path = "{}{}".format(self.pmbus_path, 'psu_p_out') val = self._api_helper.read_txt_file(pout_path) From 8f3ab89be8b477cd9175f9a7623fa6c4b4e027e1 Mon Sep 17 00:00:00 2001 From: roger530-ho Date: Tue, 15 Aug 2023 06:51:20 +0000 Subject: [PATCH 3/6] [Edgecore][as4625-54p/54t] Fixed Semgrep check error. --- .../modules/x86-64-accton-as4625-54p-psu.c | 14 ++++++++++++++ .../modules/x86-64-accton-as4625-54t-psu.c | 14 ++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c index 3592a31fda29..1dccbb263258 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c @@ -33,6 +33,8 @@ #include #include #include +#define __STDC_WANT_LIB_EXT1__ 1 +#include #define DRVNAME "as4625_54p_psu" @@ -328,9 +330,21 @@ static struct as4625_54p_psu_data *as4625_54p_psu_update_device(struct device *d data->status = status; } + #ifdef __STDC_LIB_EXT1__ + memset_s(data->model_name, sizeof(data->model_name), 0, sizeof(data->model_name)); + #else memset(data->model_name, 0, sizeof(data->model_name)); + #endif + #ifdef __STDC_LIB_EXT1__ + memset_s(data->serial, sizeof(data->serial), 0, sizeof(data->serial)); + #else memset(data->serial, 0, sizeof(data->serial)); + #endif + #ifdef __STDC_LIB_EXT1__ + memset_s(data->fan_dir, sizeof(data->fan_dir), 0, sizeof(data->fan_dir)); + #else memset(data->fan_dir, 0, sizeof(data->fan_dir)); + #endif if (IS_POWER_GOOD(data->index, data->status)) { /* Read model name */ diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c index 63f7eb80c061..fa2f74f8a452 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c @@ -33,6 +33,8 @@ #include #include #include +#define __STDC_WANT_LIB_EXT1__ 1 +#include #define DRVNAME "as4625_54t_psu" @@ -328,9 +330,21 @@ static struct as4625_54t_psu_data *as4625_54t_psu_update_device(struct device *d data->status = status; } + #ifdef __STDC_LIB_EXT1__ + memset_s(data->model_name, sizeof(data->model_name), 0, sizeof(data->model_name)); + #else memset(data->model_name, 0, sizeof(data->model_name)); + #endif + #ifdef __STDC_LIB_EXT1__ + memset_s(data->serial, sizeof(data->serial), 0, sizeof(data->serial)); + #else memset(data->serial, 0, sizeof(data->serial)); + #endif + #ifdef __STDC_LIB_EXT1__ + memset_s(data->fan_dir, sizeof(data->fan_dir), 0, sizeof(data->fan_dir)); + #else memset(data->fan_dir, 0, sizeof(data->fan_dir)); + #endif if (IS_POWER_GOOD(data->index, data->status)) { /* Read model name */ From d9ecc707d8b7b3b9ad7a7fdc1bee70a69dbc16a0 Mon Sep 17 00:00:00 2001 From: roger530-ho Date: Tue, 29 Aug 2023 06:47:46 +0000 Subject: [PATCH 4/6] [Edgecore][as4625-54p/54t] Turn off LOC LED by default. --- .../utils/accton_as4625_54p_util.py | 23 +++++++++++++++++++ .../utils/accton_as4625_54t_util.py | 23 +++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py index 22d5a66615d7..e79e3c75a0e6 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_util.py @@ -41,6 +41,9 @@ DEBUG = False ARGS = [] FORCE = 0 +LED_MODE_OFF = 0 +LED_MODE_GREEN = 1 # Default value for LOC LED +LED_LOC_PATH = "/sys/class/leds/as4625_led::loc/brightness" def main(): global DEBUG @@ -325,6 +328,24 @@ def do_sonic_platform_clean(): return +def set_loc_led(color): + global FORCE + + if os.path.exists(LED_LOC_PATH): + cmd = 'echo {} > {}'.format(color, LED_LOC_PATH) + try: + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + except Exception as e: + print({}.format(e)) + else: + print('{} does not exist.'.format(LED_LOC_PATH)) + + return + def do_install(): print('Checking system....') if driver_check() is False: @@ -344,6 +365,8 @@ def do_install(): else: print(PROJECT_NAME.upper() + ' devices detected....') + set_loc_led(LED_MODE_OFF) + do_sonic_platform_install() return diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py index 82e88294069d..8ed54983a1c8 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_util.py @@ -41,6 +41,9 @@ DEBUG = False ARGS = [] FORCE = 0 +LED_MODE_OFF = 0 +LED_MODE_GREEN = 1 # Default value for LOC LED +LED_LOC_PATH = "/sys/class/leds/as4625_led::loc/brightness" def main(): global DEBUG @@ -325,6 +328,24 @@ def do_sonic_platform_clean(): return +def set_loc_led(color): + global FORCE + + if os.path.exists(LED_LOC_PATH): + cmd = 'echo {} > {}'.format(color, LED_LOC_PATH) + try: + status, output = log_os_system(cmd, 1) + if status: + print(output) + if FORCE == 0: + return status + except Exception as e: + print({}.format(e)) + else: + print('{} does not exist.'.format(LED_LOC_PATH)) + + return + def do_install(): print('Checking system....') if driver_check() is False: @@ -344,6 +365,8 @@ def do_install(): else: print(PROJECT_NAME.upper() + ' devices detected....') + set_loc_led(LED_MODE_OFF) + do_sonic_platform_install() return From 60d2af261b00d1df7ffe7aee74565dc90c87d741 Mon Sep 17 00:00:00 2001 From: Brandon Chuang Date: Mon, 2 Oct 2023 14:36:16 +0800 Subject: [PATCH 5/6] [Edgecore][as4625-54p/54t] Add thermal_shutdown feature into thermal policy Signed-off-by: Brandon Chuang --- .../modules/x86-64-accton-as4625-54p-cpld.c | 11 +++++++++++ .../as4625-54p/utils/accton_as4625_54p_monitor.py | 6 ++++++ .../as4625-54t/utils/accton_as4625_54t_monitor.py | 6 ++++++ 3 files changed, 23 insertions(+) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c index 5c5ff42b2d92..71e43a979e2d 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c @@ -73,6 +73,7 @@ enum as4625_cpld_sysfs_attributes { PCB_VERSION, POWER_ENABLE_MAINBOARD, POWER_ENABLE_POE, + SYSTEM_THERMAL_SHUTDOWN, ACCESS, /* transceiver attributes */ TRANSCEIVER_PRESENT_ATTR_ID(49), @@ -132,6 +133,7 @@ static SENSOR_DEVICE_ATTR(pcb_id, S_IRUGO, show_version, NULL, PCB_ID); static SENSOR_DEVICE_ATTR(pcb_version, S_IRUGO, show_version, NULL, PCB_VERSION); static SENSOR_DEVICE_ATTR(pwr_enable_mb, S_IRUGO | S_IWUSR, show_status, set_control, POWER_ENABLE_MAINBOARD); static SENSOR_DEVICE_ATTR(pwr_enable_poe, S_IRUGO | S_IWUSR, show_status, set_control, POWER_ENABLE_POE); +static SENSOR_DEVICE_ATTR(thermal_shutdown, S_IRUGO | S_IWUSR, show_status, set_control, SYSTEM_THERMAL_SHUTDOWN); static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); /* transceiver attributes */ @@ -149,6 +151,7 @@ static struct attribute *as4625_cpld1_attributes[] = { &sensor_dev_attr_pcb_version.dev_attr.attr, &sensor_dev_attr_pwr_enable_mb.dev_attr.attr, &sensor_dev_attr_pwr_enable_poe.dev_attr.attr, + &sensor_dev_attr_thermal_shutdown.dev_attr.attr, &sensor_dev_attr_access.dev_attr.attr, /* transceiver attributes */ DECLARE_SFP_TRANSCEIVER_ATTR(49), @@ -200,6 +203,10 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, reg = 0x21; mask = 0x1; break; + case SYSTEM_THERMAL_SHUTDOWN: + reg = 0x27; + mask = 0x1; + break; default: return 0; } @@ -247,6 +254,10 @@ static ssize_t set_control(struct device *dev, struct device_attribute *da, reg = 0x21; mask = 0x1; break; + case SYSTEM_THERMAL_SHUTDOWN: + reg = 0x27; + mask = 0x1; + break; default: return -EINVAL; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py index 5899acee1b8f..77e82efd3d1d 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/utils/accton_as4625_54p_monitor.py @@ -236,6 +236,12 @@ def manage_fans(self): path = I2C_PATH.format('0', '64') + 'pwr_enable_poe' self._api_helper.write_txt_file(path, 0) + logging.critical( + 'Alarm-Critical for temperature critical is detected, trigger thermal shutdown') + path = I2C_PATH.format('0', '64') + 'thermal_shutdown' + time.sleep(2) + self._api_helper.write_txt_file(path, 1) + logging.critical( 'Alarm-Critical for temperature critical is detected, shutdown DUT') path = I2C_PATH.format('0', '64') + 'pwr_enable_mb' diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py index ab479a759597..bf40091d8a03 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/utils/accton_as4625_54t_monitor.py @@ -268,6 +268,12 @@ def manage_fans(self): if self.shutdown is True: # critical case*/ + logging.critical( + 'Alarm-Critical for temperature critical is detected, trigger thermal shutdown') + path = I2C_PATH.format('0', '64') + 'thermal_shutdown' + time.sleep(2) + self._api_helper.write_txt_file(path, 1) + logging.critical( 'Alarm-Critical for temperature critical is detected, shutdown DUT') path = I2C_PATH.format('0', '64') + 'pwr_enable_mb' From ce4a8ff6dffc0b17695305861494b833cebe2946 Mon Sep 17 00:00:00 2001 From: Brandon Chuang Date: Wed, 14 Aug 2024 16:16:49 +0800 Subject: [PATCH 6/6] [Edgecore][as4625-54p/54t] Support kernel 6.1 and bookworm Signed-off-by: Brandon Chuang --- .../sonic_platform/helper.py | 7 ------ .../modules/x86-64-accton-as4625-54p-cpld.c | 3 +-- .../modules/x86-64-accton-as4625-54p-fan.c | 23 ++++--------------- .../modules/x86-64-accton-as4625-54p-psu.c | 19 +-------------- .../modules/x86-64-accton-as4625-54t-psu.c | 19 +-------------- .../common/modules/ym2651y.c | 10 +++++--- 6 files changed, 15 insertions(+), 66 deletions(-) diff --git a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py index 28e01d6e458c..2784092d0ce6 100644 --- a/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py +++ b/device/accton/x86_64-accton_as4625_54p-r0/sonic_platform/helper.py @@ -37,13 +37,6 @@ def pci_get_value(self, resource, offset): 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, encoding='unicode_escape', errors='replace') as fd: diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c index 71e43a979e2d..1578f9af2fcb 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-cpld.c @@ -445,7 +445,7 @@ static int as4625_cpld_probe(struct i2c_client *client, return ret; } -static int as4625_cpld_remove(struct i2c_client *client) +static void as4625_cpld_remove(struct i2c_client *client) { struct as4625_cpld_data *data = i2c_get_clientdata(client); const struct attribute_group *group = NULL; @@ -466,7 +466,6 @@ static int as4625_cpld_remove(struct i2c_client *client) } kfree(data); - return 0; } static int as4625_cpld_read_internal(struct i2c_client *client, u8 reg) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c index 7bc0d5b8388f..900b962f44df 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-fan.c @@ -146,7 +146,7 @@ DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(1); DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(2); DECLARE_FAN_TARGET_RPM_SENSOR_DEV_ATTR(3); -static struct attribute *as4625_fan_attributes[] = { +static struct attribute *as4625_fan_attrs[] = { /* fan related attributes */ DECLARE_FAN_FAULT_ATTR(1), DECLARE_FAN_FAULT_ATTR(2), @@ -166,6 +166,8 @@ static struct attribute *as4625_fan_attributes[] = { NULL }; +ATTRIBUTE_GROUPS(as4625_fan); + #define FAN_DUTY_CYCLE_REG_MASK 0x0F #define FAN_MAX_DUTY_CYCLE 100 #define FAN_REG_VAL_TO_SPEED_RPM_STEP 150 @@ -292,10 +294,6 @@ static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, return ret; } -static const struct attribute_group as4625_fan_group = { - .attrs = as4625_fan_attributes, -}; - static struct as4625_fan_data *as4625_fan_update_device(struct device *dev) { if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || @@ -332,30 +330,19 @@ static int as4625_fan_probe(struct platform_device *pdev) { int status; - data->hwmon_dev = hwmon_device_register_with_info(&pdev->dev, - DRVNAME, NULL, NULL, NULL); + data->hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev, + DRVNAME, data, as4625_fan_groups); if (IS_ERR(data->hwmon_dev)) { status = PTR_ERR(data->hwmon_dev); return status; } - /* Register sysfs hooks */ - status = sysfs_create_group(&data->hwmon_dev->kobj, &as4625_fan_group); - if (status) - goto exit_remove; - dev_info(&pdev->dev, "device created\n"); return 0; - -exit_remove: - hwmon_device_unregister(data->hwmon_dev); - return status; } static int as4625_fan_remove(struct platform_device *pdev) { - sysfs_remove_group(&data->hwmon_dev->kobj, &as4625_fan_group); - hwmon_device_unregister(data->hwmon_dev); return 0; } diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c index 1dccbb263258..7d83c62a14e0 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54p/modules/x86-64-accton-as4625-54p-psu.c @@ -65,7 +65,6 @@ static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /* Each client has this additional data */ struct as4625_54p_psu_data { - struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if registers are valid */ unsigned long last_updated; /* In jiffies */ @@ -203,35 +202,19 @@ static int as4625_54p_psu_probe(struct i2c_client *client, goto exit_free; } - data->hwmon_dev = hwmon_device_register_with_info(&client->dev, - DRVNAME, NULL, NULL, NULL); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - dev_info(&client->dev, "%s: psu '%s'\n", - dev_name(data->hwmon_dev), client->name); - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &as4625_54p_psu_group); exit_free: kfree(data); exit: return status; } -static int as4625_54p_psu_remove(struct i2c_client *client) +static void as4625_54p_psu_remove(struct i2c_client *client) { struct as4625_54p_psu_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &as4625_54p_psu_group); kfree(data); - - return 0; } enum psu_index diff --git a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c index fa2f74f8a452..ccf09d945b88 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4625-54t/modules/x86-64-accton-as4625-54t-psu.c @@ -65,7 +65,6 @@ static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; /* Each client has this additional data */ struct as4625_54t_psu_data { - struct device *hwmon_dev; struct mutex update_lock; char valid; /* !=0 if registers are valid */ unsigned long last_updated; /* In jiffies */ @@ -203,35 +202,19 @@ static int as4625_54t_psu_probe(struct i2c_client *client, goto exit_free; } - data->hwmon_dev = hwmon_device_register_with_info(&client->dev, - DRVNAME, NULL, NULL, NULL); - if (IS_ERR(data->hwmon_dev)) { - status = PTR_ERR(data->hwmon_dev); - goto exit_remove; - } - - dev_info(&client->dev, "%s: psu '%s'\n", - dev_name(data->hwmon_dev), client->name); - return 0; - -exit_remove: - sysfs_remove_group(&client->dev.kobj, &as4625_54t_psu_group); exit_free: kfree(data); exit: return status; } -static int as4625_54t_psu_remove(struct i2c_client *client) +static void as4625_54t_psu_remove(struct i2c_client *client) { struct as4625_54t_psu_data *data = i2c_get_clientdata(client); - hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &as4625_54t_psu_group); kfree(data); - - return 0; } enum psu_index 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 cde189b12823..7e2bff0d1e8a 100755 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c @@ -32,6 +32,9 @@ #include #include +#define __STDC_WANT_LIB_EXT1__ 1 +#include + #define MAX_FAN_DUTY_CYCLE 100 /* Addresses scanned @@ -514,7 +517,6 @@ static void ym2651y_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ym2651y_group); kfree(data); - } static const struct i2c_device_id ym2651y_id[] = { @@ -672,7 +674,11 @@ static struct ym2651y_data *ym2651y_update_device(struct device *dev) goto exit; } + #ifdef __STDC_LIB_EXT1__ + strncpy_s(data->fan_dir, sizeof(data->fan_dir), fan_dir + 1, ARRAY_SIZE(data->fan_dir) - 1); + else strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); + #endif data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; /* Read mfr_id */ @@ -769,5 +775,3 @@ module_i2c_driver(ym2651y_driver); MODULE_AUTHOR("Brandon Chuang "); MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); MODULE_LICENSE("GPL"); - -