diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hwsku.json b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hwsku.json new file mode 100755 index 00000000000..faf0aac0921 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hwsku.json @@ -0,0 +1,315 @@ +{ + "interfaces": { + "Ethernet0": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet1": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet2": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet3": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet4": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet5": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet6": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet7": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet8": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet9": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet10": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet11": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet12": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet13": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet14": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet15": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet16": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet17": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet18": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet19": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet20": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet21": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet22": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet23": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet24": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet25": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet26": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet27": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet28": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet29": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet30": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet31": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet32": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet33": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet34": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet35": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet36": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet37": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet38": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet39": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet40": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet41": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet42": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet43": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet44": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet45": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet46": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet47": { + "default_brkout_mode": "1x1G", + "autoneg": "on", + "port_type": "RJ45" + }, + + "Ethernet48": { + "default_brkout_mode": "1x25G[10G]" + }, + + "Ethernet49": { + "default_brkout_mode": "1x25G[10G]" + }, + + "Ethernet50": { + "default_brkout_mode": "1x25G[10G]" + }, + + "Ethernet51": { + "default_brkout_mode": "1x25G[10G]" + }, + + "Ethernet52": { + "default_brkout_mode": "1x100G[40G]" + }, + + "Ethernet56": { + "default_brkout_mode": "1x100G[40G]" + } + } +} diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm index a5e7903abf2..f4e22dcae6e 100755 --- a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/hx5-as4630-48x1G+4x25G+2x100G.bcm @@ -1,4 +1,4 @@ -stable_size=76303168 +stable_size=0x5500000 #polarity/lanemap is using TH2 style. core_clock_frequency=893 @@ -27,7 +27,19 @@ ifp_inports_support_enable=1 #3x PM4x10Q (3 * 16 = 48 physical ports) #Doesn't support oversubscribe in Q mode #MCQ0 -port_gmii_mode_1=1 #Q mode +port_gmii_mode_1=1 #Q mode + +#riot vxlan +#dport_map_direct=1 +flow_init_mode=1 +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=8192 +l3_ecmp_levels=2 +riot_overlay_ecmp_resilient_hash_size=16384 +use_all_splithorizon_groups=1 +host_as_route_disable=1 +max_vp_lags=448 #PHY4 U56 xx1, MDC/MDIO2, PHYADDR:0x00-0x07, 0x08 port_phy_addr_1=0x40 diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini index 6c57150cdc2..c35b5bcf6d5 100755 --- a/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini +++ b/device/accton/x86_64-accton_as4630_54pe-r0/Accton-AS4630-54PE/port_config.ini @@ -1,55 +1,55 @@ # name lanes alias index speed autoneg -Ethernet0 26 thousandE1 1 1000 on -Ethernet1 25 thousandE2 2 1000 on -Ethernet2 28 thousandE3 3 1000 on -Ethernet3 27 thousandE4 4 1000 on -Ethernet4 30 thousandE5 5 1000 on -Ethernet5 29 thousandE6 6 1000 on -Ethernet6 32 thousandE7 7 1000 on -Ethernet7 31 thousandE8 8 1000 on -Ethernet8 38 thousandE9 9 1000 on -Ethernet9 37 thousandE10 10 1000 on -Ethernet10 40 thousandE11 11 1000 on -Ethernet11 39 thousandE12 12 1000 on -Ethernet12 34 thousandE13 13 1000 on -Ethernet13 33 thousandE14 14 1000 on -Ethernet14 36 thousandE15 15 1000 on -Ethernet15 35 thousandE16 16 1000 on -Ethernet16 46 thousandE17 17 1000 on -Ethernet17 45 thousandE18 18 1000 on -Ethernet18 48 thousandE19 19 1000 on -Ethernet19 47 thousandE20 20 1000 on -Ethernet20 42 thousandE21 21 1000 on -Ethernet21 41 thousandE22 22 1000 on -Ethernet22 44 thousandE23 23 1000 on -Ethernet23 43 thousandE24 24 1000 on -Ethernet24 2 thousandE25 25 1000 on -Ethernet25 1 thousandE26 26 1000 on -Ethernet26 4 thousandE27 27 1000 on -Ethernet27 3 thousandE28 28 1000 on -Ethernet28 6 thousandE29 29 1000 on -Ethernet29 5 thousandE30 30 1000 on -Ethernet30 8 thousandE31 31 1000 on -Ethernet31 7 thousandE32 32 1000 on -Ethernet32 10 thousandE33 33 1000 on -Ethernet33 9 thousandE34 34 1000 on -Ethernet34 12 thousandE35 35 1000 on -Ethernet35 11 thousandE36 36 1000 on -Ethernet36 14 thousandE37 37 1000 on -Ethernet37 13 thousandE38 38 1000 on -Ethernet38 16 thousandE39 39 1000 on -Ethernet39 15 thousandE40 40 1000 on -Ethernet40 18 thousandE41 41 1000 on -Ethernet41 17 thousandE42 42 1000 on -Ethernet42 20 thousandE43 43 1000 on -Ethernet43 19 thousandE44 44 1000 on -Ethernet44 22 thousandE45 45 1000 on -Ethernet45 21 thousandE46 46 1000 on -Ethernet46 24 thousandE47 47 1000 on -Ethernet47 23 thousandE48 48 1000 on -Ethernet48 67 twentyfiveGigE49 49 25000 off -Ethernet49 66 twentyfiveGigE50 50 25000 off -Ethernet50 65 twentyfiveGigE51 51 25000 off -Ethernet51 68 twentyfiveGigE52 52 25000 off -Ethernet52 73,74,75,76 hundredGigE53 53 100000 off -Ethernet56 69,70,71,72 hundredGigE54 54 100000 off +Ethernet0 26 Eth1(Port1) 1 1000 on +Ethernet1 25 Eth2(Port2) 2 1000 on +Ethernet2 28 Eth3(Port3) 3 1000 on +Ethernet3 27 Eth4(Port4) 4 1000 on +Ethernet4 30 Eth5(Port5) 5 1000 on +Ethernet5 29 Eth6(Port6) 6 1000 on +Ethernet6 32 Eth7(Port7) 7 1000 on +Ethernet7 31 Eth8(Port8) 8 1000 on +Ethernet8 38 Eth9(Port9) 9 1000 on +Ethernet9 37 Eth10(Port10) 10 1000 on +Ethernet10 40 Eth11(Port11) 11 1000 on +Ethernet11 39 Eth12(Port12) 12 1000 on +Ethernet12 34 Eth13(Port13) 13 1000 on +Ethernet13 33 Eth14(Port14) 14 1000 on +Ethernet14 36 Eth15(Port15) 15 1000 on +Ethernet15 35 Eth16(Port16) 16 1000 on +Ethernet16 46 Eth17(Port17) 17 1000 on +Ethernet17 45 Eth18(Port18) 18 1000 on +Ethernet18 48 Eth19(Port19) 19 1000 on +Ethernet19 47 Eth20(Port20) 20 1000 on +Ethernet20 42 Eth21(Port21) 21 1000 on +Ethernet21 41 Eth22(Port22) 22 1000 on +Ethernet22 44 Eth23(Port23) 23 1000 on +Ethernet23 43 Eth24(Port24) 24 1000 on +Ethernet24 2 Eth25(Port25) 25 1000 on +Ethernet25 1 Eth26(Port26) 26 1000 on +Ethernet26 4 Eth27(Port27) 27 1000 on +Ethernet27 3 Eth28(Port28) 28 1000 on +Ethernet28 6 Eth29(Port29) 29 1000 on +Ethernet29 5 Eth30(Port30) 30 1000 on +Ethernet30 8 Eth31(Port31) 31 1000 on +Ethernet31 7 Eth32(Port32) 32 1000 on +Ethernet32 10 Eth33(Port33) 33 1000 on +Ethernet33 9 Eth34(Port34) 34 1000 on +Ethernet34 12 Eth35(Port35) 35 1000 on +Ethernet35 11 Eth36(Port36) 36 1000 on +Ethernet36 14 Eth37(Port37) 37 1000 on +Ethernet37 13 Eth38(Port38) 38 1000 on +Ethernet38 16 Eth39(Port39) 39 1000 on +Ethernet39 15 Eth40(Port40) 40 1000 on +Ethernet40 18 Eth41(Port41) 41 1000 on +Ethernet41 17 Eth42(Port42) 42 1000 on +Ethernet42 20 Eth43(Port43) 43 1000 on +Ethernet43 19 Eth44(Port44) 44 1000 on +Ethernet44 22 Eth45(Port45) 45 1000 on +Ethernet45 21 Eth46(Port46) 46 1000 on +Ethernet46 24 Eth47(Port47) 47 1000 on +Ethernet47 23 Eth48(Port48) 48 1000 on +Ethernet48 67 Eth49(Port49) 49 25000 off +Ethernet49 66 Eth50(Port50) 50 25000 off +Ethernet50 65 Eth51(Port51) 51 25000 off +Ethernet51 68 Eth52(Port52) 52 25000 off +Ethernet52 73,74,75,76 Eth53(Port53) 53 100000 off +Ethernet56 69,70,71,72 Eth54(Port54) 54 100000 off diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf b/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf index 735fa7992db..85bb317cc90 100755 --- a/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf +++ b/device/accton/x86_64-accton_as4630_54pe-r0/installer.conf @@ -1,4 +1,4 @@ CONSOLE_PORT=0x3f8 CONSOLE_DEV=0 CONSOLE_SPEED=115200 -ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="intel_iommu=off modprobe.blacklist=i2c-ismt,i2c_ismt,i2c-i801,i2c_i801" +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_as4630_54pe-r0/pcie.yaml b/device/accton/x86_64-accton_as4630_54pe-r0/pcie.yaml new file mode 100644 index 00000000000..c7e99c8678d --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pcie.yaml @@ -0,0 +1,167 @@ +- 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: 0b + fn: '0' + id: 19a6 + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #2 (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: '10' + fn: '0' + id: 19aa + name: 'PCI bridge: Intel Corporation Atom Processor C3000 Series PCI Express Root + Port #6 (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: '13' + fn: '0' + id: 19b2 + name: 'SATA controller: Intel Corporation Atom Processor C3000 Series SATA Controller + 0 (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: 1a + fn: '0' + id: 19d8 + name: 'Serial controller: Intel Corporation Atom Processor C3000 Series HSUART Controller + (rev 11)' +- bus: '00' + dev: 1a + fn: '1' + id: 19d8 + name: 'Serial controller: Intel Corporation Atom Processor C3000 Series HSUART Controller + (rev 11)' +- bus: '00' + dev: 1a + fn: '2' + id: 19d8 + name: 'Serial controller: Intel Corporation Atom Processor C3000 Series HSUART Controller + (rev 11)' +- bus: '00' + dev: 1c + fn: '0' + id: 19db + name: 'SD Host controller: Intel Corporation Device 19db (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: '05' + dev: '00' + fn: '0' + id: b371 + name: 'Ethernet controller: Broadcom Inc. and subsidiaries BCM56371 Switch ASIC + (rev 03)' +- bus: '06' + dev: '00' + fn: '0' + id: 15c2 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: '06' + dev: '00' + fn: '1' + id: 15c2 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 Backplane + (rev 11)' +- bus: 08 + dev: '00' + fn: '0' + id: 15e5 + name: 'Ethernet controller: Intel Corporation Ethernet Connection X553 1GbE (rev + 11)' diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json index 0abf66aab7a..77dfdc82765 100644 --- a/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pd-plugin.json @@ -33,11 +33,11 @@ { "i2c": { - "valmap": { "F2B":"EXHAUST", "B2F":"INTAKE" } + "valmap": { "F2B":"exhaust", "B2F":"intake" } } }, - "PSU_FAN_MAX_SPEED":"18000" + "PSU_FAN_MAX_SPEED":"26688" }, "FAN": @@ -46,7 +46,7 @@ { "i2c": { - "valmap": {"1":"EXHAUST", "0":"INTAKE"} + "valmap": {"1":"exhaust", "0":"intake"} } }, diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json index 34013b2a84a..84a9345b19c 100644 --- a/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pddf/pddf-device.json @@ -5,7 +5,7 @@ "num_fantrays":3, "num_fans_pertray":1, "num_ports":54, - "num_temps": 3, + "num_temps": 8, "pddf_dev_types": { "description":"AS4630 - Below is the list of supported PDDF device types (chip names) for various components. If any component uses some other driver, we will create the client using 'echo > /new_device' method", @@ -56,6 +56,10 @@ "pddf_fan_driver_module", "pddf_fan_module", "pddf_led_module" + ], + "custom_kos": + [ + "pddf_custom_psu" ] }, @@ -135,7 +139,7 @@ "TEMP1" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_parent":"MUX2"}, - "dev_attr": { "display_name":"Temp_1"}, + "dev_attr": { "display_name":"MB_temp(0x48)"}, "i2c": { "topo_info": { "parent_bus":"0xe", "dev_addr":"0x48", "dev_type":"lm77"}, @@ -180,7 +184,7 @@ "TEMP2" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_parent":"MUX3"}, - "dev_attr": { "display_name":"Temp_CPU"}, + "dev_attr": { "display_name":"CB_temp(0x4B)"}, "i2c": { @@ -198,7 +202,7 @@ "TEMP3" : { "dev_info": { "device_type":"TEMP_SENSOR", "device_parent":"MUX3"}, - "dev_attr": { "display_name":"Temp_Fan"}, + "dev_attr": { "display_name":"FB_temp(0x4A)"}, "i2c": { "topo_info": { "parent_bus":"0x19", "dev_addr":"0x4a", "dev_type":"lm75"}, @@ -211,6 +215,85 @@ } }, + "TEMP4" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP4"}, + "dev_attr": { "display_name":"CPU_Package_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon1"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp1_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp1_max"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP5" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP5"}, + "dev_attr": { "display_name":"CPU_Core_0_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon1"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp4_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp4_max"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP6" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP6"}, + "dev_attr": { "display_name":"CPU_Core_1_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon1"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp8_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp8_max"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP7" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP7"}, + "dev_attr": { "display_name":"CPU_Core_2_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon1"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp10_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp10_max"}, + { "attr_name": "temp1_input"} + ] + } + }, + + "TEMP8" : + { + "dev_info": { "device_type":"TEMP_SENSOR", "device_name":"TEMP8"}, + "dev_attr": { "display_name":"CPU_Core_3_temp"}, + "i2c": + { + "path_info": {"sysfs_base_path": "/sys/class/hwmon/hwmon1"}, + "attr_list": + [ + { "attr_name": "temp1_high_crit_threshold", "drv_attr_name":"temp14_crit"}, + { "attr_name": "temp1_high_threshold", "drv_attr_name":"temp14_max"}, + { "attr_name": "temp1_input"} + ] + } + }, "CPLD1": { @@ -251,15 +334,15 @@ "SYS_LED": { "dev_info": { "device_type":"LED", "device_name":"SYS_LED"}, - "dev_attr": { "index":"0"}, + "dev_attr": { "index":"0", "flag": "rw"}, "i2c" : { "attr_list": [ - {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "7:5", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, - {"attr_name":"STATUS_LED_COLOR_GREEN_BLINK", "bits" : "7:5", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, - {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "7:5", "descr" : "", "value" : "0x4", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, - {"attr_name":"STATUS_LED_COLOR_AMBER_BLINK", "bits" : "7:5", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, - {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "7:5", "descr" : "", "value" : "0x7", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"} + {"attr_name":"green", "bits" : "7:5", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"green_blink", "bits" : "7:5", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"amber", "bits" : "7:5", "descr" : "", "value" : "0x4", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"amber_blink", "bits" : "7:5", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"off", "bits" : "7:5", "descr" : "", "value" : "0x7", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"} ] } }, @@ -268,13 +351,13 @@ "PSU1_LED": { "dev_info": { "device_type":"LED", "device_name":"PSU_LED"}, - "dev_attr": { "index":"0"}, + "dev_attr": { "index":"0", "flag": "r"}, "i2c" : { "attr_list": [ - {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "1:0", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, - {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "1:0", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, - {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "1:0", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"} + {"attr_name":"green", "bits" : "1:0", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"amber", "bits" : "1:0", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"}, + {"attr_name":"off", "bits" : "1:0", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x30"} ] } }, @@ -282,13 +365,13 @@ "PSU2_LED": { "dev_info": { "device_type":"LED", "device_name":"PSU_LED"}, - "dev_attr": { "index":"1"}, + "dev_attr": { "index":"1", "flag": "r"}, "i2c" : { "attr_list": [ - {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "7:6", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, - {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "7:6", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, - {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "7:6", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"} + {"attr_name":"green", "bits" : "7:6", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"amber", "bits" : "7:6", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"off", "bits" : "7:6", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"} ] } }, @@ -296,13 +379,13 @@ "FAN_LED": { "dev_info": { "device_type":"LED", "device_name":"FAN_LED"}, - "dev_attr": { "index":"0"}, + "dev_attr": { "index":"0", "flag": "r"}, "i2c" : { "attr_list": [ - {"attr_name":"STATUS_LED_COLOR_GREEN", "bits" : "3:2", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, - {"attr_name":"STATUS_LED_COLOR_AMBER", "bits" : "3:2", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, - {"attr_name":"STATUS_LED_COLOR_OFF", "bits" : "3:2", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"} + {"attr_name":"green", "bits" : "3:2", "descr" : "", "value" : "0x1", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"amber", "bits" : "3:2", "descr" : "", "value" : "0x2", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"}, + {"attr_name":"off", "bits" : "3:2", "descr" : "", "value" : "0x3", "swpld_addr" : "0x60", "swpld_addr_offset" : "0x31"} ] } }, @@ -336,7 +419,11 @@ { "attr_name":"psu_i_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_p_out", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, - { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_max", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa5", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_min", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa4", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out_max", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa7", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_high_threshold", "attr_devaddr":"0x58", "attr_devtype":"pmbus", "attr_offset":"0xa8", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} ] } }, @@ -350,7 +437,7 @@ "attr_list": [ { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x20", "attr_cmpval":"0x0", "attr_len":"1"}, - { "attr_name":"psu_model_name", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x20", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"12" }, + { "attr_name":"psu_model_name", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x20", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"14" }, { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x40", "attr_cmpval":"0x40", "attr_len":"1"}, { "attr_name":"psu_serial_num", "attr_devaddr":"0x50", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } ] @@ -387,7 +474,11 @@ { "attr_name":"psu_i_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8c", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_p_out", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x96", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, { "attr_name":"psu_fan1_speed_rpm", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x90", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, - { "attr_name":"psu_temp1_input", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} + { "attr_name":"psu_temp1_input", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0x8d", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_max", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0xa5", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_v_out_min", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0xa4", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_p_out_max", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0xa7", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"}, + { "attr_name":"psu_temp1_high_threshold", "attr_devaddr":"0x59", "attr_devtype":"pmbus", "attr_offset":"0xa8", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"2"} ] } }, @@ -401,7 +492,7 @@ "attr_list": [ { "attr_name":"psu_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"}, - { "attr_name":"psu_model_name", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x20", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"12" }, + { "attr_name":"psu_model_name", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x20", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"14" }, { "attr_name":"psu_power_good", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_offset":"0x22", "attr_mask":"0x4", "attr_cmpval":"0x4", "attr_len":"1"}, { "attr_name":"psu_serial_num", "attr_devaddr":"0x51", "attr_devtype":"eeprom", "attr_offset":"0x35", "attr_mask":"0x0", "attr_cmpval":"0xff", "attr_len":"19" } ] @@ -592,7 +683,9 @@ "topo_info": { "parent_bus":"0x16", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, "attr_list": [ - { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"} + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x0", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x3", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x2", "attr_cmpval":"0x0", "attr_len":"1"} ] } }, @@ -630,7 +723,9 @@ "topo_info": { "parent_bus":"0x17", "dev_addr":"0x53", "dev_type":"pddf_xcvr"}, "attr_list": [ - { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"} + { "attr_name":"xcvr_present", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x4", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_reset", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x7", "attr_cmpval":"0x0", "attr_len":"1"}, + { "attr_name":"xcvr_intr_status", "attr_devaddr":"0x60", "attr_devtype":"cpld", "attr_devname":"CPLD1", "attr_offset":"0x21", "attr_mask":"0x5", "attr_cmpval":"0x0", "attr_len":"1"} ] } } diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/platform.json b/device/accton/x86_64-accton_as4630_54pe-r0/platform.json new file mode 100644 index 00000000000..5f335fef255 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/platform.json @@ -0,0 +1,686 @@ +{ + "chassis": { + "name": "4630-54PE", + "thermal_manager":false, + "status_led": { + "controllable": true, + "colors": ["green", "green_blink", "amber", "amber_blink", "off"] + }, + "components": [ + { + "name": "CPLD1" + }, + { + "name": "BIOS" + } + ], + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + }, + { + "name": "FAN-3", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + } + ], + "fan_drawers":[ + { + "name": "FanTray1", + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "num_fans" : 1, + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray2", + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "num_fans" : 1, + "fans": [ + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray3", + "max_consumed_power": false, + "status_led": { + "controllable": false + }, + "num_fans" : 1, + "fans": [ + { + "name": "FAN-3", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": 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-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 + } + ] + } + ], + "thermals": [ + { + "name": "MB_temp(0x48)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "CB_temp(0x4B)", + "controllable": true, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": false + }, + { + "name": "FB_temp(0x4A)", + "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": true + }, + { + "name": "CPU_Core_0_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + }, + { + "name": "CPU_Core_1_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + }, + { + "name": "CPU_Core_2_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + }, + { + "name": "CPU_Core_3_temp", + "controllable": false, + "low-threshold": false, + "high-threshold": true, + "low-crit-threshold": false, + "high-crit-threshold": true + } + ], + "sfps": [ + { + "name": "Ethernet48" + }, + { + "name": "Ethernet49" + }, + { + "name": "Ethernet50" + }, + { + "name": "Ethernet51" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet56" + } + ] + }, + "interfaces": { + "Ethernet0": { + "index": "1", + "lanes": "26", + "breakout_modes": { + "1x1G": ["Eth1(Port1)"] + } + }, + + "Ethernet1": { + "index": "2", + "lanes": "25", + "breakout_modes": { + "1x1G": ["Eth2(Port2)"] + } + }, + + "Ethernet2": { + "index": "3", + "lanes": "28", + "breakout_modes": { + "1x1G": ["Eth3(Port3)"] + } + }, + + "Ethernet3": { + "index": "4", + "lanes": "27", + "breakout_modes": { + "1x1G": ["Eth4(Port4)"] + } + }, + + "Ethernet4": { + "index": "5", + "lanes": "30", + "breakout_modes": { + "1x1G": ["Eth5(Port5)"] + } + }, + + "Ethernet5": { + "index": "6", + "lanes": "29", + "breakout_modes": { + "1x1G": ["Eth6(Port6)"] + } + }, + + "Ethernet6": { + "index": "7", + "lanes": "32", + "breakout_modes": { + "1x1G": ["Eth7(Port7)"] + } + }, + + "Ethernet7": { + "index": "8", + "lanes": "31", + "breakout_modes": { + "1x1G": ["Eth8(Port8)"] + } + }, + + "Ethernet8": { + "index": "9", + "lanes": "38", + "breakout_modes": { + "1x1G": ["Eth9(Port9)"] + } + }, + + "Ethernet9": { + "index": "10", + "lanes": "37", + "breakout_modes": { + "1x1G": ["Eth10(Port10)"] + } + }, + + "Ethernet10": { + "index": "11", + "lanes": "40", + "breakout_modes": { + "1x1G": ["Eth11(Port11)"] + } + }, + + "Ethernet11": { + "index": "12", + "lanes": "39", + "breakout_modes": { + "1x1G": ["Eth12(Port12)"] + } + }, + + "Ethernet12": { + "index": "13", + "lanes": "34", + "breakout_modes": { + "1x1G": ["Eth13(Port13)"] + } + }, + + "Ethernet13": { + "index": "14", + "lanes": "33", + "breakout_modes": { + "1x1G": ["Eth14(Port14)"] + } + }, + + "Ethernet14": { + "index": "15", + "lanes": "36", + "breakout_modes": { + "1x1G": ["Eth15(Port15)"] + } + }, + + "Ethernet15": { + "index": "16", + "lanes": "35", + "breakout_modes": { + "1x1G": ["Eth16(Port16)"] + } + }, + + "Ethernet16": { + "index": "17", + "lanes": "46", + "breakout_modes": { + "1x1G": ["Eth17(Port17)"] + } + }, + + "Ethernet17": { + "index": "18", + "lanes": "45", + "breakout_modes": { + "1x1G": ["Eth18(Port18)"] + } + }, + + "Ethernet18": { + "index": "19", + "lanes": "48", + "breakout_modes": { + "1x1G": ["Eth19(Port19)"] + } + }, + + "Ethernet19": { + "index": "20", + "lanes": "47", + "breakout_modes": { + "1x1G": ["Eth20(Port20)"] + } + }, + + "Ethernet20": { + "index": "21", + "lanes": "42", + "breakout_modes": { + "1x1G": ["Eth21(Port21)"] + } + }, + + "Ethernet21": { + "index": "22", + "lanes": "41", + "breakout_modes": { + "1x1G": ["Eth22(Port22)"] + } + }, + + "Ethernet22": { + "index": "23", + "lanes": "44", + "breakout_modes": { + "1x1G": ["Eth23(Port23)"] + } + }, + + "Ethernet23": { + "index": "24", + "lanes": "43", + "breakout_modes": { + "1x1G": ["Eth24(Port24)"] + } + }, + + "Ethernet24": { + "index": "25", + "lanes": "2", + "breakout_modes": { + "1x1G": ["Eth25(Port25)"] + } + }, + + "Ethernet25": { + "index": "26", + "lanes": "1", + "breakout_modes": { + "1x1G": ["Eth26(Port26)"] + } + }, + + "Ethernet26": { + "index": "27", + "lanes": "4", + "breakout_modes": { + "1x1G": ["Eth27(Port27)"] + } + }, + + "Ethernet27": { + "index": "28", + "lanes": "3", + "breakout_modes": { + "1x1G": ["Eth28(Port28)"] + } + }, + + "Ethernet28": { + "index": "29", + "lanes": "6", + "breakout_modes": { + "1x1G": ["Eth29(Port29)"] + } + }, + + "Ethernet29": { + "index": "30", + "lanes": "5", + "breakout_modes": { + "1x1G": ["Eth30(Port30)"] + } + }, + + "Ethernet30": { + "index": "31", + "lanes": "8", + "breakout_modes": { + "1x1G": ["Eth31(Port31)"] + } + }, + + "Ethernet31": { + "index": "32", + "lanes": "7", + "breakout_modes": { + "1x1G": ["Eth32(Port32)"] + } + }, + + "Ethernet32": { + "index": "33", + "lanes": "10", + "breakout_modes": { + "1x1G": ["Eth33(Port33)"] + } + }, + + "Ethernet33": { + "index": "34", + "lanes": "9", + "breakout_modes": { + "1x1G": ["Eth34(Port34)"] + } + }, + + "Ethernet34": { + "index": "35", + "lanes": "12", + "breakout_modes": { + "1x1G": ["Eth35(Port35)"] + } + }, + + "Ethernet35": { + "index": "36", + "lanes": "11", + "breakout_modes": { + "1x1G": ["Eth36(Port36)"] + } + }, + + "Ethernet36": { + "index": "37", + "lanes": "14", + "breakout_modes": { + "1x1G": ["Eth37(Port37)"] + } + }, + + "Ethernet37": { + "index": "38", + "lanes": "13", + "breakout_modes": { + "1x1G": ["Eth38(Port38)"] + } + }, + + "Ethernet38": { + "index": "39", + "lanes": "16", + "breakout_modes": { + "1x1G": ["Eth39(Port39)"] + } + }, + + "Ethernet39": { + "index": "40", + "lanes": "15", + "breakout_modes": { + "1x1G": ["Eth40(Port40)"] + } + }, + + "Ethernet40": { + "index": "41", + "lanes": "18", + "breakout_modes": { + "1x1G": ["Eth41(Port41)"] + } + }, + + "Ethernet41": { + "index": "42", + "lanes": "17", + "breakout_modes": { + "1x1G": ["Eth42(Port42)"] + } + }, + + "Ethernet42": { + "index": "43", + "lanes": "20", + "breakout_modes": { + "1x1G": ["Eth43(Port43)"] + } + }, + + "Ethernet43": { + "index": "44", + "lanes": "19", + "breakout_modes": { + "1x1G": ["Eth44(Port44)"] + } + }, + + "Ethernet44": { + "index": "45", + "lanes": "22", + "breakout_modes": { + "1x1G": ["Eth45(Port45)"] + } + }, + + "Ethernet45": { + "index": "46", + "lanes": "21", + "breakout_modes": { + "1x1G": ["Eth46(Port46)"] + } + }, + + "Ethernet46": { + "index": "47", + "lanes": "24", + "breakout_modes": { + "1x1G": ["Eth47(Port47)"] + } + }, + + "Ethernet47": { + "index": "48", + "lanes": "23", + "breakout_modes": { + "1x1G": ["Eth48(Port48)"] + } + }, + + "Ethernet48": { + "index": "49", + "lanes": "67", + "breakout_modes": { + "1x25G[10G]": ["Eth49(Port49)"] + } + }, + + "Ethernet49": { + "index": "50", + "lanes": "66", + "breakout_modes": { + "1x25G[10G]": ["Eth50(Port50)"] + } + }, + + "Ethernet50": { + "index": "51", + "lanes": "65", + "breakout_modes": { + "1x25G[10G]": ["Eth51(Port51)"] + } + }, + + "Ethernet51": { + "index": "52", + "lanes": "68", + "breakout_modes": { + "1x25G[10G]": ["Eth52(Port52)"] + } + }, + "Ethernet52": { + "index": "53,53,53,53", + "lanes": "73,74,75,76", + "breakout_modes": { + "1x100G[40G]": ["Eth53(Port53)"], + "2x50G": ["Eth53/1(Port53)", "Eth53/2(Port53)"], + "4x25G[10G]": ["Eth53/1(Port53)", "Eth53/2(Port53)", "Eth53/3(Port53)", "Eth53/4(Port53)"] + } + }, + + "Ethernet56": { + "index": "54,54,54,54", + "lanes": "69,70,71,72", + "breakout_modes": { + "1x100G[40G]": ["Eth54(Port54)"], + "2x50G": ["Eth54/1(Port54)", "Eth54/2(Port54)"], + "4x25G[10G]": ["Eth54/1(Port54)", "Eth54/2(Port54)", "Eth54/3(Port54)", "Eth54/4(Port54)"] + } + } + } +} diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/platform_components.json b/device/accton/x86_64-accton_as4630_54pe-r0/platform_components.json new file mode 100644 index 00000000000..c1465e1374a --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-r0/platform_components.json @@ -0,0 +1,10 @@ +{ + "chassis": { + "4630-54PE-O-AC-F": { + "component": { + "CPLD1": { }, + "BIOS": { } + } + } + } +} \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/plugins/ssd_util.py b/device/accton/x86_64-accton_as4630_54pe-r0/plugins/ssd_util.py new file mode 100755 index 00000000000..6194fc7df7b --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54pe-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_as4630_54pe-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json index a3b204e20d8..44bad649422 100644 --- a/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as4630_54pe-r0/pmon_daemon_control.json @@ -1,5 +1,4 @@ { - "skip_ledd": true, - "skip_pcied": true + "skip_ledd": true } diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/sensors.conf b/device/accton/x86_64-accton_as4630_54pe-r0/sensors.conf index d34edc0f5a1..f52b326747e 100644 --- a/device/accton/x86_64-accton_as4630_54pe-r0/sensors.conf +++ b/device/accton/x86_64-accton_as4630_54pe-r0/sensors.conf @@ -31,10 +31,10 @@ chip "as4630_54pe_cpld-*" chip "lm77-i2c-*-48" - label temp1 "Main Board Temperature" + label temp1 "MB_temp" chip "lm75-i2c-*-4a" - label temp1 "Fan Board Temperature" + label temp1 "FB_temp" chip "lm75-i2c-*-4b" - label temp1 "CPU Board Temperature" + label temp1 "CB_temp" diff --git a/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json index 61f624ee34c..deb3745e141 100644 --- a/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json +++ b/device/accton/x86_64-accton_as4630_54pe-r0/system_health_monitoring_config.json @@ -1,17 +1,13 @@ { "services_to_ignore": [], "devices_to_ignore": [ - "asic", - "psu.voltage", - "psu.temperature", - "PSU1_FAN1.speed", - "PSU2_FAN1.speed" + "asic" ], "user_defined_checkers": [], "polling_interval": 60, "led_color": { - "fault": "STATUS_LED_COLOR_AMBER", - "normal": "STATUS_LED_COLOR_GREEN", - "booting": "STATUS_LED_COLOR_GREEN_BLINK" + "fault": "amber", + "normal": "green", + "booting": "green_blink" } } diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile index 41953f866b6..8b78ec0a754 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/Makefile @@ -1,7 +1,10 @@ ifneq ($(KERNELRELEASE),) obj-m:= x86-64-accton-as4630-54pe-cpld.o x86-64-accton-as4630-54pe-psu.o \ - x86-64-accton-as4630-54pe-leds.o ym2651y.o - + x86-64-accton-as4630-54pe-leds.o ym2651y.o pddf_custom_psu.o + +CFLAGS_pddf_custom_psu.o := -I$(M)/../../../../pddf/i2c/modules/include +KBUILD_EXTRA_SYMBOLS := $(M)/../../../../pddf/i2c/Module.symvers.PDDF + else ifeq (,$(KERNEL_SRC)) $(error KERNEL_SRC is not defined) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/accton_psu_api.h b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/accton_psu_api.h new file mode 120000 index 00000000000..a6b156930a8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/accton_psu_api.h @@ -0,0 +1 @@ +../../common/modules/accton_psu_api.h \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/accton_psu_defs.h b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/accton_psu_defs.h new file mode 120000 index 00000000000..96202b3ead2 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/accton_psu_defs.h @@ -0,0 +1 @@ +../../common/modules/accton_psu_defs.h \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/pddf_custom_psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/pddf_custom_psu.c new file mode 100644 index 00000000000..e9f0d33b194 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/pddf_custom_psu.c @@ -0,0 +1,538 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pddf_client_defs.h" +#include "pddf_psu_defs.h" +#include "pddf_psu_driver.h" +#include "pddf_psu_api.h" + + +ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf); +ssize_t pddf_show_custom_psu_v_out_max(struct device *dev, struct device_attribute *da, char *buf); +ssize_t pddf_show_custom_psu_v_out_min(struct device *dev, struct device_attribute *da, char *buf); +extern PSU_SYSFS_ATTR_DATA access_psu_v_out; +extern PSU_SYSFS_ATTR_DATA access_psu_v_out_max; +extern PSU_SYSFS_ATTR_DATA access_psu_v_out_min; +int pddf_post_get_custom_psu_model_name(void *i2c_client, PSU_DATA_ATTR *adata, void *data); +extern PSU_SYSFS_ATTR_DATA access_psu_serial_num; +int pddf_post_get_custom_psu_serial_num(void *i2c_client, PSU_DATA_ATTR *adata, void *data); +extern PSU_SYSFS_ATTR_DATA access_psu_model_name; +int pddf_post_get_custom_psu_fan_dir(void *i2c_client, PSU_DATA_ATTR *adata, void *data); +extern PSU_SYSFS_ATTR_DATA access_psu_fan_dir; +int pddf_custom_psu_post_probe(struct i2c_client *client, const struct i2c_device_id *dev_id); +int pddf_custom_psu_post_remove(struct i2c_client *client); +extern struct pddf_ops_t pddf_psu_ops; + +const char FAN_DIR_F2B[] = "F2B\0"; +const char FAN_DIR_B2F[] = "B2F\0"; + + +static LIST_HEAD(psu_eeprom_client_list); +static struct mutex list_lock; + +struct psu_eeprom_client_node { + struct i2c_client *client; + struct list_head list; +}; + +int pddf_post_get_custom_psu_model_name(void *i2c_client, PSU_DATA_ATTR *adata, void *data) +{ + struct psu_attr_info *sysfs_attr_info = (struct psu_attr_info *)data; + char *model_name = sysfs_attr_info->val.strval; + + if(!strncmp(model_name, "YPEB1200", strlen("YPEB1200"))) + { + if (model_name[9]=='A' && model_name[10]=='M') + { + model_name[8]='A'; + model_name[9]='M'; + model_name[strlen("YPEB1200AM")]='\0'; + } + else + model_name[strlen("YPEB1200")]='\0'; + } + + return 0; +} + +/* + * Get the PSU EEPROM I2C client with the same bus number. + */ +static struct i2c_client *find_psu_eeprom_client(struct i2c_client *pmbus_client) +{ + struct list_head *list_node = NULL; + struct psu_eeprom_client_node *psu_eeprom_node = NULL; + struct i2c_client *eeprom_client = NULL; + + mutex_lock(&list_lock); + list_for_each(list_node, &psu_eeprom_client_list) { + psu_eeprom_node = list_entry(list_node, struct psu_eeprom_client_node, list); + /* Check if the bus adapter is the same or not. */ + if (psu_eeprom_node->client->adapter == pmbus_client->adapter) { + eeprom_client = psu_eeprom_node->client; + break; + } + } + mutex_unlock(&list_lock); + + return eeprom_client; +} + +/* + * Compare the model name, then replace the content of psu_fan_dir. + */ +const char *fan_b2f_models[] = { + NULL +}; + +const char *fan_f2b_models[] = { + "YPEB1200", + "YPEB1200AM", + "UP1K21R-1085G", + NULL +}; + +int pddf_post_get_custom_psu_fan_dir(void *i2c_client, PSU_DATA_ATTR *adata, void *data) +{ + int i; + struct i2c_client *client = (struct i2c_client *)i2c_client; + struct psu_attr_info *psu_fan_dir_attr_info = (struct psu_attr_info *)data; + struct psu_data *psu_eeprom_client_data = NULL; + struct psu_attr_info *psu_eeprom_model_name = NULL; + struct i2c_client *psu_eeprom_client = NULL; + + psu_eeprom_client = find_psu_eeprom_client(client); + if (!psu_eeprom_client) { + return 0; + } + + /* + * Get the model name from the PSU EEPROM I2C client. + */ + psu_eeprom_client_data = i2c_get_clientdata(psu_eeprom_client); + if (!psu_eeprom_client_data) { + return 0; + } + for (i = 0; i < psu_eeprom_client_data->num_attr; i++) { + if (strcmp(psu_eeprom_client_data->attr_info[i].name, "psu_model_name") == 0) { + psu_eeprom_model_name = &psu_eeprom_client_data->attr_info[i]; + break; + } + } + if (!psu_eeprom_model_name) { + return 0; + } + + /* + * Compare the model name, then replace the content of psu_fan_dir. + */ + /* Check for B2F models */ + for (i = 0; fan_b2f_models[i] != NULL; i++) { + if (strcmp(psu_eeprom_model_name->val.strval, fan_b2f_models[i]) == 0) { + strscpy(psu_fan_dir_attr_info->val.strval, + FAN_DIR_B2F, + sizeof(psu_fan_dir_attr_info->val.strval)); + /* Match found in B2F models, exit early */ + return 0; + } + } + + /* If not found in B2F models, check F2B models */ + for (i = 0; fan_f2b_models[i] != NULL; i++) { + if (strcmp(psu_eeprom_model_name->val.strval, fan_f2b_models[i]) == 0) { + strscpy(psu_fan_dir_attr_info->val.strval, + FAN_DIR_F2B, + sizeof(psu_fan_dir_attr_info->val.strval)); + break; + } + } + + return 0; +} + + +int pddf_post_get_custom_psu_serial_num(void *i2c_client, PSU_DATA_ATTR *adata, void *data) +{ + int i; + struct i2c_client *client = (struct i2c_client *)i2c_client; + struct psu_attr_info *psu_serial_num_attr_info = (struct psu_attr_info *)data; + char *psu_serial_num = psu_serial_num_attr_info->val.strval; + + struct psu_data *psu_eeprom_client_data = NULL; + struct psu_attr_info *psu_eeprom_model_name = NULL; + struct i2c_client *psu_eeprom_client = NULL; + + psu_eeprom_client = find_psu_eeprom_client(client); + if (!psu_eeprom_client) { + return 0; + } + /* + * Get the model name from the PSU EEPROM I2C client. + */ + psu_eeprom_client_data = i2c_get_clientdata(psu_eeprom_client); + if (!psu_eeprom_client_data) { + return 0; + } + for (i = 0; i < psu_eeprom_client_data->num_attr; i++) { + if (strcmp(psu_eeprom_client_data->attr_info[i].name, "psu_model_name") == 0) { + psu_eeprom_model_name = &psu_eeprom_client_data->attr_info[i]; + break; + } + } + if (!psu_eeprom_model_name) { + return 0; + } + + if(!strncmp(psu_eeprom_model_name->val.strval, "UP1K21R-1085G", strlen("UP1K21R-1085G"))) + { + char buf[10]={0}; + memcpy(buf, &psu_serial_num[6], 9); + memcpy(psu_serial_num, buf, 9); + psu_serial_num[9]='\0'; + } + + return 0; +} + +static u8 psu_get_vout_mode(struct i2c_client *client) +{ + u8 status = 0, retry = 10; + uint8_t offset = 0x20; // VOUT_MODE + + while (retry) { + status = i2c_smbus_read_byte_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + printk(KERN_ERR "%s: Get PSU Vout mode failed\n", __func__); + return 0; + } + else + return status; + +} + +static u16 psu_get_v_out(struct i2c_client *client) +{ + u16 status = 0, retry = 10; + uint8_t offset = 0x8b; // READ_VOUT + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + printk(KERN_ERR "%s: Get PSU Vout failed\n", __func__); + return 0; + } + else + { + /*printk(KERN_ERR "%s: vout reg value 0x%x\n", __func__, status);*/ + return status; + } +} + +/* MFR_VOUT_MAX=0xa5, MFR_VOUT_MIN=0xa4 */ +static u16 psu_get_v_out_threshold(struct i2c_client *client, uint8_t offset) +{ + u16 status = 0, retry = 10; + + while (retry) { + status = i2c_smbus_read_word_data((struct i2c_client *)client, offset); + if (unlikely(status < 0)) { + msleep(60); + retry--; + continue; + } + break; + } + + if (status < 0) + { + printk(KERN_ERR "%s: Get PSU Vout failed\n", __func__); + return 0; + } + else + { + return status; + } +} + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + + +ssize_t pddf_show_custom_psu_v_out(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + struct psu_data *psu_eeprom_client_data = NULL; + struct psu_attr_info *psu_eeprom_model_name = NULL; + struct i2c_client *psu_eeprom_client = NULL; + + int exponent, mantissa, status, i; + int multiplier = 1000; + + u16 value = psu_get_v_out(client); + u8 vout_mode = psu_get_vout_mode(client); + + psu_eeprom_client = find_psu_eeprom_client(client); + if (!psu_eeprom_client) { + return 0; + } + /* + * Get the model name from the PSU EEPROM I2C client. + */ + psu_eeprom_client_data = i2c_get_clientdata(psu_eeprom_client); + if (!psu_eeprom_client_data) { + return 0; + } + + for (i = 0; i < psu_eeprom_client_data->num_attr; i++) { + if (strcmp(psu_eeprom_client_data->attr_info[i].name, "psu_model_name") == 0) { + psu_eeprom_model_name = &psu_eeprom_client_data->attr_info[i]; + break; + } + } + if (!psu_eeprom_model_name) { + return 0; + } + if(strncmp(psu_eeprom_model_name->val.strval, "UP1K21R-1085G", strlen("UP1K21R-1085G")) == 0 ) + { + exponent = two_complement_to_int(vout_mode, 5, 0x1f); + mantissa = value; + + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + } + else + { + + multiplier = 1000; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + } +} +ssize_t pddf_show_custom_psu_v_out_max(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + struct psu_data *psu_eeprom_client_data = NULL; + struct psu_attr_info *psu_eeprom_model_name = NULL; + struct i2c_client *psu_eeprom_client = NULL; + + int exponent, mantissa, status, i; + int multiplier = 1000; + + u16 value = psu_get_v_out_threshold(client, 0xa5); + u8 vout_mode = psu_get_vout_mode(client); + + psu_eeprom_client = find_psu_eeprom_client(client); + if (!psu_eeprom_client) { + return 0; + } + /* + * Get the model name from the PSU EEPROM I2C client. + */ + psu_eeprom_client_data = i2c_get_clientdata(psu_eeprom_client); + if (!psu_eeprom_client_data) { + return 0; + } + + for (i = 0; i < psu_eeprom_client_data->num_attr; i++) { + if (strcmp(psu_eeprom_client_data->attr_info[i].name, "psu_model_name") == 0) { + psu_eeprom_model_name = &psu_eeprom_client_data->attr_info[i]; + break; + } + } + if (!psu_eeprom_model_name) { + return 0; + } + if(strncmp(psu_eeprom_model_name->val.strval, "UP1K21R-1085G", strlen("UP1K21R-1085G")) == 0 ) + { + /**Linear16 mode*/ + exponent = two_complement_to_int(vout_mode, 5, 0x1f); + mantissa = value; + + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + } + else + { + /**Linear11 mode*/ + multiplier = 1000; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + } +} +ssize_t pddf_show_custom_psu_v_out_min(struct device *dev, struct device_attribute *da, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + struct psu_data *psu_eeprom_client_data = NULL; + struct psu_attr_info *psu_eeprom_model_name = NULL; + struct i2c_client *psu_eeprom_client = NULL; + + int exponent, mantissa, status, i; + int multiplier = 1000; + + u16 value = psu_get_v_out_threshold(client, 0xa4); + u8 vout_mode = psu_get_vout_mode(client); + + psu_eeprom_client = find_psu_eeprom_client(client); + if (!psu_eeprom_client) { + return 0; + } + /* + * Get the model name from the PSU EEPROM I2C client. + */ + psu_eeprom_client_data = i2c_get_clientdata(psu_eeprom_client); + if (!psu_eeprom_client_data) { + return 0; + } + + for (i = 0; i < psu_eeprom_client_data->num_attr; i++) { + if (strcmp(psu_eeprom_client_data->attr_info[i].name, "psu_model_name") == 0) { + psu_eeprom_model_name = &psu_eeprom_client_data->attr_info[i]; + break; + } + } + if (!psu_eeprom_model_name) { + return 0; + } + if(strncmp(psu_eeprom_model_name->val.strval, "UP1K21R-1085G", strlen("UP1K21R-1085G")) == 0 ) + { + /*Linear16 mode*/ + exponent = two_complement_to_int(vout_mode, 5, 0x1f); + mantissa = value; + if (exponent >= 0) + return sprintf(buf, "%d\n", (mantissa << exponent) * multiplier); + else + return sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + } + else + { + /*Linear11 mode*/ + multiplier = 1000; + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + } +} + +int pddf_custom_psu_post_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) +{ + struct psu_eeprom_client_node *psu_eeprom_node; + + if (strcmp(dev_id->name, "psu_eeprom") != 0) { + return 0; + } + + psu_eeprom_node = kzalloc(sizeof(struct psu_eeprom_client_node), GFP_KERNEL); + if (!psu_eeprom_node) { + dev_dbg(&client->dev, "Can't allocate psu_eeprom_client_node (0x%x)\n", client->addr); + return -ENOMEM; + } + + psu_eeprom_node->client = client; + + mutex_lock(&list_lock); + list_add(&psu_eeprom_node->list, &psu_eeprom_client_list); + mutex_unlock(&list_lock); + + return 0; +} + +int pddf_custom_psu_post_remove(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct psu_eeprom_client_node *psu_eeprom_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &psu_eeprom_client_list) { + psu_eeprom_node = list_entry(list_node, struct psu_eeprom_client_node, list); + + if (psu_eeprom_node->client == client) { + list_del_init(&psu_eeprom_node->list); + found = 1; + break; + } + } + + if (found) { + kfree(psu_eeprom_node); + } + + mutex_unlock(&list_lock); + + return 0; +} + +static int __init pddf_custom_psu_init(void) +{ + mutex_init(&list_lock); + access_psu_model_name.post_get = pddf_post_get_custom_psu_model_name; + access_psu_serial_num.post_get = pddf_post_get_custom_psu_serial_num; + access_psu_fan_dir.post_get = pddf_post_get_custom_psu_fan_dir; + access_psu_v_out.show = pddf_show_custom_psu_v_out; + access_psu_v_out_max.show = pddf_show_custom_psu_v_out_max; + access_psu_v_out_min.show = pddf_show_custom_psu_v_out_min; + + pddf_psu_ops.post_probe = pddf_custom_psu_post_probe; + pddf_psu_ops.post_remove = pddf_custom_psu_post_remove; + return 0; +} + +static void __exit pddf_custom_psu_exit(void) +{ + return; +} + +MODULE_AUTHOR("Broadcom"); +MODULE_DESCRIPTION("pddf custom psu api"); +MODULE_LICENSE("GPL"); + +module_init(pddf_custom_psu_init); +module_exit(pddf_custom_psu_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c index 20a00abb8d7..38c0c8d53ca 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/modules/x86-64-accton-as4630-54pe-psu.c @@ -36,7 +36,12 @@ #define MAX_MODEL_NAME 20 #define MAX_SERIAL_NUMBER 19 +#define FAN_DIR_LEN 4 +const char FAN_DIR_F2B[] = "F2B"; +const char FAN_DIR_B2F[] = "B2F"; + +static int models_min_offset = 0; 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); static int as4630_54pe_psu_read_block(struct i2c_client *client, u8 command, u8 *data,int data_len); @@ -57,6 +62,7 @@ struct as4630_54pe_psu_data { u8 status; /* Status(present/power_good) register read from CPLD */ char model_name[MAX_MODEL_NAME]; /* Model name, read from eeprom */ char serial_number[MAX_SERIAL_NUMBER]; + char fan_dir[FAN_DIR_LEN]; }; static struct as4630_54pe_psu_data *as4630_54pe_psu_update_device(struct device *dev); @@ -65,7 +71,39 @@ enum as4630_54pe_psu_sysfs_attributes { PSU_PRESENT, PSU_MODEL_NAME, PSU_POWER_GOOD, - PSU_SERIAL_NUMBER + PSU_SERIAL_NUMBER, + PSU_FAN_DIR +}; + +enum psu_type { + PSU_YPEB1200, /* F2B */ + PSU_YPEB1200AM, /* F2B */ + PSU_UP1K21R_1085G, /* F2B */ + UNKNOWN_PSU +}; + +struct model_name_info { + enum psu_type type; + u8 offset; + u8 length; + char* model_name; +}; + +struct model_name_info models[] = { +{PSU_YPEB1200, 0x20, 11, "YPEB1200"}, +{PSU_YPEB1200AM, 0x20, 11, "YPEB1200AM"}, /* Replace YPEB1200-AM to YPEB1200AM */ +{PSU_UP1K21R_1085G, 0x20, 13, "UP1K21R-1085G"}, +}; + +struct serial_number_info { + u8 offset; + u8 length; +}; + +struct serial_number_info serials[] = { + [PSU_YPEB1200] = {0x35, 17}, + [PSU_YPEB1200AM] = {0x35, 18}, + [PSU_UP1K21R_1085G] = {0x3B, 9}, }; /* sysfs attributes for hwmon @@ -74,13 +112,14 @@ static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRE 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_number, 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 *as4630_54pe_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_number.dev_attr.attr, + &sensor_dev_attr_psu_fan_dir.dev_attr.attr, NULL }; @@ -90,7 +129,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct as4630_54pe_psu_data *data = as4630_54pe_psu_update_device(dev); u8 status = 0; - + if (attr->index == PSU_PRESENT) { if(data->index==0) status = !( (data->status >> 5) & 0x1); @@ -101,7 +140,7 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, if(data->index==0) status = ( (data->status >> 6) & 0x1); else - status = ( (data->status >> 2) & 0x1); + status = ( (data->status >> 2) & 0x1); } return sprintf(buf, "%d\n", status); @@ -125,6 +164,9 @@ static ssize_t show_string(struct device *dev, struct device_attribute *da, case PSU_SERIAL_NUMBER: ptr = data->serial_number; break; + case PSU_FAN_DIR: + ptr = data->fan_dir; + break; default: return -EINVAL; } @@ -136,6 +178,18 @@ static const struct attribute_group as4630_54pe_psu_group = { .attrs = as4630_54pe_psu_attributes, }; +static int find_models_min_offset(void) { + int i, min_offset = models[0].offset; + + for(i = 1; i < (sizeof(models) / sizeof(models[0])); i++) { + if(models[i].offset < min_offset) { + min_offset = models[i].offset; + } + } + + return min_offset; +} + static int as4630_54pe_psu_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { @@ -157,6 +211,7 @@ static int as4630_54pe_psu_probe(struct i2c_client *client, data->valid = 0; data->index = dev_id->driver_data; mutex_init(&data->update_lock); + models_min_offset = find_models_min_offset(); dev_info(&client->dev, "chip found\n"); @@ -193,7 +248,6 @@ static void as4630_54pe_psu_remove(struct i2c_client *client) hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &as4630_54pe_psu_group); kfree(data); - } enum psu_index @@ -253,13 +307,14 @@ static struct as4630_54pe_psu_data *as4630_54pe_psu_update_device(struct device { struct i2c_client *client = to_i2c_client(dev); struct as4630_54pe_psu_data *data = i2c_get_clientdata(client); + char temp_model_name[MAX_MODEL_NAME] = {0}; mutex_lock(&data->update_lock); if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { int status; - int power_good = 0; + int i, power_good = 0; dev_dbg(&client->dev, "Starting as4630_54pe update\n"); @@ -275,50 +330,96 @@ static struct as4630_54pe_psu_data *as4630_54pe_psu_update_device(struct device /* Read model name */ memset(data->model_name, 0, sizeof(data->model_name)); memset(data->serial_number, 0, sizeof(data->serial_number)); - power_good = (data->status >> (3-data->index) & 0x1); - + memset(data->fan_dir, 0, sizeof(data->fan_dir)); + power_good = (data->status >> (data->index==0? 6:2)) & 0x1; + if (power_good) { - status = as4630_54pe_psu_read_block(client, 0x20, data->model_name, - ARRAY_SIZE(data->model_name)-1); + enum psu_type type = UNKNOWN_PSU; + + status = as4630_54pe_psu_read_block(client, models_min_offset, + temp_model_name, + ARRAY_SIZE(temp_model_name)); 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; } - else if(!strncmp(data->model_name, "YPEB1200", strlen("YPEB1200"))) - { - if (data->model_name[9]=='A' && data->model_name[10]=='M') - { - data->model_name[8]='A'; - data->model_name[9]='M'; - data->model_name[strlen("YPEB1200AM")]='\0'; - } - else - data->model_name[strlen("YPEB1200")]='\0'; + + for (i = 0; i < ARRAY_SIZE(models); i++) { + if ((models[i].length+1) > ARRAY_SIZE(data->model_name)) { + dev_dbg(&client->dev, + "invalid models[%d].length(%d), should not exceed the size of data->model_name(%ld)\n", + i, models[i].length, ARRAY_SIZE(data->model_name)); + continue; + } + + snprintf(data->model_name, models[i].length + 1, "%s", + temp_model_name + (models[i].offset - models_min_offset)); + + if(!strncmp(data->model_name, "YPEB1200", strlen("YPEB1200"))) + { + if (data->model_name[9]=='A' && data->model_name[10]=='M') + { + data->model_name[8]='A'; + data->model_name[9]='M'; + data->model_name[strlen("YPEB1200AM")]='\0'; + } + else + data->model_name[strlen("YPEB1200")]='\0'; + } + + /* Determine if the model name is known, if not, read next index */ + if (strcmp(data->model_name, models[i].model_name) == 0) { + type = models[i].type; + break; + } + + data->model_name[0] = '\0'; } - else - { - data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; + + switch (type) { + case PSU_YPEB1200: + case PSU_YPEB1200AM: + case PSU_UP1K21R_1085G: + memcpy(data->fan_dir, FAN_DIR_F2B, sizeof(FAN_DIR_F2B)); + break; + default: + dev_dbg(&client->dev, "Unknown PSU type for fan direction\n"); + break; } - /* Read from offset 0x35 ~ 0x46 (18 bytes) */ - status = as4630_54pe_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); - if (status < 0) - { - data->serial_number[0] = '\0'; - dev_dbg(&client->dev, "unable to read model name from (0x%x) offset(0x35)\n", client->addr); + + if (type < ARRAY_SIZE(serials)) { + if ((serials[type].length+1) > ARRAY_SIZE(data->serial_number)) { + dev_dbg(&client->dev, + "invalid serials[%d].length(%d), should not exceed the size of data->serial_number(%ld)\n", + type, serials[type].length, ARRAY_SIZE(data->serial_number)); + goto exit; + } + + memset(data->serial_number, 0, sizeof(data->serial_number)); + status = as4630_54pe_psu_read_block(client, serials[type].offset, + data->serial_number, + serials[type].length); + if (status < 0) { + dev_dbg(&client->dev, + "unable to read serial from (0x%x) offset(0x%02x)\n", + client->addr, serials[type].length); + goto exit; + } + else { + data->serial_number[serials[type].length]= '\0'; + } } - if (!strncmp(data->model_name, "YPEB1200AM", strlen("YPEB1200AM"))) /*for YPEB1200AM, SN length=18*/ - { - data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + else { + dev_dbg(&client->dev, "invalid PSU type(%d)\n", type); + goto exit; } - else - data->serial_number[MAX_SERIAL_NUMBER-2]='\0'; - } data->last_updated = jiffies; data->valid = 1; } +exit: mutex_unlock(&data->update_lock); return data; diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-pddf-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-pddf-platform-monitor.service new file mode 100644 index 00000000000..99bca2684f4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/service/as4630-54pe-pddf-platform-monitor.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS4630-54PE Platform Monitoring service +Before=pmon.service +After=pddf-platform-init.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as4630_54pe_pddf_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py index 1dfca24ab32..8ec7deb95aa 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/chassis.py @@ -10,10 +10,14 @@ import sys from sonic_platform_pddf_base.pddf_chassis import PddfChassis from .event import SfpEvent + from .helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") NUM_COMPONENT = 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" class Chassis(PddfChassis): """ @@ -26,6 +30,7 @@ def __init__(self, pddf_data=None, pddf_plugin_data=None): PddfChassis.__init__(self, pddf_data, pddf_plugin_data) self.__initialize_components() self._sfpevent = SfpEvent(self.get_all_sfps()) + self._api_helper = APIHelper() def __initialize_components(self): from sonic_platform.component import Component @@ -68,3 +73,57 @@ def get_status_led(self): def set_status_led(self, color): return self.set_system_led(self.SYSLED_DEV_NAME, color) + + + 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, 53): + return SfpBase.SFP_PORT_TYPE_BIT_SFP | SfpBase.SFP_PORT_TYPE_BIT_SFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_SFP28 + else: + return SfpBase.SFP_PORT_TYPE_BIT_QSFP | SfpBase.SFP_PORT_TYPE_BIT_QSFP_PLUS | SfpBase.SFP_PORT_TYPE_BIT_QSFP28 + + 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_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return self._eeprom.revision_str() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py index 2659d16f1c8..a30b4630e0a 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/component.py @@ -8,6 +8,8 @@ ############################################################################# try: + import os + import json from sonic_platform_base.component_base import ComponentBase from sonic_py_common.general import getstatusoutput_noshell except ImportError as e: @@ -82,4 +84,85 @@ def install_firmware(self, image_path): Returns: A boolean, True if install successfully, False if not """ - raise NotImplementedError + ret, output = getstatusoutput_noshell(["tar", "-C", "/tmp", "-xzf", image_path ] ) + if ret != 0 : + print("Installation failed because of wrong image package") + return False + + if os.path.exists("/tmp/install.json") is False: + print("Installation failed without jsonfile") + return False + + input_file = open ('/tmp/install.json') + json_array = json.load(input_file) + ret = 1 + for item in json_array: + if item.get('id')==None or item.get('path')==None: + continue + if self.name == item['id'] and item['path'] and item.get('cpu'): + print( "Find", item['id'], item['path'], item['cpu'] ) + ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'], item['cpu'] ]) + if ret==0: + break + elif self.name == item['id'] and item['path']: + print( "Find", item['id'], item['path'] ) + ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'] ]) + if ret==0: + break + + if ret==0: + return True + else : + return False + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py index d5dac6d7f7e..1a2f60dbb67 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/event.py @@ -1,11 +1,21 @@ try: import time from sonic_py_common.logger import Logger + from .sfp import Sfp except ImportError as e: raise ImportError(repr(e) + " - required module not found") POLL_INTERVAL_IN_SEC = 1 +# SFP errors that will block eeprom accessing +SFP_BLOCKING_ERRORS = [ + Sfp.SFP_ERROR_BIT_I2C_STUCK, + Sfp.SFP_ERROR_BIT_BAD_EEPROM, + Sfp.SFP_ERROR_BIT_UNSUPPORTED_CABLE, + Sfp.SFP_ERROR_BIT_HIGH_TEMP, + Sfp.SFP_ERROR_BIT_BAD_CABLE +] + class SfpEvent: ''' Listen to insert/remove sfp events ''' @@ -46,15 +56,54 @@ def get_sfp_event(self, timeout=2000): if changed_ports != 0: for sfp in self._sfp_list: i=sfp.get_position_in_parent() - 1 - if (changed_ports & (1 << i)): - if (bitmap & (1 << i)) == 0: - port_dict[i+1] = '0' - else: - port_dict[i+1] = '1' + if (changed_ports & (1 << i)) == 0: + continue + + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + # sfp.refresh_optoe_dev_class() + sfp_state_bits = self.get_sfp_state_bits(sfp, True) + sfp_state_bits = self.check_sfp_blocking_errors(sfp_state_bits) + port_dict[i+1] = str(sfp_state_bits) # Update the cache dict self._sfp_change_event_data['present'] = bitmap return True, change_dict else: return True, change_dict + + def get_sfp_state_bits(self, sfp, present): + sfp_state_bits = 0 + + if present is True: + sfp_state_bits |= Sfp.SFP_STATUS_BIT_INSERTED + else: + return sfp_state_bits + + status = sfp.validate_eeprom() + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + elif status is not True: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BAD_EEPROM + return sfp_state_bits + + status = sfp.validate_temperature() + if status is None: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_I2C_STUCK + return sfp_state_bits + elif status is not True: + sfp_state_bits |= Sfp.SFP_ERROR_BIT_HIGH_TEMP + return sfp_state_bits + + return sfp_state_bits + + def check_sfp_blocking_errors(self, sfp_state_bits): + for i in SFP_BLOCKING_ERRORS: + if (i & sfp_state_bits) == 0: + continue + sfp_state_bits |= Sfp.SFP_ERROR_BIT_BLOCKING + + return sfp_state_bits diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py index ef8deaffb6f..b9be5e3ca32 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan.py @@ -6,6 +6,7 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") +FAN_NAME_LIST = ["FAN-1", "FAN-2", "FAN-3"] class Fan(PddfFan): """PDDF Platform-Specific Fan class""" @@ -24,25 +25,53 @@ def get_direction(self): A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction """ + direction = 'N/A' if self.is_psu_fan: direction = self.FAN_DIRECTION_EXHAUST - else: - idx = (self.fantray_index-1)*self.platform['num_fans_pertray'] + self.fan_index - attr = "fan" + str(idx) + "_direction" - output = self.pddf_obj.get_attr_name_output("FAN-CTRL", attr) - if not output: - return False - - mode = output['mode'] - val = output['status'] - - val = val.rstrip() - vmap = self.plugin_data['FAN']['direction'][mode]['valmap'] - if val in vmap: - direction = vmap[val] - else: - direction = val + direction = super().get_direction() + if direction is not None and len(direction) > 0: + return direction return direction + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + fan_name = FAN_NAME_LIST[self.fantray_index - 1] \ + if not self.is_psu_fan \ + else "PSU-{} FAN-{}".format(self.fans_psu_index, self.fan_index) + + return fan_name + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.is_psu_fan: + return super().get_speed() + else: + return super().get_target_speed() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan_drawer.py index 3b9bb607f63..eae95191e19 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan_drawer.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/fan_drawer.py @@ -15,3 +15,26 @@ def __init__(self, tray_idx, pddf_data=None, pddf_plugin_data=None): PddfFanDrawer.__init__(self, tray_idx, pddf_data, pddf_plugin_data) # Provide the functions/variables below for which implementation is to be overwritten + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray{}".format(self.fantray_index) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/helper.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/helper.py new file mode 100644 index 00000000000..c0d15a618ef --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/helper.py @@ -0,0 +1,361 @@ +import os +import struct +import json +import fcntl +from mmap import * +from sonic_py_common import device_info +from sonic_py_common import logger +from threading import Lock +from typing import cast +from sonic_py_common.general import getstatusoutput_noshell_pipe +from sonic_py_common.general import getstatusoutput_noshell + +HOST_CHK_CMD = ["docker"] +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + try: + status, output = getstatusoutput_noshell(HOST_CHK_CMD) + return status == 0 + except Exception: + return False + + def pci_get_value(self, resource, offset): + status = True + result = "" + try: + fd = os.open(resource, os.O_RDWR) + mm = mmap(fd, 0) + mm.seek(int(offset)) + read_data_stream = mm.read(4) + result = struct.unpack('I', read_data_stream) + except Exception: + status = False + return status, result + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() + ret = data.strip() + if len(ret) > 0: + return ret + except IOError: + pass + return None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'raw', str(netfn), str(cmd)]) + if err == [0]: + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + if (key is None): + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'fru', 'print', str(id)]) + else: + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'fru', 'print', str(id)], ['grep', str(key)]) + if err == [0] or err == [0, 0]: + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + err, raw_data = getstatusoutput_noshell_pipe(['ipmitool', 'sensor', 'thresh', str(id), str(threshold_key), str(value)]) + if err == [0]: + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + +class FileLock: + """ + Due to pmon docker not installing the py-filelock, this class + implements a simple file lock feature. + Ref: https://github.com/tox-dev/py-filelock/blob/main/src/filelock/ + """ + + def __init__(self, lock_file): + self._lock_file = lock_file + self._thread_lock = Lock() + self.is_locked = False + + def acquire(self): + with self._thread_lock: + if self.is_locked: + return + + fd = os.open(self._lock_file, flags=(os.O_RDWR | os.O_CREAT | os.O_TRUNC)) + fcntl.flock(fd, fcntl.LOCK_EX) + self._lock_file_fd = fd + self.is_locked = True + + def release(self): + with self._thread_lock: + if self.is_locked: + fd = cast(int, self._lock_file_fd) + self._lock_file_fd = None + fcntl.flock(fd, fcntl.LOCK_UN) + os.close(fd) + self.is_locked = False + + def __enter__(self): + self.acquire() + return self + + def __exit__(self, exc_type, exc_val, traceback): + self.release() + + def __del__(self): + self.release() + + +DEVICE_THRESHOLD_JSON_PATH = "/tmp/device_threshold.json" + +class DeviceThreshold: + HIGH_THRESHOLD = 'high_threshold' + LOW_THRESHOLD = 'low_threshold' + HIGH_CRIT_THRESHOLD = 'high_critical_threshold' + LOW_CRIT_THRESHOLD = 'low_critical_threshold' + NOT_AVAILABLE = 'N/A' + + def __init__(self, th_name = NOT_AVAILABLE): + self.flock = FileLock("{}.lock".format(DEVICE_THRESHOLD_JSON_PATH)) + self.name = th_name + self.__log = logger.Logger(log_identifier="DeviceThreshold") + + self.__db_data = {} + self.__db_mtime = 0 + + def __reload_db(self): + try: + db_data = {} + with self.flock: + with open(DEVICE_THRESHOLD_JSON_PATH, "r") as db_file: + db_data = json.load(db_file) + except Exception as e: + self.__log.log_warning('{}'.format(str(e))) + return None + + return db_data + + def __get_data(self, field): + """ + Retrieves data frome JSON file by field + + Args : + field: String + + Returns: + A string if getting is successfully, 'N/A' if not + """ + if os.path.exists(DEVICE_THRESHOLD_JSON_PATH): + new_mtime = os.path.getmtime(DEVICE_THRESHOLD_JSON_PATH) + if new_mtime != self.__db_mtime: + new_data = self.__reload_db() + if new_data is not None: + self.__db_data = new_data + self.__db_mtime = new_mtime + + if self.name not in self.__db_data.keys(): + return self.NOT_AVAILABLE + + if field not in self.__db_data[self.name].keys(): + return self.NOT_AVAILABLE + + return self.__db_data[self.name][field] + + def __set_data(self, field, new_val): + """ + Set data to JSON file by field + + Args : + field: String + new_val: String + + Returns: + A boolean, True if setting is set successfully, False if not + """ + if self.name not in self.__db_data.keys(): + self.__db_data[self.name] = {} + + old_val = self.__db_data[self.name].get(field, None) + if old_val is not None and old_val == new_val: + return True + + self.__db_data[self.name][field] = new_val + + try: + with self.flock: + db_data = {} + mode = "r+" if os.path.exists(DEVICE_THRESHOLD_JSON_PATH) else "w+" + with open(DEVICE_THRESHOLD_JSON_PATH, mode) as db_file: + if mode == "r+": + db_data = json.load(db_file) + + if self.name not in db_data.keys(): + db_data[self.name] = {} + + db_data[self.name][field] = new_val + + if mode == "r+": + db_file.seek(0) + # erase old data + db_file.truncate(0) + # write all data + json.dump(db_data, db_file, indent=4) + self.__db_mtime = os.path.getmtime(DEVICE_THRESHOLD_JSON_PATH) + except Exception as e: + self.__log.log_error('{}'.format(str(e))) + return False + + return True + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature from JSON file. + + Returns: + string : the high threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.HIGH_THRESHOLD) + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.HIGH_THRESHOLD, temperature) + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature from JSON file. + + Returns: + string : the low threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.LOW_THRESHOLD) + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.LOW_THRESHOLD, temperature) + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature from JSON file. + + Returns: + string : the high critical threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.HIGH_CRIT_THRESHOLD) + + def set_high_critical_threshold(self, temperature): + """ + Sets the high critical threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.HIGH_CRIT_THRESHOLD, temperature) + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature from JSON file. + + Returns: + string : the low critical threshold temperature of thermal, + e.g. "30.125" + """ + return self.__get_data(self.LOW_CRIT_THRESHOLD) + + def set_low_critical_threshold(self, temperature): + """ + Sets the low critical threshold temperature of thermal + Args : + temperature: A string of temperature, e.g. "30.125" + Returns: + A boolean, True if threshold is set successfully, False if not + """ + if isinstance(temperature, str) is not True: + raise TypeError('The parameter requires string type.') + + try: + if temperature != self.NOT_AVAILABLE: + float(temperature) + except ValueError: + raise ValueError('The parameter requires a float string. ex:\"30.1\"') + + return self.__set_data(self.LOW_CRIT_THRESHOLD, temperature) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/pcie.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/pcie.py new file mode 100644 index 00000000000..73d3627dbf7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/pcie.py @@ -0,0 +1,19 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# Base PCIe class +############################################################################# + +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Pcie(PcieUtil): + """Edgecore Platform-specific PCIe class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py index f002f5e0394..17991087e15 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/psu.py @@ -10,42 +10,132 @@ class Psu(PddfPsu): """PDDF Platform-Specific PSU class""" - - PLATFORM_PSU_CAPACITY = 1200 def __init__(self, index, pddf_data=None, pddf_plugin_data=None): PddfPsu.__init__(self, index, pddf_data, pddf_plugin_data) # Provide the functions/variables below for which implementation is to be overwritten - def get_capacity(self): + def get_name(self): + return "PSU-{}".format(self.psu_index) + + def get_revision(self): """ - Gets the capacity (maximum output power) of the PSU in watts + Retrieves the hardware revision of the device Returns: - An integer, the capacity of PSU + string: Revision value of device """ - return (self.PLATFORM_PSU_CAPACITY) + return 'N/A' - def get_type(self): + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - Gets the type of the PSU + threshold = super().get_temperature_high_threshold() + + for psu_thermal_idx in range(self.num_psu_thermals): + try: + tmp = self._thermal_list[psu_thermal_idx].get_high_threshold() + if threshold > tmp or threshold == 0.0: + threshold = tmp + except Exception: + pass + + return threshold + + def get_model(self): + """ + Retrieves the model number (or part number) of the device Returns: - A string, the type of PSU (AC/DC) + string: Model/part number of device """ - ptype = "AC" - # Currently the platform supports only AC type of PSUs - #try: - #import sonic_platform.platform - #ch=sonic_platform.platform.Platform().get_chassis() - #e=ch.sys_eeprom.read_eeprom() - #ret, prod_name = ch.sys_eeprom.get_tlv_field(e,0x21) - #if ret: - #prod_name = prod_name[2] - ##print("Product name is {}".format(prod_name)) - #if '48V' in prod_name: - #ptype = 'DC' - #except Exception as e: - #print("Error while trying to read syseeprom to get PSU type") + model = super().get_model() + if model and model.strip() == "": + return None + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = super().get_serial() + if serial and serial.strip() == "": + return None + + return serial + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + if self.get_status() is not True: + return 0.0 + + return super().get_voltage() + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, electric current in amperes, + e.g. 15.4 + """ + if self.get_status() is not True: + return 0.0 + + return super().get_current() + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + if self.get_status() is not True: + return 0.0 + + return super().get_power() + + def get_maximum_supplied_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, + e.g. 302.6 + """ + device = "PSU{}".format(self.psu_index) + output = self.pddf_obj.get_attr_name_output(device, "psu_p_out_max") + if not output: + return 0.0 + + p_out = output['status'] + + # power is returned in micro watts + return float(p_out)/1000 + def get_voltage_high_threshold(self): + if self.get_model()=='UP1K21R-1085G': + return 56.135 + + return super().get_voltage_high_threshold() + + def get_voltage_low_threshold(self): + if self.get_model()=='UP1K21R-1085G': + return 52.865 + + return super().get_voltage_low_threshold() - return ptype diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py index c9fb07d6364..5acb25e8ec4 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/sfp.py @@ -1,7 +1,10 @@ #!/usr/bin/env python try: + import natsort from sonic_platform_pddf_base.pddf_sfp import PddfSfp + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from sonic_py_common import device_info except ImportError as e: raise ImportError (str(e) + "- required module not found") @@ -11,10 +14,232 @@ class Sfp(PddfSfp): PDDF Platform-Specific Sfp class """ + SFP_TYPE_CODE_LIST = [ + 0x03, # SFP/SFP+/SFP28 + 0x0b # DWDM-SFP/SFP+ + ] + QSFP_TYPE_CODE_LIST = [ + 0x0c, # QSFP + 0x0d, # QSFP+ or later + 0x11, # QSFP28 or later + 0xe1 # QSFP28 EDFA + ] + def __init__(self, index, pddf_data=None, pddf_plugin_data=None): PddfSfp.__init__(self, index, pddf_data, pddf_plugin_data) + self.index = self.port_index # Provide the functions/variables below for which implementation is to be overwritten def get_position_in_parent(self): """Retrieves 1-based relative physical position in parent device.""" return self.port_index + + def __get_path_to_port_config_file(self): + platform, hwsku = device_info.get_platform_and_hwsku() + hwsku_path = "/".join(["/usr/share/sonic/platform",hwsku]) + return "/".join([hwsku_path, "port_config.ini"]) + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings( + self.__get_path_to_port_config_file()) + + logical_port_list = sfputil_helper.logical + logical_port_list = natsort.natsorted(logical_port_list) + name = logical_port_list[self.port_index-1] or "Unknown" + + return name + + def __validate_eeprom_sfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(0, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + checksum_test = 0 + eeprom_raw = self.read_eeprom(384, 96) + if eeprom_raw is None: + return None + + for i in range(0, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + return True + + def __validate_eeprom_qsfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(128, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + return True + + def validate_eeprom(self): + id_byte_raw = self.read_eeprom(0, 1) + if id_byte_raw is None: + return None + + id = id_byte_raw[0] + if id in self.QSFP_TYPE_CODE_LIST: + return self.__validate_eeprom_qsfp() + elif id in self.SFP_TYPE_CODE_LIST: + return self.__validate_eeprom_sfp() + else: + return False + + def validate_temperature(self): + temperature = self.get_temperature() + if temperature is None: + return None + + threshold_dict = self.get_transceiver_threshold_info() + if threshold_dict is None: + return None + + if isinstance(temperature, float) is not True: + return True + + if isinstance(threshold_dict['temphighalarm'], float) is not True: + return True + + return threshold_dict['temphighalarm'] > temperature + + def __get_error_description(self): + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + + err_stat = self.SFP_STATUS_BIT_INSERTED + + status = self.validate_eeprom() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_BAD_EEPROM) + + status = self.validate_temperature() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_HIGH_TEMP) + + if err_stat is self.SFP_STATUS_BIT_INSERTED: + return self.SFP_STATUS_OK + else: + err_desc = '' + cnt = 0 + for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT: + if (err_stat & key) != 0: + if cnt > 0: + err_desc = err_desc + "|" + cnt = cnt + 1 + err_desc = err_desc + self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT[key] + + return err_desc + + def get_reset_status(self): + if self.sfp_type == "QSFP28": + return super().get_reset_status() + return False + + def reset(self): + if self.sfp_type == "QSFP28": + return super().reset() + return False + + 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.sfp_type != "SFP28" and self.sfp_type != "QSFP28": + return "Not implemented" + try: + ret = super().get_error_description() + if ret is not None: + return ret + except NotImplementedError: + pass + return self.__get_error_description() + + def get_lpmode(self): + + lpmode = False + + if self.get_presence()==False: + return False + + device = 'PORT{}'.format(self.port_index) + output = self.pddf_obj.get_attr_name_output(device, 'xcvr_lpmode') + + if output: + status = int(output['status'].rstrip()) + + if status == 1: + lpmode = True + else: + lpmode = False + else: + xcvr_id = self._xcvr_api_factory._get_id() + + if xcvr_id is not None: + if xcvr_id == 0x18 or xcvr_id == 0x19 or xcvr_id == 0x1e: + # QSFP-DD or OSFP + # Use common SfpOptoeBase implementation for get_lpmode + lpmode = super().get_lpmode() + elif xcvr_id == 0x11 or xcvr_id == 0x0d or xcvr_id == 0x0c: + # QSFP28, QSFP+, QSFP + # get_power_set() is not defined in the optoe_base class + api = self.get_xcvr_api() + power_set = api.get_power_set() + power_override = self.get_power_override() + + return power_set if power_override else False + + return lpmode \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/thermal.py index 77d6ec7ae88..dc6ccdebfb2 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/thermal.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/sonic_platform/thermal.py @@ -3,10 +3,79 @@ try: from sonic_platform_pddf_base.pddf_thermal import PddfThermal + from .helper import DeviceThreshold except ImportError as e: raise ImportError(str(e) + "- required module not found") +NOT_AVAILABLE = DeviceThreshold.NOT_AVAILABLE +HIGH_THRESHOLD = DeviceThreshold.HIGH_THRESHOLD +LOW_THRESHOLD = DeviceThreshold.LOW_THRESHOLD +HIGH_CRIT_THRESHOLD = DeviceThreshold.HIGH_CRIT_THRESHOLD +LOW_CRIT_THRESHOLD = DeviceThreshold.LOW_CRIT_THRESHOLD + +DEFAULT_THRESHOLD = { + 'MB_temp(0x48)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CB_temp(0x4B)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'FB_temp(0x4A)' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Package_temp' : { + HIGH_THRESHOLD : '71.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '91.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_0_temp' : { + HIGH_THRESHOLD : '71.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '91.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_1_temp' : { + HIGH_THRESHOLD : '71.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '91.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_2_temp' : { + HIGH_THRESHOLD : '71.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '91.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'CPU_Core_3_temp' : { + HIGH_THRESHOLD : '71.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : '91.0', + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'PSU-1 temp sensor 1' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + }, + 'PSU-2 temp sensor 1' : { + HIGH_THRESHOLD : '80.0', + LOW_THRESHOLD : NOT_AVAILABLE, + HIGH_CRIT_THRESHOLD : NOT_AVAILABLE, + LOW_CRIT_THRESHOLD : NOT_AVAILABLE + } +} class Thermal(PddfThermal): """PDDF Platform-Specific Thermal class""" @@ -14,4 +83,205 @@ class Thermal(PddfThermal): def __init__(self, index, pddf_data=None, pddf_plugin_data=None, is_psu_thermal=False, psu_index=0): PddfThermal.__init__(self, index, pddf_data, pddf_plugin_data, is_psu_thermal, psu_index) + self.pddf_obj = pddf_data + self.thermal_obj_name = "TEMP{}".format(self.thermal_index) + self.thermal_obj = self.pddf_obj.data[self.thermal_obj_name] + + # Threshold Configuration + self.__conf = DeviceThreshold(self.get_name()) + # Default threshold. + self.__default_threshold = DEFAULT_THRESHOLD[self.get_name()] + self.min_temperature = None + self.max_temperature = None + # Provide the functions/variables below for which implementation is to be overwritten + def get_name(self): + if self.is_psu_thermal: + return "PSU-{0} temp sensor 1".format(self.thermals_psu_index) + else: + if 'dev_attr' in self.thermal_obj.keys(): + if 'display_name' in self.thermal_obj['dev_attr']: + return str(self.thermal_obj['dev_attr']['display_name']) + + # In case of errors + return "Temp sensor {0}".format(self.thermal_index) + + def get_status(self): + get_temp=self.get_temperature() + + if get_temp is not None: + return True if get_temp else False + + def get_temperature(self): + current = super().get_temperature() + + if self.min_temperature is None or \ + current < self.min_temperature: + self.min_temperature = current + + if self.max_temperature is None or \ + current > self.max_temperature: + self.max_temperature = current + + return current + + def set_high_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be more than the default value. + default_value = self.__default_threshold[HIGH_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value > float(default_value): + return False + + try: + self.__conf.set_high_threshold(str(value)) + except Exception: + return False + + return True + + def get_high_threshold(self): + value = self.__conf.get_high_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[HIGH_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + return super().get_high_threshold() + + def set_low_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be less than the default value. + default_value = self.__default_threshold[LOW_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value < float(default_value): + return False + + try: + self.__conf.set_low_threshold(str(value)) + except Exception: + return False + + return True + + def get_low_threshold(self): + value = self.__conf.get_low_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[LOW_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def set_high_critical_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be more than the default value. + default_value = self.__default_threshold[HIGH_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value > float(default_value): + return False + + try: + self.__conf.set_high_critical_threshold(str(value)) + except Exception: + return False + + return True + + def get_high_critical_threshold(self): + value = self.__conf.get_high_critical_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[HIGH_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + return super().get_high_critical_threshold() + + def set_low_critical_threshold(self, temperature): + try: + value = float(temperature) + except Exception: + return False + + # The new value can not be less than the default value. + default_value = self.__default_threshold[LOW_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + if value < float(default_value): + return False + + try: + self.__conf.set_low_critical_threshold(str(value)) + except Exception: + return False + + return True + + def get_low_critical_threshold(self): + value = self.__conf.get_low_critical_threshold() + if value != NOT_AVAILABLE: + return float(value) + + default_value = self.__default_threshold[LOW_CRIT_THRESHOLD] + if default_value != NOT_AVAILABLE: + return float(default_value) + + raise NotImplementedError + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.min_temperature is None: + self.get_temperature() + + return self.min_temperature + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.max_temperature is None: + self.get_temperature() + + return self.max_temperature diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py index 6bbaeaa06d6..5e8a5210e82 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_pddf_monitor.py @@ -207,14 +207,24 @@ def manage_fans(self): fan_fail_list[i] = 0 if sum(fan_fail_list) == NUM_FANS: + logging.critical( + 'Alarm for all fan faulty/absent is detected, disable PoE') + cmd_str = ["i2cset", "-f", "-y", "16", "0x20", "0x06", "0x0", "0x0", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xFE", "i"] + getstatusoutput_noshell(cmd_str) # Disable PoE + # Critical: Either all the fans are faulty or they are removed, shutdown the system logging.critical('Alarm for all fan faulty/absent is detected') - logging.critical("Alarm for all fan faulty/absent is detected, reset DUT") - cmd_str = ["i2cset", "-y", "-f", "3", "0x60", "0x4", "0xE4"] + logging.critical("Alarm for all fan faulty/absent is detected, shutdown DUT") + + # Sync log buffer to disk + cmd_str = ["sync"] + getstatusoutput_noshell(cmd_str) + cmd_str = ["/sbin/fstrim", "-av"] + getstatusoutput_noshell(cmd_str) + time.sleep(3) + + cmd_str = ["i2cset", "-y", "-f", "3", "0x60", "0x4", "0x74"] time.sleep(2) - getstatusoutput_noshell('sync') - getstatusoutput_noshell('sync') - getstatusoutput_noshell('sync') getstatusoutput_noshell(cmd_str) elif sum(fan_fail_list) != 0: # Set the 100% speed only for first fan failure detection @@ -243,8 +253,13 @@ def manage_fans(self): if temp[0] >= 70000: # LM77-48 # critical case*/ + logging.critical( + 'Alarm-Critical for temperature critical is detected, disable PoE') + cmd_str = ["i2cset", "-f", "-y", "16", "0x20", "0x06", "0x0", "0x0", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xff", "0xFE", "i"] + getstatusoutput_noshell(cmd_str) # Disable PoE + logging.critical('Alarm for temperature critical is detected') - logging.critical("Alarm-Critical for temperature critical is detected, reset DUT") + logging.critical("Alarm-Critical for temperature critical is detected, shutdown DUT") # Update the reboot cause file to reflect that critical temperature # has been crossed. Upon next boot, the contents of this file will # be used to determine the cause of the previous reboot @@ -255,10 +270,14 @@ def manage_fans(self): if status: logging.warning('Reboot cause file not updated. {}'.format(output)) - cmd_str = ["i2cset", "-y", "-f", "3", "0x60", "0x4", "0xE4"] - getstatusoutput_noshell('sync') - getstatusoutput_noshell('sync') - getstatusoutput_noshell('sync') + # Sync log buffer to disk + cmd_str = ["sync"] + getstatusoutput_noshell(cmd_str) + cmd_str = ["/sbin/fstrim", "-av"] + getstatusoutput_noshell(cmd_str) + time.sleep(3) + + cmd_str = ["i2cset", "-y", "-f", "3", "0x60", "0x4", "0x74"] time.sleep(3) getstatusoutput_noshell(cmd_str) diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py index b954da8726d..0c55036ddf7 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/accton_as4630_54pe_util.py @@ -16,21 +16,30 @@ # 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 +usage: accton_as4630_54pe_util.py [-h] [-d] [-f] {install,clean,api,api_clean,threshold} ... + +AS4630-54PE Platform Utility + +optional arguments: + -h, --help show this help message and exit + -d, --debug run with debug mode + -f, --force ignore error during installation or clean + +Utility Command: + {install,clean,api,api_clean,threshold} + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + api : install SONiC platform API + api_clean : uninstall SONiC platform API + threshold : modify thermal threshold """ import subprocess -import getopt import sys import logging import time import os +import argparse +from sonic_py_common.general import getstatusoutput_noshell PROJECT_NAME = 'as4630_54pe' version = '0.0.1' @@ -97,40 +106,48 @@ def main(): global DEBUG global args global FORCE + global THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH + + util_parser = argparse.ArgumentParser(description="AS4630-54PE Platform Utility") + util_parser.add_argument("-d", "--debug", dest='debug', action='store_true', default=False, + help="run with debug mode") + util_parser.add_argument("-f", "--force", dest='force', action='store_true', default=False, + help="ignore error during installation or clean") + subcommand = util_parser.add_subparsers(dest='cmd', title='Utility Command', required=True) + subcommand.add_parser('install', help=': install drivers and generate related sysfs nodes') + subcommand.add_parser('clean', help=': uninstall drivers and remove related sysfs nodes') + subcommand.add_parser('api', help=': install SONiC platform API') + subcommand.add_parser('api_clean', help=': uninstall SONiC platform API') + threshold_parser = subcommand.add_parser('threshold', help=': modify thermal threshold') + threshold_parser.add_argument("-l", dest='list', action='store_true', default=False, + help="list avaliable thermal") + threshold_parser.add_argument("-t", dest='thermal', type=str, metavar='THERMAL_NAME', + help="thermal name, ex: -t 'Temp sensor 1'") + threshold_parser.add_argument("-ht", dest='high_threshold', type=restricted_float, + metavar='THRESHOLD_VALUE', + help="high threshold: %.1f ~ %.1f" % (THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH)) + threshold_parser.add_argument("-hct", dest='high_crit_threshold', type=restricted_float, + metavar='THRESHOLD_VALUE', + help="high critical threshold : %.1f ~ %.1f" % (THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH)) + args = util_parser.parse_args() - if len(sys.argv)<2: - show_help() - - options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', - 'debug', - 'force', - ]) if DEBUG == True: - print(options) print(args) print(len(sys.argv)) - for opt, arg in options: - if opt in ('-h', '--help'): - show_help() - elif opt in ('-d', '--debug'): - DEBUG = True - logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): - FORCE = 1 - else: - logging.info('no option') - for arg in args: - if arg == 'install': - do_install() - elif arg == 'clean': - do_uninstall() - elif arg == 'api': - do_sonic_platform_install() - elif arg == 'api_clean': - do_sonic_platform_clean() - else: - show_help() + DEBUG = args.debug + FORCE = 1 if args.force else 0 + + if args.cmd == 'install': + do_install() + elif args.cmd == 'clean': + do_uninstall() + elif args.cmd == 'api': + do_sonic_platform_install() + elif args.cmd == 'api_clean': + do_sonic_platform_clean() + elif args.cmd == 'threshold': + do_threshold() return 0 @@ -382,5 +399,162 @@ def device_exist(): ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) return not(ret1 or ret2) +THRESHOLD_RANGE_LOW = 30.0 +THRESHOLD_RANGE_HIGH = 110.0 +# Code to initialize chassis object +init_chassis_code = \ + "import sonic_platform.platform\n"\ + "platform = sonic_platform.platform.Platform()\n"\ + "chassis = platform.get_chassis()\n\n" + +# Looking for thermal +looking_for_thermal_code = \ + "thermal = None\n"\ + "all_thermals = chassis.get_all_thermals()\n"\ + "for psu in chassis.get_all_psus():\n"\ + " all_thermals += psu.get_all_thermals()\n"\ + "for tmp in all_thermals:\n"\ + " if '{}' == tmp.get_name():\n"\ + " thermal = tmp\n"\ + " break\n"\ + "if thermal == None:\n"\ + " print('{} not found!')\n"\ + " exit(1)\n\n" + +def avaliable_thermals(): + global init_chassis_code + + get_all_thermal_name_code = \ + "thermal_list = []\n"\ + "all_thermals = chassis.get_all_thermals()\n"\ + "for psu in chassis.get_all_psus():\n"\ + " all_thermals += psu.get_all_thermals()\n"\ + "for tmp in all_thermals:\n"\ + " thermal_list.append(tmp.get_name())\n"\ + "print(str(thermal_list)[1:-1])\n" + + all_code = "{}{}".format(init_chassis_code, get_all_thermal_name_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + if status != 0: + return "" + return output + +def restricted_float(x): + global THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH + + try: + x = float(x) + except ValueError: + raise argparse.ArgumentTypeError("%r not a floating-point literal" % (x,)) + + if x < THRESHOLD_RANGE_LOW or x > THRESHOLD_RANGE_HIGH: + raise argparse.ArgumentTypeError("%r not in range [%.1f ~ %.1f]" % + (x, THRESHOLD_RANGE_LOW, THRESHOLD_RANGE_HIGH)) + + return x + +def get_high_threshold(name): + global init_chassis_code, looking_for_thermal_code + + get_high_threshold_code = \ + "try:\n"\ + " print(thermal.get_high_threshold())\n"\ + " exit(0)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the get_high_threshold method!')\n"\ + " exit(1)" + + all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(name, name), + get_high_threshold_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + if status == 1: + return None + + return float(output) + +def get_high_crit_threshold(name): + global init_chassis_code, looking_for_thermal_code + + get_high_crit_threshold_code = \ + "try:\n"\ + " print(thermal.get_high_critical_threshold())\n"\ + " exit(0)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the get_high_critical_threshold method!')\n"\ + " exit(1)" + + all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(name, name), + get_high_crit_threshold_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + if status == 1: + return None + + return float(output) + +def do_threshold(): + global args, init_chassis_code, looking_for_thermal_code + + if args.list: + print("Thermals: " + avaliable_thermals()) + return + + if args.thermal is None: + print("The following arguments are required: -t") + return + + set_threshold_code = "" + if args.high_threshold is not None: + if args.high_crit_threshold is not None and \ + args.high_threshold >= args.high_crit_threshold: + print("Invalid Threshold!(High threshold can not be more than " \ + "or equal to high critical threshold.)") + exit(1) + + high_crit = get_high_crit_threshold(args.thermal) + if high_crit is not None and \ + args.high_threshold >= high_crit: + print("Invalid Threshold!(High threshold can not be more than " \ + "or equal to high critical threshold.)") + exit(1) + + set_threshold_code += \ + "try:\n"\ + " if thermal.set_high_threshold({}) is False:\n"\ + " print('{}: set_high_threshold failure!')\n"\ + " exit(1)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the set_high_threshold method!')\n"\ + "print('Apply the new high threshold successfully.')\n"\ + "\n".format(args.high_threshold, args.thermal) + + if args.high_crit_threshold is not None: + high = get_high_threshold(args.thermal) + if high is not None and \ + args.high_crit_threshold <= high: + print("Invalid Threshold!(High critical threshold can not " \ + "be less than or equal to high threshold.)") + exit(1) + + set_threshold_code += \ + "try:\n"\ + " if thermal.set_high_critical_threshold({}) is False:\n"\ + " print('{}: set_high_critical_threshold failure!')\n"\ + " exit(1)\n"\ + "except NotImplementedError:\n"\ + " print('Not implement the set_high_critical_threshold method!')\n"\ + "print('Apply the new high critical threshold successfully.')\n"\ + "\n".format(args.high_crit_threshold, args.thermal) + + if set_threshold_code == "": + return + + all_code = "{}{}{}".format(init_chassis_code, looking_for_thermal_code.format(args.thermal, args.thermal), set_threshold_code) + + status, output = getstatusoutput_noshell(["docker", "exec", "pmon", "python3", "-c", all_code]) + print(output) + if __name__ == "__main__": main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/handle_mgmt_interface.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/handle_mgmt_interface.sh index e1acd16a016..19eae1716db 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/handle_mgmt_interface.sh +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/handle_mgmt_interface.sh @@ -1,9 +1,7 @@ #!/bin/bash -#Due to the hardware design, as4630-54pe use "eth2" instead of "eth0" as management interface. -#Rename netdev "eth0" and "eth2" to swap original "eth2" to "eth0". - -ifconfig eth0 down -ip link set eth0 name eth3 -ip link set eth2 name eth0 -ifconfig eth0 up +# Re-install the igb and ixgbe again to make the NIC sequence follow the udev rule +modprobe -r igb +modprobe -r ixgbe +modprobe igb +modprobe ixgbe diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh index d820352ac7e..fcff78fd0bd 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54pe/utils/pddf_post_device_create.sh @@ -11,4 +11,8 @@ stk_val=$(i2cget -y -f 3 0x60 0x31) new_val=$((${stk_val}|0x30)) i2cset -y -f 3 0x60 0x31 ${new_val} echo "STK LEDs are turned off successfully" - +insmod_jc42_drv() +{ + modprobe jc42 &>/dev/null +} +insmod_jc42_drv() diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_api.h b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_api.h new file mode 100644 index 00000000000..d522979f1e8 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_api.h @@ -0,0 +1,29 @@ +/* + * Copyright 2022 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Description: + * PSU driver related api declarations + */ + +#ifndef ACCTON_PSU_API_H +#define ACCTON_PSU_API_H + +#include "accton_psu_defs.h" + +/** Description: + * Register psu status entry, set entry as NULL to unregister + */ +extern int register_psu_status_entry(PSU_STATUS_ENTRY *entry); + +#endif /* ACCTON_PSU_API_H */ diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_defs.h b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_defs.h new file mode 100644 index 00000000000..11bb253a573 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/accton_psu_defs.h @@ -0,0 +1,28 @@ +/* + * Copyright 2022 Accton Technology Corporation. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * + * Description: + * Platform PSU defines/structures header file + */ + +#ifndef ACCTON_PSU_DEFS_H +#define ACCTON_PSU_DEFS_H + +typedef struct PSU_STATUS_ENTRY +{ + int (*get_presence)(void *client); + int (*get_powergood)(void *client); +} PSU_STATUS_ENTRY; + +#endif /* ACCTON_PSU_DEFS_H */ diff --git a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c index 4708d825f45..2f5a1234c6e 100755 --- a/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c +++ b/platform/broadcom/sonic-platform-modules-accton/common/modules/ym2651y.c @@ -31,29 +31,87 @@ #include #include #include +#include +#include +#include "accton_psu_defs.h" +#define __STDC_WANT_LIB_EXT1__ 1 +#include #define MAX_FAN_DUTY_CYCLE 100 +#define ACCESS_INTERVAL_MAX 120 +#define ACCESS_INTERVAL_YM1151D_DEFAULT 60 +#define REFRESH_INTERVAL_SECOND 3 +#define REFRESH_INTERVAL_MSEC (REFRESH_INTERVAL_SECOND * 1000) +#define REFRESH_INTERVAL_HZ (REFRESH_INTERVAL_SECOND * HZ) + +/* STATUS WORD BIT MAP + * + * BIT 0(Low Byte): NONE OF THE ABOVE + * BIT 1(Low Byte): COMM, MEMORY, LOGIC EVENT + * BIT 2(Low Byte): TEMPERATURE FAULT OR WARNING + * BIT 3(Low Byte): VIN_UV_FAULT + * BIT 4(Low Byte): IOUT_OC_FAULT + * BIT 5(Low Byte): VOUT_OV_FAULT + * BIT 6(Low Byte): UNIT IS OFF + * BIT 7(Low Byte): UNIT WAS BUSY + * + * BIT 8(High Byte): UNKNOWN FAULT OR WARNING + * BIT 9(High Byte): OTHER + * BIT10(High Byte): FAN FAULT OR WARNING + * BIT11(High Byte): POWER_GOOD Negated + * BIT12(High Byte): MFR_SPECIFIC + * BIT13(High Byte): INPUT FAULT OR WARNING + * BIT14(High Byte): IOUT/POUT FAULT OR WARNING + * BIT15(High Byte): VOUT FAULT OR WARNING + */ +#define STATUS_WORD_CHECKER_INPUT (BIT(3) | BIT(6) | BIT(11) | BIT(13)) +#define STATUS_WORD_CHECKER_VOUT (BIT(5) | BIT(15) | STATUS_WORD_CHECKER_INPUT) +#define STATUS_WORD_CHECKER_IOUT (BIT(4) | BIT(14) | STATUS_WORD_CHECKER_INPUT) +#define STATUS_WORD_CHECKER_POUT (BIT(14) | STATUS_WORD_CHECKER_INPUT) + +#define EXIT_IF_POWER_FAILED(c) \ + do { \ + if (ym2651y_is_powergood(c) != 1) \ + goto exit; \ + } while (0) + +#define SLEEP_IF_INTERVAL(pInterval) \ + do { \ + int interval = atomic_read(pInterval); \ + if (interval > 0) \ + msleep(interval); \ + } while (0) + +/* SLEEP_IF_INTERVAL should be called before EXIT_IF_POWER_FAILED. + * It is known that accessing PSU when power failed might cause problems. + * So it is better to do sleep before checking power status because it avoids + * the risk that power status changes to failed during the sleep period. + */ +#define VALIDATE_POWERGOOD_AND_INTERVAL(client, pInterval) \ + do { \ + SLEEP_IF_INTERVAL(pInterval); \ + EXIT_IF_POWER_FAILED(client); \ + } while (0) + +struct mutex entry_lock; +PSU_STATUS_ENTRY access_psu_status = { NULL, NULL }; /* Addresses scanned */ -static const unsigned short normal_i2c[] = { 0x58, 0x5b, I2C_CLIENT_END }; +static const unsigned short normal_i2c[] = { 0x58, 0x59, 0x5b, I2C_CLIENT_END }; enum chips { - YM2651, - YM2401, - YM2851, - YM1401A, - YPEB1200AM + YM2651, + YM2401, + YM2851, + YM1401A, + YPEB1200AM, + YM1151D, + UMEC_UPD150SA, + UMEC_UP1K21R }; -/* Each client has this additional data - */ -struct ym2651y_data { - struct device *hwmon_dev; - struct mutex update_lock; - char valid; /* !=0 if registers are valid */ - unsigned long last_updated; /* In jiffies */ - u8 chip; /* chip id */ +struct pmbus_register_value { u8 capability; /* Register value */ u16 status_word; /* Register value */ u8 fan_fault; /* Register value */ @@ -62,15 +120,15 @@ 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 */ u8 pmbus_revision; /* Register value */ u8 mfr_serial[21]; /* Register value */ u8 mfr_id[10]; /* Register value */ - u8 mfr_model[16]; /* Register value */ - u8 mfr_revsion[3]; /* Register value */ + u8 mfr_model[18]; /* Register value */ + u8 mfr_revsion[10]; /* Register value */ u16 mfr_vin_min; /* Register value */ u16 mfr_vin_max; /* Register value */ u16 mfr_iin_max; /* Register value */ @@ -81,6 +139,23 @@ struct ym2651y_data { u16 mfr_vout_max; /* Register value */ }; +typedef int (*range_checker_t)(u16 reg_val, struct pmbus_register_value*); + +/* Each client has this additional data + */ +struct ym2651y_data { + struct device *hwmon_dev; + struct mutex update_lock; + struct task_struct *update_task; + struct completion update_stop; + atomic_t access_interval; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 chip; /* chip id */ + u8 mfr_serial_supported; + struct pmbus_register_value reg_val; +}; + static ssize_t show_vout(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_byte(struct device *dev, struct device_attribute *da, @@ -95,7 +170,14 @@ static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, char *buf); static ssize_t show_ascii(struct device *dev, struct device_attribute *da, char *buf); -static struct ym2651y_data *ym2651y_update_device(struct device *dev); +static ssize_t show_interval(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_interval(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static int mfr_serial_supported(u8 chip); +static int ym2651y_update_device(struct i2c_client *client, + struct pmbus_register_value *data); +static int ym2651y_update_thread(void *arg); static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count); static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value); @@ -112,6 +194,8 @@ enum ym2651y_sysfs_attributes { PSU_P_OUT, PSU_P_OUT_UV, /*In Unit of microVolt, instead of mini.*/ PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, PSU_FAN1_SPEED, PSU_FAN1_DUTY_CYCLE, PSU_PMBUS_REVISION, @@ -127,7 +211,8 @@ enum ym2651y_sysfs_attributes { PSU_MFR_IIN_MAX, PSU_MFR_IOUT_MAX, PSU_MFR_PIN_MAX, - PSU_MFR_POUT_MAX + PSU_MFR_POUT_MAX, + PSU_ACCESS_INTERVAL }; /* sysfs attributes for hwmon @@ -141,6 +226,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); @@ -152,20 +239,25 @@ static SENSOR_DEVICE_ATTR(psu_mfr_revision, S_IRUGO, show_ascii, NULL, PSU_MF static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL); static SENSOR_DEVICE_ATTR(psu_mfr_vin_min, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MIN); static SENSOR_DEVICE_ATTR(psu_mfr_vin_max, S_IRUGO, show_linear, NULL, PSU_MFR_VIN_MAX); -static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MIN); -static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_linear, NULL, PSU_MFR_VOUT_MAX); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_min, S_IRUGO, show_vout, NULL, PSU_MFR_VOUT_MIN); +static SENSOR_DEVICE_ATTR(psu_mfr_vout_max, S_IRUGO, show_vout, NULL, PSU_MFR_VOUT_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_iin_max, S_IRUGO, show_linear, NULL, PSU_MFR_IIN_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_iout_max, S_IRUGO, show_linear, NULL, PSU_MFR_IOUT_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_pin_max, S_IRUGO, show_linear, NULL, PSU_MFR_PIN_MAX); static SENSOR_DEVICE_ATTR(psu_mfr_pout_max, S_IRUGO, show_linear, NULL, PSU_MFR_POUT_MAX); +static SENSOR_DEVICE_ATTR(psu_access_interval, S_IWUSR | S_IRUGO, show_interval, set_interval, PSU_ACCESS_INTERVAL); /*Duplicate nodes for lm-sensors.*/ static SENSOR_DEVICE_ATTR(in3_input, S_IRUGO, show_vout, NULL, PSU_V_OUT); static SENSOR_DEVICE_ATTR(curr2_input, S_IRUGO, show_linear, NULL, PSU_I_OUT); static SENSOR_DEVICE_ATTR(power2_input, S_IRUGO, show_linear, NULL, PSU_P_OUT_UV); static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_linear, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_linear, NULL, PSU_TEMP3_INPUT); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); static SENSOR_DEVICE_ATTR(temp1_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(temp2_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); +static SENSOR_DEVICE_ATTR(temp3_fault, S_IRUGO, show_word, NULL, PSU_TEMP_FAULT); static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_power_on.dev_attr.attr, @@ -177,6 +269,8 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_i_out.dev_attr.attr, &sensor_dev_attr_psu_p_out.dev_attr.attr, &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, &sensor_dev_attr_psu_fan1_duty_cycle_percentage.dev_attr.attr, &sensor_dev_attr_psu_fan_dir.dev_attr.attr, @@ -194,13 +288,18 @@ static struct attribute *ym2651y_attributes[] = { &sensor_dev_attr_psu_mfr_vout_min.dev_attr.attr, &sensor_dev_attr_psu_mfr_vout_max.dev_attr.attr, &sensor_dev_attr_psu_mfr_iout_max.dev_attr.attr, + &sensor_dev_attr_psu_access_interval.dev_attr.attr, /*Duplicate nodes for lm-sensors.*/ &sensor_dev_attr_curr2_input.dev_attr.attr, &sensor_dev_attr_in3_input.dev_attr.attr, &sensor_dev_attr_power2_input.dev_attr.attr, &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, &sensor_dev_attr_fan1_input.dev_attr.attr, &sensor_dev_attr_temp1_fault.dev_attr.attr, + &sensor_dev_attr_temp2_fault.dev_attr.attr, + &sensor_dev_attr_temp3_fault.dev_attr.attr, NULL }; @@ -208,32 +307,59 @@ static ssize_t show_byte(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + u8 status = 0; - return (attr->index == PSU_PMBUS_REVISION) ? sprintf(buf, "%d\n", data->pmbus_revision) : - sprintf(buf, "0\n"); + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + + if (attr->index == PSU_PMBUS_REVISION) + status = data->reg_val.pmbus_revision; + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_word(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); u16 status = 0; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + switch (attr->index) { case PSU_POWER_ON: /* psu_power_on, low byte bit 6 of status_word, 0=>ON, 1=>OFF */ - status = (data->status_word & 0x40) ? 0 : 1; + status = (data->reg_val.status_word & 0x40) ? 0 : 1; break; case PSU_TEMP_FAULT: /* psu_temp_fault, low byte bit 2 of status_word, 0=>Normal, 1=>temp fault */ - status = (data->status_word & 0x4) >> 2; + status = (data->reg_val.status_word & 0x4) >> 2; break; case PSU_POWER_GOOD: /* psu_power_good, high byte bit 3 of status_word, 0=>OK, 1=>FAIL */ - status = (data->status_word & 0x800) ? 0 : 1; + status = (data->reg_val.status_word & 0x800) ? 0 : 1; break; + default: + goto exit; } + mutex_unlock(&data->update_lock); return sprintf(buf, "%d\n", status); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static int two_complement_to_int(u16 data, u8 valid_bit, int mask) @@ -244,6 +370,87 @@ static int two_complement_to_int(u16 data, u8 valid_bit, int mask) return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; } +int pmbus_linear_format_to_int(u16 reg_val, int multiplier) +{ + int exponent, mantissa; + + exponent = two_complement_to_int(reg_val >> 11, 5, 0x1f); + mantissa = two_complement_to_int(reg_val & 0x7ff, 11, 0x7ff); + + return (exponent >= 0) ? ((mantissa << exponent) * multiplier) : + ((mantissa * multiplier) / (1 << -exponent)); +} + +int pmbus_vout_data_to_int(u16 reg_val, u8 vout_mode, int multiplier) +{ + int exponent, mantissa; + + exponent = two_complement_to_int(vout_mode, 5, 0x1f); + mantissa = reg_val; + + return (exponent > 0) ? ((mantissa << exponent) * multiplier) : + ((mantissa * multiplier) / (1 << -exponent)); +} + +int vout_range_checker(u16 reg_val, struct pmbus_register_value *data) +{ + int vout = 0; + int vout_max = 0; + int vout_min = 0; + + if ((data->vout_mode & 0xE0) == 0) { /* ULINEAR16 Format */ + vout = pmbus_vout_data_to_int(reg_val, data->vout_mode, 1000); + vout_max = pmbus_vout_data_to_int(data->mfr_vout_max, data->vout_mode, 1000); + vout_min = pmbus_vout_data_to_int(data->mfr_vout_min, data->vout_mode, 1000); + } + else { + vout = pmbus_linear_format_to_int(reg_val, 1000); + vout_max = pmbus_linear_format_to_int(data->mfr_vout_max, 1000); + vout_min = pmbus_linear_format_to_int(data->mfr_vout_min, 1000); + } + + return ((vout <= vout_max) && (vout >= vout_min)) ? 0 : -EINVAL;; +} + +int iout_range_checker(u16 reg_val, struct pmbus_register_value *data) +{ + int iout = pmbus_linear_format_to_int(reg_val, 1000); + int iout_max = pmbus_linear_format_to_int(data->mfr_iout_max, 1000); + + return ((iout > 0) && (iout <= iout_max)) ? 0 : -EINVAL; +} + +int pout_range_checker(u16 reg_val, struct pmbus_register_value *data) +{ + int pout = pmbus_linear_format_to_int(reg_val, 1000); + int pout_max = pmbus_linear_format_to_int(data->mfr_pout_max, 1000); + + return ((pout > 0) && (pout <= pout_max)) ? 0 : -EINVAL; +} + +int enable_status_range_checker(struct pmbus_register_value *data) +{ + int i; + char *model_list[] = { + "YM-2651Y", "YM-1151D", "YM-1151E", + "YM-1401A", "YM-2401H", "YM-2651V", + "YM-2851F", "YM-2851J", "YM-1151F", "YPEB1200AM" + }; + + if (!data) { + return 0; + } + + for (i = 0; i < ARRAY_SIZE(model_list); i++) { + if (strncmp(model_list[i], data->mfr_model+1, strlen(model_list[i])) != 0) { + continue; + } + return 1; + } + + return 0; +} + static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *da, const char *buf, size_t count) { @@ -262,8 +469,8 @@ static ssize_t set_fan_duty_cycle(struct device *dev, struct device_attribute *d return -EINVAL; mutex_lock(&data->update_lock); - data->fan_duty_cycle[nr] = speed; - ym2651y_write_word(client, 0x3B + nr, data->fan_duty_cycle[nr]); + data->reg_val.fan_duty_cycle[nr] = speed; + ym2651y_write_word(client, 0x3B + nr, data->reg_val.fan_duty_cycle[nr]); mutex_unlock(&data->update_lock); return count; @@ -273,151 +480,214 @@ static ssize_t show_linear(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); - + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); u16 value = 0; int exponent, mantissa; int multiplier = 1000; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + switch (attr->index) { case PSU_V_OUT: - value = data->v_out; + value = data->reg_val.v_out; break; case PSU_I_OUT: - value = data->i_out; + value = data->reg_val.i_out; break; case PSU_P_OUT_UV: multiplier = 1000000; /*For lm-sensors, unit is micro-Volt.*/ /*Passing through*/ case PSU_P_OUT: - value = data->p_out; + value = data->reg_val.p_out; break; case PSU_TEMP1_INPUT: - value = data->temp; + case PSU_TEMP2_INPUT: + case PSU_TEMP3_INPUT: + value = data->reg_val.temp_input[attr->index - PSU_TEMP1_INPUT]; break; case PSU_FAN1_SPEED: - value = data->fan_speed; + value = data->reg_val.fan_speed; multiplier = 1; break; case PSU_FAN1_DUTY_CYCLE: - value = data->fan_duty_cycle[0]; + value = data->reg_val.fan_duty_cycle[0]; multiplier = 1; break; case PSU_MFR_VIN_MIN: - value = data->mfr_vin_min; + value = data->reg_val.mfr_vin_min; break; case PSU_MFR_VIN_MAX: - value = data->mfr_vin_max; + value = data->reg_val.mfr_vin_max; break; case PSU_MFR_VOUT_MIN: - value = data->mfr_vout_min; + value = data->reg_val.mfr_vout_min; break; case PSU_MFR_VOUT_MAX: - value = data->mfr_vout_max; + value = data->reg_val.mfr_vout_max; break; case PSU_MFR_PIN_MAX: - value = data->mfr_pin_max; + value = data->reg_val.mfr_pin_max; break; case PSU_MFR_POUT_MAX: - value = data->mfr_pout_max; + value = data->reg_val.mfr_pout_max; break; case PSU_MFR_IOUT_MAX: - value = data->mfr_iout_max; + value = data->reg_val.mfr_iout_max; break; case PSU_MFR_IIN_MAX: - value = data->mfr_iin_max; + value = data->reg_val.mfr_iin_max; break; + default: + goto exit; } + mutex_unlock(&data->update_lock); exponent = two_complement_to_int(value >> 11, 5, 0x1f); mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_fan_fault(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + u8 shift = 0; + u8 fan_fault = 0; - u8 shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + + fan_fault = data->reg_val.fan_fault; + mutex_unlock(&data->update_lock); - return sprintf(buf, "%d\n", data->fan_fault >> shift); + shift = (attr->index == PSU_FAN1_FAULT) ? 7 : 6; + return sprintf(buf, "%d\n", fan_fault >> shift); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_over_temp(struct device *dev, struct device_attribute *da, char *buf) { - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + u8 over_temp = 0; - return sprintf(buf, "%d\n", data->over_temp >> 7); + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + + over_temp = data->reg_val.over_temp; + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", over_temp >> 7); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_ascii(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + ssize_t ret = 0; u8 *ptr = NULL; + mutex_lock(&data->update_lock); + if (!data->valid) { + goto exit; + } + switch (attr->index) { case PSU_FAN_DIRECTION: /* psu_fan_dir */ if (data->chip==YPEB1200AM) { - memcpy(data->fan_dir, "F2B", 3); - data->fan_dir[3]='\0'; + #ifdef __STDC_LIB_EXT1__ + memcpy_s(data->reg_val.fan_dir, 3, "F2B", 3); + #else + memcpy(data->reg_val.fan_dir, "F2B", 3); + #endif + data->reg_val.fan_dir[3]='\0'; } - ptr = data->fan_dir; + ptr = data->reg_val.fan_dir; break; case PSU_MFR_SERIAL: /* psu_mfr_serial */ - ptr = data->mfr_serial+1; /* The first byte is the count byte of string. */ + ptr = data->reg_val.mfr_serial+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_ID: /* psu_mfr_id */ - ptr = data->mfr_id+1; /* The first byte is the count byte of string. */ + ptr = data->reg_val.mfr_id+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_MODEL: /* psu_mfr_model */ - ptr = data->mfr_model+1; /* The first byte is the count byte of string. */ + ptr = data->reg_val.mfr_model+1; /* The first byte is the count byte of string. */ break; case PSU_MFR_REVISION: /* psu_mfr_revision */ - ptr = data->mfr_revsion+1; + ptr = data->reg_val.mfr_revsion+1; break; default: - return 0; + goto exit; } - return sprintf(buf, "%s\n", ptr); + ret = sprintf(buf, "%s\n", ptr); + +exit: + mutex_unlock(&data->update_lock); + return ret; } static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); - struct ym2651y_data *data = ym2651y_update_device(dev); + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); int exponent, mantissa; int multiplier = 1000; + mutex_lock(&data->update_lock); if (!data->valid) { - return 0; + goto exit; } - exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + exponent = two_complement_to_int(data->reg_val.vout_mode, 5, 0x1f); switch (attr->index) { case PSU_MFR_VOUT_MIN: - mantissa = data->mfr_vout_min; + mantissa = data->reg_val.mfr_vout_min; break; case PSU_MFR_VOUT_MAX: - mantissa = data->mfr_vout_max; + mantissa = data->reg_val.mfr_vout_max; break; case PSU_V_OUT: - mantissa = data->v_out; + mantissa = data->reg_val.v_out; break; default: - return 0; + goto exit; } + mutex_unlock(&data->update_lock); return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : - sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); + +exit: + mutex_unlock(&data->update_lock); + return 0; } static ssize_t show_vout(struct device *dev, struct device_attribute *da, @@ -426,14 +696,50 @@ static ssize_t show_vout(struct device *dev, struct device_attribute *da, struct i2c_client *client = to_i2c_client(dev); struct ym2651y_data *data = i2c_get_clientdata(client); - if (data->chip == YM2401 || data->chip==YM1401A) { - return show_vout_by_mode(dev, da, buf); + if ( (!strncmp("SPAACTN-01", data->reg_val.mfr_model+1, strlen("SPAACTN-01"))) || + (!strncmp("SPAACTN-02", data->reg_val.mfr_model+1, strlen("SPAACTN-02"))) ) + { + return show_linear(dev, da, buf); + } + else if (data->chip == YM2401 || data->chip==YM1401A || + (!strncmp("UPD1501SA-1190G", data->reg_val.mfr_model + 1, strlen("UPD1501SA-1190G"))) || + (!strncmp("UPD1501SA-1290G", data->reg_val.mfr_model + 1, strlen("UPD1501SA-1290G"))) || + (!strncmp("UP1K21R-1085G", data->reg_val.mfr_model + 1, strlen("UP1K21R-1085G")))) { + return show_vout_by_mode(dev, da, buf); /*format: linear16*/ } else { return show_linear(dev, da, buf); } } +static ssize_t show_interval(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + return sprintf(buf, "%d\n", atomic_read(&data->access_interval)); +} + +static ssize_t set_interval(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + long interval; + struct i2c_client *client = to_i2c_client(dev); + struct ym2651y_data *data = i2c_get_clientdata(client); + + status = kstrtol(buf, 10, &interval); + if (status) + return status; + + if (interval < 0 || interval > ACCESS_INTERVAL_MAX) + return -EINVAL; + + atomic_set(&data->access_interval, (int)interval); + return count; +} + static const struct attribute_group ym2651y_group = { .attrs = ym2651y_attributes, }; @@ -461,6 +767,7 @@ static int ym2651y_probe(struct i2c_client *client, i2c_set_clientdata(client, data); mutex_init(&data->update_lock); data->chip = dev_id->driver_data; + data->mfr_serial_supported = mfr_serial_supported(data->chip); dev_info(&client->dev, "chip found\n"); /* Register sysfs hooks */ @@ -475,11 +782,26 @@ static int ym2651y_probe(struct i2c_client *client, goto exit_remove; } + /* create update thread */ + if (data->chip == YM1151D) + atomic_set(&data->access_interval, ACCESS_INTERVAL_YM1151D_DEFAULT); + else + atomic_set(&data->access_interval, 0); + + init_completion(&data->update_stop); + data->update_task = kthread_run(ym2651y_update_thread, client, "ym2651y_update_task"); + if (IS_ERR(data->update_task)) { + dev_dbg(&client->dev, "Failed to create ym2651y update task!\n"); + goto exit_hwmon; + } + dev_info(&client->dev, "%s: psu '%s'\n", dev_name(data->hwmon_dev), client->name); return 0; +exit_hwmon: + hwmon_device_unregister(data->hwmon_dev); exit_remove: sysfs_remove_group(&client->dev.kobj, &ym2651y_group); exit_free: @@ -493,10 +815,13 @@ static void ym2651y_remove(struct i2c_client *client) { struct ym2651y_data *data = i2c_get_clientdata(client); + /* Stop update task */ + kthread_stop(data->update_task); + wait_for_completion(&data->update_stop); + hwmon_device_unregister(data->hwmon_dev); sysfs_remove_group(&client->dev.kobj, &ym2651y_group); kfree(data); - } static const struct i2c_device_id ym2651y_id[] = { @@ -505,6 +830,9 @@ static const struct i2c_device_id ym2651y_id[] = { { "ym2851", YM2851 }, { "ym1401a",YM1401A}, { "ype1200am", YPEB1200AM }, + { "ym1151d", YM1151D }, + { "umec_upd150sa", UMEC_UPD150SA }, + { "umec_up1k21r", UMEC_UP1K21R }, {} }; MODULE_DEVICE_TABLE(i2c, ym2651y_id); @@ -520,6 +848,23 @@ static struct i2c_driver ym2651y_driver = { .address_list = normal_i2c, }; +static int ym2651y_is_powergood(struct i2c_client *client) +{ + int powergood = 0; + + mutex_lock(&entry_lock); + if (access_psu_status.get_powergood == NULL) { + powergood = 1; /* skip powergood validation if API is not registered */ + goto exit; + } + + powergood = access_psu_status.get_powergood(client); + +exit: + mutex_unlock(&entry_lock); + return powergood; +} + static int ym2651y_read_byte(struct i2c_client *client, u8 reg) { return i2c_smbus_read_byte_data(client, reg); @@ -538,8 +883,9 @@ static int ym2651y_write_word(struct i2c_client *client, u8 reg, u16 value) static int ym2651y_read_block(struct i2c_client *client, u8 command, u8 *data, int data_len) { - int result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + int result; + result = i2c_smbus_read_i2c_block_data(client, command, data_len, data); if (unlikely(result < 0)) goto abort; if (unlikely(result != data_len)) { @@ -561,183 +907,362 @@ struct reg_data_byte { struct reg_data_word { u8 reg; u16 *value; + u16 old_value; + u16 status_checker; + range_checker_t range_checker; }; -static struct ym2651y_data *ym2651y_update_device(struct device *dev) +static char *get_fan_dir_by_model_name(struct i2c_client *client, char *ptr_model, char *fan_dir, int command) { - struct i2c_client *client = to_i2c_client(dev); - struct ym2651y_data *data = i2c_get_clientdata(client); - - mutex_lock(&data->update_lock); + int status; + char *ptr_fan; + + ptr_fan = fan_dir; + + if ( (!strncmp("FSJ001", ptr_model+1, strlen("FSJ001"))) || + (!strncmp("FSJ004", ptr_model+1, strlen("FSJ004"))) || + (!strncmp("SPAACTN-01", ptr_model+1, strlen("SPAACTN-01"))) || + (!strncmp("SPAACTN-02", ptr_model+1, strlen("SPAACTN-02"))) || + (!strncmp("UPD1501SA-1279G", ptr_model+1, strlen("UPD1501SA-1279G"))) || + (!strncmp("UP1K21R-1085G", ptr_model+1, strlen("UP1K21R-1085G"))) ) + { + /* Not add function: VALIDATE_POWERGOOD_AND_INTERVAL() because, + * when these PSU modules power_good are fail, + * they did not have any error happen on it when accessed them. */ + status = ym2651y_read_byte(client, command); - if (time_after(jiffies, data->last_updated + HZ + HZ / 2) - || !data->valid) { - int i, status, length; - u8 command, buf; - u8 fan_dir[5] = {0}; - struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, - {0x20, &data->vout_mode}, - {0x7d, &data->over_temp}, - {0x81, &data->fan_fault}, - {0x98, &data->pmbus_revision} - }; - struct reg_data_word regs_word[] = { {0x79, &data->status_word}, - {0x8b, &data->v_out}, - {0x8c, &data->i_out}, - {0x96, &data->p_out}, - {0x8d, &data->temp}, - {0x3b, &(data->fan_duty_cycle[0])}, - {0x3c, &(data->fan_duty_cycle[1])}, - {0x90, &data->fan_speed}, - {0xa0, &data->mfr_vin_min}, - {0xa1, &data->mfr_vin_max}, - {0xa2, &data->mfr_iin_max}, - {0xa3, &data->mfr_pin_max}, - {0xa4, &data->mfr_vout_min}, - {0xa5, &data->mfr_vout_max}, - {0xa6, &data->mfr_iout_max}, - {0xa7, &data->mfr_pout_max} - }; - - dev_dbg(&client->dev, "Starting ym2651 update\n"); - - /* Read byte data */ - for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { - status = ym2651y_read_byte(client, regs_byte[i].reg); - - if (status < 0) + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + ptr_fan = NULL; + } + else + { + u16 B2F_flag = 0x01; /*BIT[4:3]=01: AFI*/ + u16 F2B_flag = 0x02; /*BIT[4:3]=10: AFO*/ + if( (status >> 3)& B2F_flag) + { + memcpy(fan_dir, "B2F", 3); + } + else if( (status >> 3)& F2B_flag) { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_byte[i].reg, status); - *(regs_byte[i].value) = 0; - goto exit; + memcpy(fan_dir, "F2B", 3); } else { - *(regs_byte[i].value) = status; + ptr_fan = NULL; } } + } + else if (!strncmp("FSJ035", ptr_model+1, strlen("FSJ035")) || + !strncmp("UPD1501SA-1190G", ptr_model+1, strlen("UPD1501SA-1190G"))) /*hard code: spec do not define*/ + { + memcpy(fan_dir, "F2B", 3); + } + else if (!strncmp("FSJ036", ptr_model+1, strlen("FSJ036")) || + !strncmp("UPD1501SA-1290G", ptr_model+1, strlen("UPD1501SA-1290G"))) /*hard code: spec do not define*/ + { + memcpy(fan_dir, "B2F", 3); + } + else + { + ptr_fan = NULL; + } + + dev_dbg(&client->dev, "Model name is %s, get by read_word is (%s)\n", + ptr_model+1, ptr_fan ? ptr_fan : "NULL"); + return ptr_fan; +} +static int ym2651y_update_device(struct i2c_client *client, + struct pmbus_register_value *data) +{ + struct ym2651y_data *driver_data = i2c_get_clientdata(client); + int i, status, length; + u8 command, buf; + u8 fan_dir[5] = {0}; + int enable_checker = 0; + struct reg_data_byte regs_byte[] = { {0x19, &data->capability}, + {0x20, &data->vout_mode}, + {0x7d, &data->over_temp}, + {0x81, &data->fan_fault}, + {0x98, &data->pmbus_revision} + }; + struct reg_data_word regs_word[] = { + /* The mfr_* and status_word should be read + * before reading the data with a status/range checker + */ + {0x79, &data->status_word, 0, 0, NULL}, + {0x8d, &(data->temp_input[0]), 0, 0, NULL}, + {0x8e, &(data->temp_input[1]), 0, 0, NULL}, + {0x8f, &(data->temp_input[2]), 0, 0, NULL}, + {0x3b, &(data->fan_duty_cycle[0]), 0, 0, NULL}, + {0x3c, &(data->fan_duty_cycle[1]), 0, 0, NULL}, + {0x90, &data->fan_speed, 0, 0, NULL}, + {0xa0, &data->mfr_vin_min, 0, 0, NULL}, + {0xa1, &data->mfr_vin_max, 0, 0, NULL}, + {0xa2, &data->mfr_iin_max, 0, 0, NULL}, + {0xa3, &data->mfr_pin_max, 0, 0, NULL}, + {0xa4, &data->mfr_vout_min, 0, 0, NULL}, + {0xa5, &data->mfr_vout_max, 0, 0, NULL}, + {0xa6, &data->mfr_iout_max, 0, 0, NULL}, + {0xa7, &data->mfr_pout_max, 0, 0, NULL}, + {0x8b, &data->v_out, driver_data->reg_val.v_out, STATUS_WORD_CHECKER_VOUT, vout_range_checker}, + {0x8c, &data->i_out, driver_data->reg_val.i_out, STATUS_WORD_CHECKER_IOUT, iout_range_checker}, + {0x96, &data->p_out, driver_data->reg_val.p_out, STATUS_WORD_CHECKER_POUT, pout_range_checker} + }; + + dev_dbg(&client->dev, "Starting ym2651 update\n"); + + /* Read byte data */ + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + + status = ym2651y_read_byte(client, regs_byte[i].reg); + if (status < 0) + { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + *(regs_byte[i].value) = 0; + goto exit; + } + else { + *(regs_byte[i].value) = status; + } + } - /* Read word data */ - for (i = 0; i < ARRAY_SIZE(regs_word); i++) { - status = ym2651y_read_word(client, regs_word[i].reg); + /* Read mfr_model */ + command = 0x9a; + length = 1; + /* Read first byte to determine the length of data */ + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_block(client, command, &buf, length); + if (status == 0 && buf != 0xFF) { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_block(client, command, data->mfr_model, buf+1); + if (status == 0) { + if ((buf+1) >= (ARRAY_SIZE(data->mfr_model)-1)) + data->mfr_model[ARRAY_SIZE(data->mfr_model)-1] = '\0'; + else + data->mfr_model[buf+1] = '\0'; + } + } - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", - regs_word[i].reg, status); - *(regs_word[i].value) = 0; - goto exit; - } - else { - *(regs_word[i].value) = status; + /* Read word data */ + enable_checker = enable_status_range_checker(data); + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + + /* To prevent hardware errors, + access to temp2_input and temp3_input should be skipped + if the chip ID is not in the following list. */ + if (regs_word[i].reg == 0x8e || regs_word[i].reg == 0x8f) { + if (driver_data->chip != UMEC_UPD150SA && + driver_data->chip != UMEC_UP1K21R) { + continue; } } - /* Read fan_direction */ - command = 0xC3; - status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1); - + status = ym2651y_read_word(client, regs_word[i].reg); if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + *(regs_word[i].value) = 0; goto exit; } + else { + if ((enable_checker == 0) || (regs_word[i].status_checker == 0)) { + *(regs_word[i].value) = status; + continue; + } - strncpy(data->fan_dir, fan_dir+1, ARRAY_SIZE(data->fan_dir)-1); - data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + /* Validate data range */ + if (regs_word[i].range_checker && + regs_word[i].range_checker(status, data) < 0) { + if (!(data->status_word & regs_word[i].status_checker)) { + /* Drop the data because it is out of the + * expected range and the status bit is not set. + * Keep old_value instead. + */ + *(regs_word[i].value) = regs_word[i].old_value; + continue; + } + } + *(regs_word[i].value) = status; + } + } - /* Read mfr_id */ - command = 0x99; - status = ym2651y_read_block(client, command, data->mfr_id, - ARRAY_SIZE(data->mfr_id)-1); - data->mfr_id[ARRAY_SIZE(data->mfr_id)-1] = '\0'; + /* Read mfr_id */ + command = 0x99; + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_block(client, command, data->mfr_id, + ARRAY_SIZE(data->mfr_id)-1); + if (status == 0) + { + length = data->mfr_id[0]; + data->mfr_id[length+1] = '\0'; + } - if (status < 0) - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + /* Read fan_direction */ + command = 0xC3; + char *fan_ptr; + fan_ptr = get_fan_dir_by_model_name(client, data->mfr_model, fan_dir, command); + if( fan_ptr != NULL ) + { + snprintf(data->fan_dir, ARRAY_SIZE(data->fan_dir), "%s", fan_dir); + data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + } + else + { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_block(client, command, fan_dir, ARRAY_SIZE(fan_dir)-1); + if (status == 0) { + snprintf(data->fan_dir, ARRAY_SIZE(data->fan_dir), "%s", fan_dir); + data->fan_dir[ARRAY_SIZE(data->fan_dir)-1] = '\0'; + } + } - /* Read mfr_model */ - command = 0x9a; + /*YM-1401A PSU doens't support to get serial_num, so ignore it. + *It's vout doesn't support linear, so let it use show_vout_by_mode(). + */ + if (!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A"))) { + driver_data->chip=YM1401A; + } + else if (driver_data->mfr_serial_supported) { + /* Read mfr_serial */ + command = 0x9e; length = 1; /* Read first byte to determine the length of data */ + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); status = ym2651y_read_block(client, command, &buf, length); - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; + if (status == 0 && buf != 0xFF) { + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_block(client, command, data->mfr_serial, buf+1); + if (status == 0) { + if ((buf+1) >= (ARRAY_SIZE(data->mfr_serial)-1)) + data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0'; + else + data->mfr_serial[buf+1] = '\0'; + } } - 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 - data->mfr_model[buf+1] = '\0'; + /* Read mfr_revsion */ + command = 0x9b; + VALIDATE_POWERGOOD_AND_INTERVAL(client, &driver_data->access_interval); + status = ym2651y_read_block(client, command, data->mfr_revsion, + ARRAY_SIZE(data->mfr_revsion)-1); + if (status == 0) + { + length = data->mfr_revsion[0]; + data->mfr_revsion[length+1] = '\0'; + } - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } + return 1; /* Return 1 for valid data, 0 for invalid */ - /*YM-1401A PSU doens't support to get serial_num, so ignore it. - *It's vout doesn't support linear, so let it use show_vout_by_mode(). - */ - if(!strncmp("YM-1401A", data->mfr_model+1, strlen("YM-1401A"))) - { - data->chip=YM1401A; - } - else - { - /* Read mfr_serial */ - command = 0x9e; - length = 1; - /* Read first byte to determine the length of data */ - status = ym2651y_read_block(client, command, &buf, length); - if (status < 0) { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - status = ym2651y_read_block(client, command, data->mfr_serial, buf+1); +exit: + return 0; +} - if ((buf+1) >= (ARRAY_SIZE(data->mfr_serial)-1)) - { - data->mfr_serial[ARRAY_SIZE(data->mfr_serial)-1] = '\0'; - } - else - data->mfr_serial[buf+1] = '\0'; +static int ym2651y_update_thread(void *arg) +{ + int valid = 0; + unsigned long start_time = 0; + unsigned long next_start_time = 0; /* expected next start time */ + struct i2c_client *client = arg; + struct ym2651y_data *data = i2c_get_clientdata(client); - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } - } + if (data == NULL) + return -EINVAL; - /* Read mfr_revsion */ - command = 0x9b; - status = ym2651y_read_block(client, command, data->mfr_revsion, - ARRAY_SIZE(data->mfr_revsion)-1); - data->mfr_revsion[ARRAY_SIZE(data->mfr_revsion)-1] = '\0'; + while (!kthread_should_stop()) { + struct pmbus_register_value reg_val = { 0 }; - if (status < 0) - { - dev_dbg(&client->dev, "reg %d, err %d\n", command, status); - goto exit; - } + start_time = jiffies; + valid = ym2651y_update_device(client, ®_val); - data->last_updated = jiffies; + mutex_lock(&data->update_lock); data->valid = 1; + if (valid) { + #ifdef __STDC_LIB_EXT1__ + memcpy_s(&data->reg_val, sizeof(reg_val), ®_val, sizeof(reg_val)); + #else + memcpy(&data->reg_val, ®_val, sizeof(reg_val)); + #endif + } else { + #ifdef __STDC_LIB_EXT1__ + memset_s(&data->reg_val, sizeof(reg_val), 0, sizeof(reg_val)); + #else + memset(&data->reg_val, 0, sizeof(reg_val)); + #endif + + /* PMBus STATUS_WORD(0x79): psu_power_on, low byte bit 6, 0=>ON, 1=>OFF */ + data->reg_val.status_word |= 0x40; + + /* PMBus STATUS_WORD(0x79): psu_power_good, high byte bit 3, 0=>OK, 1=>FAIL */ + data->reg_val.status_word |= 0x800; + + /* psu_power_good = failed, modified to return 1023 degree for python used. */ + data->reg_val.temp_input[0] = 0x3ff; + data->reg_val.temp_input[1] = 0x3ff; + data->reg_val.temp_input[2] = 0x3ff; + } + mutex_unlock(&data->update_lock); + + next_start_time = start_time + REFRESH_INTERVAL_HZ; + if (time_before(jiffies, next_start_time)) { + /* Sleep if time consumed is less than REFRESH_INTERVAL_SECOND */ + msleep(min(jiffies_to_msecs(next_start_time - jiffies), REFRESH_INTERVAL_MSEC)); + } } - exit: - mutex_unlock(&data->update_lock); + complete_all(&data->update_stop); + return 0; +} + +int register_psu_status_entry(PSU_STATUS_ENTRY *entry) +{ + mutex_lock(&entry_lock); + + if (entry) { + access_psu_status.get_presence = entry->get_presence; + access_psu_status.get_powergood = entry->get_powergood; + } + else { + access_psu_status.get_presence = NULL; + access_psu_status.get_powergood = NULL; + } - return data; + mutex_unlock(&entry_lock); + return 0; } +EXPORT_SYMBOL(register_psu_status_entry); -module_i2c_driver(ym2651y_driver); +static int __init ym2651y_init(void) +{ + mutex_init(&entry_lock); + return i2c_add_driver(&ym2651y_driver); +} + +static void __exit ym2651y_exit(void) +{ + i2c_del_driver(&ym2651y_driver); +} + +static int mfr_serial_supported(u8 chip) +{ + int i = 0; + u8 supported_chips[] = {UMEC_UPD150SA, UMEC_UP1K21R}; + + for (i = 0; i < ARRAY_SIZE(supported_chips); i++) { + if (chip == supported_chips[i]) + return 1; + } + + return 0; +} MODULE_AUTHOR("Brandon Chuang "); MODULE_DESCRIPTION("3Y Power YM-2651Y driver"); MODULE_LICENSE("GPL"); - +module_init(ym2651y_init); +module_exit(ym2651y_exit); diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst index 1a87abf9ada..d46217400dc 100644 --- a/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst +++ b/platform/broadcom/sonic-platform-modules-accton/debian/sonic-platform-accton-as4630-54pe.postinst @@ -8,3 +8,5 @@ systemctl start pddf-platform-init.service systemctl enable as4630-54pe-pddf-platform-monitor.service systemctl start as4630-54pe-pddf-platform-monitor.service /usr/local/bin/restart_ixgbe.sh +systemctl enable as4630-54pe-platform-handle-mgmt-interface.service +systemctl start as4630-54pe-platform-handle-mgmt-interface.service