diff --git a/123.patch b/123.patch new file mode 100644 index 0000000000..f6ee0957d8 --- /dev/null +++ b/123.patch @@ -0,0 +1,5611 @@ +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hwsku.json b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hwsku.json +new file mode 100755 +index 000000000..faf0aac09 +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/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_54te-r0/Accton-AS4630-54TE/hx5-as4630-48x1G+4x25G+2x100G.bcm b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hx5-as4630-48x1G+4x25G+2x100G.bcm +new file mode 100755 +index 000000000..1a0241506 +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hx5-as4630-48x1G+4x25G+2x100G.bcm +@@ -0,0 +1,502 @@ ++stable_size=76303168 ++ ++#polarity/lanemap is using TH2 style. ++core_clock_frequency=893 ++dpp_clock_ratio=2:3 ++ ++ptp_ts_pll_fref=50000000 ++ptp_bs_fref_0=50000000 ++ptp_bs_fref_1=50000000 ++ ++#oversubscribe_mode=1 ++ ++pbmp_xport_xe=0x1FFFFFFE000000000000 ++ ++parity_enable=0 ++mem_cache_enable=1 ++ ++l2_mem_entries=32768 ++#l3_mem_entries=49152 ++#fpem_mem_entries=16384 ++l2xmsg_mode=1 ++l3_alpm_enable=2 ++ipv6_lpm_128b_enable=1 ++port_flex_enable=1 ++pcie_hot_swap_timeout_usec=10000 ++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 ++ ++#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 ++port_phy_addr_2=0x41 ++port_phy_addr_3=0x42 ++port_phy_addr_4=0x43 ++port_phy_addr_5=0x44 ++port_phy_addr_6=0x45 ++port_phy_addr_7=0x46 ++port_phy_addr_8=0x47 ++phy_port_primary_and_offset_1=0x0100 ++phy_port_primary_and_offset_2=0x0101 ++phy_port_primary_and_offset_3=0x0102 ++phy_port_primary_and_offset_4=0x0103 ++phy_port_primary_and_offset_5=0x0104 ++phy_port_primary_and_offset_6=0x0105 ++phy_port_primary_and_offset_7=0x0106 ++phy_port_primary_and_offset_8=0x0107 ++dport_map_port_1=26 ++dport_map_port_2=25 ++dport_map_port_3=28 ++dport_map_port_4=27 ++dport_map_port_5=30 ++dport_map_port_6=29 ++dport_map_port_7=32 ++dport_map_port_8=31 ++portmap_1=1:1 ++portmap_2=2:1 ++portmap_3=3:1 ++portmap_4=4:1 ++portmap_5=5:1 ++portmap_6=6:1 ++portmap_7=7:1 ++portmap_8=8:1 ++phy_chain_rx_lane_map_physical{1.0}=0x3210 ++phy_chain_rx_lane_map_physical{2.0}=0x3210 ++phy_chain_rx_lane_map_physical{3.0}=0x3210 ++phy_chain_rx_lane_map_physical{4.0}=0x3210 ++phy_chain_rx_lane_map_physical{5.0}=0x3210 ++phy_chain_rx_lane_map_physical{6.0}=0x3210 ++phy_chain_rx_lane_map_physical{7.0}=0x3210 ++phy_chain_rx_lane_map_physical{8.0}=0x3210 ++phy_chain_tx_lane_map_physical{1.0}=0x3210 ++phy_chain_tx_lane_map_physical{2.0}=0x3210 ++phy_chain_tx_lane_map_physical{3.0}=0x3210 ++phy_chain_tx_lane_map_physical{4.0}=0x3210 ++phy_chain_tx_lane_map_physical{5.0}=0x3210 ++phy_chain_tx_lane_map_physical{6.0}=0x3210 ++phy_chain_tx_lane_map_physical{7.0}=0x3210 ++phy_chain_tx_lane_map_physical{8.0}=0x3210 ++phy_chain_rx_polarity_flip_physical{1.0}=0x0 ++phy_chain_rx_polarity_flip_physical{2.0}=0x0 ++phy_chain_rx_polarity_flip_physical{3.0}=0x0 ++phy_chain_rx_polarity_flip_physical{4.0}=0x0 ++phy_chain_rx_polarity_flip_physical{5.0}=0x0 ++phy_chain_rx_polarity_flip_physical{6.0}=0x0 ++phy_chain_rx_polarity_flip_physical{7.0}=0x0 ++phy_chain_rx_polarity_flip_physical{8.0}=0x0 ++phy_chain_tx_polarity_flip_physical{1.0}=0x0 ++phy_chain_tx_polarity_flip_physical{2.0}=0x0 ++phy_chain_tx_polarity_flip_physical{3.0}=0x0 ++phy_chain_tx_polarity_flip_physical{4.0}=0x0 ++phy_chain_tx_polarity_flip_physical{5.0}=0x0 ++phy_chain_tx_polarity_flip_physical{6.0}=0x0 ++phy_chain_tx_polarity_flip_physical{7.0}=0x0 ++phy_chain_tx_polarity_flip_physical{8.0}=0x0 ++ ++ ++#PHY5 U57 x1x, MDC/MDIO2, PHYADDR:0x09-0x10, 0x11 ++port_phy_addr_9=0x49 ++port_phy_addr_10=0x4A ++port_phy_addr_11=0x4B ++port_phy_addr_12=0x4C ++port_phy_addr_13=0x4D ++port_phy_addr_14=0x4E ++port_phy_addr_15=0x4F ++port_phy_addr_16=0x50 ++phy_port_primary_and_offset_9=0x0900 ++phy_port_primary_and_offset_10=0x0901 ++phy_port_primary_and_offset_11=0x0902 ++phy_port_primary_and_offset_12=0x0903 ++phy_port_primary_and_offset_13=0x0904 ++phy_port_primary_and_offset_14=0x0905 ++phy_port_primary_and_offset_15=0x0906 ++phy_port_primary_and_offset_16=0x0907 ++dport_map_port_9=34 ++dport_map_port_10=33 ++dport_map_port_11=36 ++dport_map_port_12=35 ++dport_map_port_13=38 ++dport_map_port_14=37 ++dport_map_port_15=40 ++dport_map_port_16=39 ++portmap_9=9:1 ++portmap_10=10:1 ++portmap_11=11:1 ++portmap_12=12:1 ++portmap_13=13:1 ++portmap_14=14:1 ++portmap_15=15:1 ++portmap_16=16:1 ++phy_chain_rx_lane_map_physical{9.0}=0x3210 ++phy_chain_rx_lane_map_physical{10.0}=0x3210 ++phy_chain_rx_lane_map_physical{11.0}=0x3210 ++phy_chain_rx_lane_map_physical{12.0}=0x3210 ++phy_chain_rx_lane_map_physical{13.0}=0x3210 ++phy_chain_rx_lane_map_physical{14.0}=0x3210 ++phy_chain_rx_lane_map_physical{15.0}=0x3210 ++phy_chain_rx_lane_map_physical{16.0}=0x3210 ++phy_chain_tx_lane_map_physical{9.0}=0x3210 ++phy_chain_tx_lane_map_physical{10.0}=0x3210 ++phy_chain_tx_lane_map_physical{11.0}=0x3210 ++phy_chain_tx_lane_map_physical{12.0}=0x3210 ++phy_chain_tx_lane_map_physical{13.0}=0x3210 ++phy_chain_tx_lane_map_physical{14.0}=0x3210 ++phy_chain_tx_lane_map_physical{15.0}=0x3210 ++phy_chain_tx_lane_map_physical{16.0}=0x3210 ++phy_chain_rx_polarity_flip_physical{9.0}=0x0 ++phy_chain_rx_polarity_flip_physical{10.0}=0x0 ++phy_chain_rx_polarity_flip_physical{11.0}=0x0 ++phy_chain_rx_polarity_flip_physical{12.0}=0x0 ++phy_chain_rx_polarity_flip_physical{13.0}=0x0 ++phy_chain_rx_polarity_flip_physical{14.0}=0x0 ++phy_chain_rx_polarity_flip_physical{15.0}=0x0 ++phy_chain_rx_polarity_flip_physical{16.0}=0x0 ++phy_chain_tx_polarity_flip_physical{9.0}=0x0 ++phy_chain_tx_polarity_flip_physical{10.0}=0x0 ++phy_chain_tx_polarity_flip_physical{11.0}=0x0 ++phy_chain_tx_polarity_flip_physical{12.0}=0x0 ++phy_chain_tx_polarity_flip_physical{13.0}=0x0 ++phy_chain_tx_polarity_flip_physical{14.0}=0x0 ++phy_chain_tx_polarity_flip_physical{15.0}=0x0 ++phy_chain_tx_polarity_flip_physical{16.0}=0x0 ++ ++#MCQ1 ++port_gmii_mode_17=1 #Q mode ++ ++#PHY6 U58 11x, MDC/MDIO2, PHYADDR:0x12-0x19, 0x1A ++port_phy_addr_17=0x52 ++port_phy_addr_18=0x53 ++port_phy_addr_19=0x54 ++port_phy_addr_20=0x55 ++port_phy_addr_21=0x56 ++port_phy_addr_22=0x57 ++port_phy_addr_23=0x58 ++port_phy_addr_24=0x59 ++phy_port_primary_and_offset_17=0x1100 ++phy_port_primary_and_offset_18=0x1101 ++phy_port_primary_and_offset_19=0x1102 ++phy_port_primary_and_offset_20=0x1103 ++phy_port_primary_and_offset_21=0x1104 ++phy_port_primary_and_offset_22=0x1105 ++phy_port_primary_and_offset_23=0x1106 ++phy_port_primary_and_offset_24=0x1107 ++dport_map_port_17=42 ++dport_map_port_18=41 ++dport_map_port_19=44 ++dport_map_port_20=43 ++dport_map_port_21=46 ++dport_map_port_22=45 ++dport_map_port_23=48 ++dport_map_port_24=47 ++portmap_17=17:1 ++portmap_18=18:1 ++portmap_19=19:1 ++portmap_20=20:1 ++portmap_21=21:1 ++portmap_22=22:1 ++portmap_23=23:1 ++portmap_24=24:1 ++phy_chain_rx_lane_map_physical{17.0}=0x3210 ++phy_chain_rx_lane_map_physical{18.0}=0x3210 ++phy_chain_rx_lane_map_physical{19.0}=0x3210 ++phy_chain_rx_lane_map_physical{20.0}=0x3210 ++phy_chain_rx_lane_map_physical{21.0}=0x3210 ++phy_chain_rx_lane_map_physical{22.0}=0x3210 ++phy_chain_rx_lane_map_physical{23.0}=0x3210 ++phy_chain_rx_lane_map_physical{24.0}=0x3210 ++phy_chain_tx_lane_map_physical{17.0}=0x3210 ++phy_chain_tx_lane_map_physical{18.0}=0x3210 ++phy_chain_tx_lane_map_physical{19.0}=0x3210 ++phy_chain_tx_lane_map_physical{20.0}=0x3210 ++phy_chain_tx_lane_map_physical{21.0}=0x3210 ++phy_chain_tx_lane_map_physical{22.0}=0x3210 ++phy_chain_tx_lane_map_physical{23.0}=0x3210 ++phy_chain_tx_lane_map_physical{24.0}=0x3210 ++phy_chain_rx_polarity_flip_physical{17.0}=0x0 ++phy_chain_rx_polarity_flip_physical{18.0}=0x0 ++phy_chain_rx_polarity_flip_physical{19.0}=0x0 ++phy_chain_rx_polarity_flip_physical{20.0}=0x0 ++phy_chain_rx_polarity_flip_physical{21.0}=0x0 ++phy_chain_rx_polarity_flip_physical{22.0}=0x0 ++phy_chain_rx_polarity_flip_physical{23.0}=0x0 ++phy_chain_rx_polarity_flip_physical{24.0}=0x0 ++phy_chain_tx_polarity_flip_physical{17.0}=0x0 ++phy_chain_tx_polarity_flip_physical{18.0}=0x0 ++phy_chain_tx_polarity_flip_physical{19.0}=0x0 ++phy_chain_tx_polarity_flip_physical{20.0}=0x0 ++phy_chain_tx_polarity_flip_physical{21.0}=0x0 ++phy_chain_tx_polarity_flip_physical{22.0}=0x0 ++phy_chain_tx_polarity_flip_physical{23.0}=0x0 ++phy_chain_tx_polarity_flip_physical{24.0}=0x0 ++ ++#PHY1 U53 xx1, MDC/MDIO0, PHYADDR:0x00-0x07, 0x08 ++port_phy_addr_25=0x00 ++port_phy_addr_26=0x01 ++port_phy_addr_27=0x02 ++port_phy_addr_28=0x03 ++port_phy_addr_29=0x04 ++port_phy_addr_30=0x05 ++port_phy_addr_31=0x06 ++port_phy_addr_32=0x07 ++phy_port_primary_and_offset_25=0x1900 ++phy_port_primary_and_offset_26=0x1901 ++phy_port_primary_and_offset_27=0x1902 ++phy_port_primary_and_offset_28=0x1903 ++phy_port_primary_and_offset_29=0x1904 ++phy_port_primary_and_offset_30=0x1905 ++phy_port_primary_and_offset_31=0x1906 ++phy_port_primary_and_offset_32=0x1907 ++dport_map_port_25=2 ++dport_map_port_26=1 ++dport_map_port_27=4 ++dport_map_port_28=3 ++dport_map_port_29=6 ++dport_map_port_30=5 ++dport_map_port_31=8 ++dport_map_port_32=7 ++portmap_25=25:1 ++portmap_26=26:1 ++portmap_27=27:1 ++portmap_28=28:1 ++portmap_29=29:1 ++portmap_30=30:1 ++portmap_31=31:1 ++portmap_32=32:1 ++phy_chain_rx_lane_map_physical{25.0}=0x3210 ++phy_chain_rx_lane_map_physical{26.0}=0x3210 ++phy_chain_rx_lane_map_physical{27.0}=0x3210 ++phy_chain_rx_lane_map_physical{28.0}=0x3210 ++phy_chain_rx_lane_map_physical{29.0}=0x3210 ++phy_chain_rx_lane_map_physical{30.0}=0x3210 ++phy_chain_rx_lane_map_physical{31.0}=0x3210 ++phy_chain_rx_lane_map_physical{32.0}=0x3210 ++phy_chain_tx_lane_map_physical{25.0}=0x3210 ++phy_chain_tx_lane_map_physical{26.0}=0x3210 ++phy_chain_tx_lane_map_physical{27.0}=0x3210 ++phy_chain_tx_lane_map_physical{28.0}=0x3210 ++phy_chain_tx_lane_map_physical{29.0}=0x3210 ++phy_chain_tx_lane_map_physical{30.0}=0x3210 ++phy_chain_tx_lane_map_physical{31.0}=0x3210 ++phy_chain_tx_lane_map_physical{32.0}=0x3210 ++phy_chain_rx_polarity_flip_physical{25.0}=0x0 ++phy_chain_rx_polarity_flip_physical{26.0}=0x0 ++phy_chain_rx_polarity_flip_physical{27.0}=0x0 ++phy_chain_rx_polarity_flip_physical{28.0}=0x0 ++phy_chain_rx_polarity_flip_physical{29.0}=0x0 ++phy_chain_rx_polarity_flip_physical{30.0}=0x0 ++phy_chain_rx_polarity_flip_physical{31.0}=0x0 ++phy_chain_rx_polarity_flip_physical{32.0}=0x0 ++phy_chain_tx_polarity_flip_physical{25.0}=0x0 ++phy_chain_tx_polarity_flip_physical{26.0}=0x0 ++phy_chain_tx_polarity_flip_physical{27.0}=0x0 ++phy_chain_tx_polarity_flip_physical{28.0}=0x0 ++phy_chain_tx_polarity_flip_physical{29.0}=0x0 ++phy_chain_tx_polarity_flip_physical{30.0}=0x0 ++phy_chain_tx_polarity_flip_physical{31.0}=0x0 ++phy_chain_tx_polarity_flip_physical{32.0}=0x0 ++ ++#MCQ2 ++port_gmii_mode_33=1 #Q mode ++ ++#PHY2 U54 x1x, MDC/MDIO0, PHYADDR:0x09-0x10, 0x11 ++port_phy_addr_33=0x0D ++port_phy_addr_34=0x0E ++port_phy_addr_35=0x0F ++port_phy_addr_36=0x10 ++port_phy_addr_37=0x09 ++port_phy_addr_38=0x0A ++port_phy_addr_39=0x0B ++port_phy_addr_40=0x0C ++phy_port_primary_and_offset_33=0x2504 ++phy_port_primary_and_offset_34=0x2505 ++phy_port_primary_and_offset_35=0x2506 ++phy_port_primary_and_offset_36=0x2507 ++phy_port_primary_and_offset_37=0x2500 ++phy_port_primary_and_offset_38=0x2501 ++phy_port_primary_and_offset_39=0x2502 ++phy_port_primary_and_offset_40=0x2503 ++dport_map_port_33=14 ++dport_map_port_34=13 ++dport_map_port_35=16 ++dport_map_port_36=15 ++dport_map_port_37=10 ++dport_map_port_38=9 ++dport_map_port_39=12 ++dport_map_port_40=11 ++portmap_33=33:1 ++portmap_34=34:1 ++portmap_35=35:1 ++portmap_36=36:1 ++portmap_37=37:1 ++portmap_38=38:1 ++portmap_39=39:1 ++portmap_40=40:1 ++phy_chain_rx_lane_map_physical{33.0}=0x3210 ++phy_chain_rx_lane_map_physical{34.0}=0x3210 ++phy_chain_rx_lane_map_physical{35.0}=0x3210 ++phy_chain_rx_lane_map_physical{36.0}=0x3210 ++phy_chain_rx_lane_map_physical{37.0}=0x3210 ++phy_chain_rx_lane_map_physical{38.0}=0x3210 ++phy_chain_rx_lane_map_physical{39.0}=0x3210 ++phy_chain_rx_lane_map_physical{40.0}=0x3210 ++phy_chain_tx_lane_map_physical{33.0}=0x3210 ++phy_chain_tx_lane_map_physical{34.0}=0x3210 ++phy_chain_tx_lane_map_physical{35.0}=0x3210 ++phy_chain_tx_lane_map_physical{36.0}=0x3210 ++phy_chain_tx_lane_map_physical{37.0}=0x3210 ++phy_chain_tx_lane_map_physical{38.0}=0x3210 ++phy_chain_tx_lane_map_physical{39.0}=0x3210 ++phy_chain_tx_lane_map_physical{40.0}=0x3210 ++phy_chain_rx_polarity_flip_physical{33.0}=0x1 ++phy_chain_rx_polarity_flip_physical{34.0}=0x1 ++phy_chain_rx_polarity_flip_physical{35.0}=0x1 ++phy_chain_rx_polarity_flip_physical{36.0}=0x1 ++phy_chain_rx_polarity_flip_physical{37.0}=0x1 ++phy_chain_rx_polarity_flip_physical{38.0}=0x1 ++phy_chain_rx_polarity_flip_physical{39.0}=0x1 ++phy_chain_rx_polarity_flip_physical{40.0}=0x1 ++phy_chain_tx_polarity_flip_physical{33.0}=0x1 ++phy_chain_tx_polarity_flip_physical{34.0}=0x1 ++phy_chain_tx_polarity_flip_physical{35.0}=0x1 ++phy_chain_tx_polarity_flip_physical{36.0}=0x1 ++phy_chain_tx_polarity_flip_physical{37.0}=0x1 ++phy_chain_tx_polarity_flip_physical{38.0}=0x1 ++phy_chain_tx_polarity_flip_physical{39.0}=0x1 ++phy_chain_tx_polarity_flip_physical{40.0}=0x1 ++ ++#PHY3 U55 11x, MDC/MDIO0, PHYADDR:0x12-0x19, 0x1A ++port_phy_addr_41=0x16 ++port_phy_addr_42=0x17 ++port_phy_addr_43=0x18 ++port_phy_addr_44=0x19 ++port_phy_addr_45=0x12 ++port_phy_addr_46=0x13 ++port_phy_addr_47=0x14 ++port_phy_addr_48=0x15 ++phy_port_primary_and_offset_41=0x2D00 ++phy_port_primary_and_offset_42=0x2D01 ++phy_port_primary_and_offset_43=0x2D02 ++phy_port_primary_and_offset_44=0x2D03 ++phy_port_primary_and_offset_45=0x2D04 ++phy_port_primary_and_offset_46=0x2D05 ++phy_port_primary_and_offset_47=0x2D06 ++phy_port_primary_and_offset_48=0x2D07 ++dport_map_port_41=22 ++dport_map_port_42=21 ++dport_map_port_43=24 ++dport_map_port_44=23 ++dport_map_port_45=18 ++dport_map_port_46=17 ++dport_map_port_47=20 ++dport_map_port_48=19 ++portmap_41=41:1 ++portmap_42=42:1 ++portmap_43=43:1 ++portmap_44=44:1 ++portmap_45=45:1 ++portmap_46=46:1 ++portmap_47=47:1 ++portmap_48=48:1 ++phy_chain_rx_lane_map_physical{41.0}=0x3210 ++phy_chain_rx_lane_map_physical{42.0}=0x3210 ++phy_chain_rx_lane_map_physical{43.0}=0x3210 ++phy_chain_rx_lane_map_physical{44.0}=0x3210 ++phy_chain_rx_lane_map_physical{45.0}=0x3210 ++phy_chain_rx_lane_map_physical{46.0}=0x3210 ++phy_chain_rx_lane_map_physical{47.0}=0x3210 ++phy_chain_rx_lane_map_physical{48.0}=0x3210 ++phy_chain_tx_lane_map_physical{41.0}=0x3210 ++phy_chain_tx_lane_map_physical{42.0}=0x3210 ++phy_chain_tx_lane_map_physical{43.0}=0x3210 ++phy_chain_tx_lane_map_physical{44.0}=0x3210 ++phy_chain_tx_lane_map_physical{45.0}=0x3210 ++phy_chain_tx_lane_map_physical{46.0}=0x3210 ++phy_chain_tx_lane_map_physical{47.0}=0x3210 ++phy_chain_tx_lane_map_physical{48.0}=0x3210 ++phy_chain_rx_polarity_flip_physical{41.0}=0x1 ++phy_chain_rx_polarity_flip_physical{42.0}=0x1 ++phy_chain_rx_polarity_flip_physical{43.0}=0x1 ++phy_chain_rx_polarity_flip_physical{44.0}=0x1 ++phy_chain_rx_polarity_flip_physical{45.0}=0x1 ++phy_chain_rx_polarity_flip_physical{46.0}=0x1 ++phy_chain_rx_polarity_flip_physical{47.0}=0x1 ++phy_chain_rx_polarity_flip_physical{48.0}=0x1 ++phy_chain_tx_polarity_flip_physical{41.0}=0x1 ++phy_chain_tx_polarity_flip_physical{42.0}=0x1 ++phy_chain_tx_polarity_flip_physical{43.0}=0x1 ++phy_chain_tx_polarity_flip_physical{44.0}=0x1 ++phy_chain_tx_polarity_flip_physical{45.0}=0x1 ++phy_chain_tx_polarity_flip_physical{46.0}=0x1 ++phy_chain_tx_polarity_flip_physical{47.0}=0x1 ++phy_chain_tx_polarity_flip_physical{48.0}=0x1 ++ ++#3x PM4x25 (3 * 4 = 12 physical ports) ++#FC0 ++dport_map_port_49=51 ++dport_map_port_50=50 ++dport_map_port_51=49 ++dport_map_port_52=52 ++portmap_49=65:25 ++portmap_50=66:25 ++portmap_51=67:25 ++portmap_52=68:25 ++#FC1 ++dport_map_port_53=57 ++dport_map_port_54=58 ++dport_map_port_55=59 ++dport_map_port_56=60 ++portmap_53=69:100:4 ++#portmap_55=71:50 ++#portmap_54=70:25 ++#portmap_55=71:25 ++#portmap_56=72:25 ++#FC2 ++dport_map_port_57=53 ++dport_map_port_58=54 ++dport_map_port_59=55 ++dport_map_port_60=56 ++portmap_57=73:100:4 ++#portmap_59=75:50 ++#portmap_58=74:25 ++#portmap_59=75:25 ++#portmap_60=76:25 ++ ++#4x PM4x10 (4 * 4 = 16 physical ports) ++#MC0 No connection ++#MC1 No connection ++#MC2 No connection ++#MC3 No connection ++#portmap_=49:10 ++#portmap_=50:10 ++#portmap_=51:10 ++#portmap_=52:10 ++ ++#portmap_=53:10 ++#portmap_=54:10 ++#portmap_=55:10 ++#portmap_=56:10 ++ ++#portmap_=57:10 ++#portmap_=58:10 ++#portmap_=59:10 ++#portmap_=60:10 ++ ++#portmap_=61:10 ++#portmap_=62:10 ++#portmap_=63:10 ++#portmap_=64:10 +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/port_config.ini b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/port_config.ini +index 7040875fa..c30f99f48 100755 +--- a/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/port_config.ini ++++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/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 ++# name lanes alias index speed autoneg ++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_54te-r0/Accton-AS4630-54TE/sai.profile b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/sai.profile +new file mode 100755 +index 000000000..5329410fe +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/sai.profile +@@ -0,0 +1 @@ ++SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/hx5-as4630-48x1G+4x25G+2x100G.bcm +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/installer.conf b/device/accton/x86_64-accton_as4630_54te-r0/installer.conf +index 925a32fc0..d5f9419d7 100755 +--- a/device/accton/x86_64-accton_as4630_54te-r0/installer.conf ++++ b/device/accton/x86_64-accton_as4630_54te-r0/installer.conf +@@ -1,3 +1,4 @@ + CONSOLE_PORT=0x3f8 + CONSOLE_DEV=0 + CONSOLE_SPEED=115200 ++ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off" +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/led_proc_init.soc b/device/accton/x86_64-accton_as4630_54te-r0/led_proc_init.soc +new file mode 100644 +index 000000000..696632b6e +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/led_proc_init.soc +@@ -0,0 +1,3 @@ ++#m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin ++led start ++#led auto on +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/pcie.yaml b/device/accton/x86_64-accton_as4630_54te-r0/pcie.yaml +new file mode 100644 +index 000000000..c7e99c867 +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-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_54te-r0/platform.json b/device/accton/x86_64-accton_as4630_54te-r0/platform.json +new file mode 100644 +index 000000000..af158fc72 +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/platform.json +@@ -0,0 +1,820 @@ ++{ ++ "chassis": { ++ "name": "AS4630-54TE", ++ "thermal_manager":false, ++ "status_led": { ++ "controllable": true, ++ "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_GREEN_BLINK", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] ++ }, ++ "components": [ ++ { ++ "name": "CPLD1" ++ }, ++ { ++ "name": "CPLD2" ++ }, ++ { ++ "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", ++ "status_led": { ++ "controllable": false ++ }, ++ "num_fans" : 1, ++ "fans": [ ++ { ++ "name": "FAN-1", ++ "speed": { ++ "controllable": true, ++ "minimum": 7 ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray2", ++ "status_led": { ++ "controllable": false ++ }, ++ "num_fans" : 1, ++ "fans": [ ++ { ++ "name": "FAN-2", ++ "speed": { ++ "controllable": true, ++ "minimum": 7 ++ }, ++ "status_led": { ++ "controllable": false ++ } ++ } ++ ] ++ }, ++ { ++ "name": "FanTray3", ++ "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": true, ++ "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] ++ }, ++ "fans": [ ++ { ++ "name": "PSU-1 FAN-1" ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "PSU-1 temp sensor 1", ++ "controllable": false, ++ "low-crit-threshold": false, ++ "high-crit-threshold": false ++ } ++ ] ++ }, ++ { ++ "name": "PSU-2", ++ "status_led": { ++ "controllable": true, ++ "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] ++ }, ++ "fans": [ ++ { ++ "name": "PSU-2 FAN-1" ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "PSU-2 temp sensor 1", ++ "controllable": false, ++ "low-crit-threshold": false, ++ "high-crit-threshold": false ++ } ++ ] ++ } ++ ], ++ "thermals": [ ++ { ++ "name": "MB_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": "Ethernet0" ++ }, ++ { ++ "name": "Ethernet1" ++ }, ++ { ++ "name": "Ethernet2" ++ }, ++ { ++ "name": "Ethernet3" ++ }, ++ { ++ "name": "Ethernet4" ++ }, ++ { ++ "name": "Ethernet5" ++ }, ++ { ++ "name": "Ethernet6" ++ }, ++ { ++ "name": "Ethernet7" ++ }, ++ { ++ "name": "Ethernet8" ++ }, ++ { ++ "name": "Ethernet9" ++ }, ++ { ++ "name": "Ethernet10" ++ }, ++ { ++ "name": "Ethernet11" ++ }, ++ { ++ "name": "Ethernet12" ++ }, ++ { ++ "name": "Ethernet13" ++ }, ++ { ++ "name": "Ethernet14" ++ }, ++ { ++ "name": "Ethernet15" ++ }, ++ { ++ "name": "Ethernet16" ++ }, ++ { ++ "name": "Ethernet17" ++ }, ++ { ++ "name": "Ethernet18" ++ }, ++ { ++ "name": "Ethernet19" ++ }, ++ { ++ "name": "Ethernet20" ++ }, ++ { ++ "name": "Ethernet21" ++ }, ++ { ++ "name": "Ethernet22" ++ }, ++ { ++ "name": "Ethernet23" ++ }, ++ { ++ "name": "Ethernet24" ++ }, ++ { ++ "name": "Ethernet25" ++ }, ++ { ++ "name": "Ethernet26" ++ }, ++ { ++ "name": "Ethernet27" ++ }, ++ { ++ "name": "Ethernet28" ++ }, ++ { ++ "name": "Ethernet29" ++ }, ++ { ++ "name": "Ethernet30" ++ }, ++ { ++ "name": "Ethernet31" ++ }, ++ { ++ "name": "Ethernet32" ++ }, ++ { ++ "name": "Ethernet33" ++ }, ++ { ++ "name": "Ethernet34" ++ }, ++ { ++ "name": "Ethernet35" ++ }, ++ { ++ "name": "Ethernet36" ++ }, ++ { ++ "name": "Ethernet37" ++ }, ++ { ++ "name": "Ethernet38" ++ }, ++ { ++ "name": "Ethernet39" ++ }, ++ { ++ "name": "Ethernet40" ++ }, ++ { ++ "name": "Ethernet41" ++ }, ++ { ++ "name": "Ethernet42" ++ }, ++ { ++ "name": "Ethernet43" ++ }, ++ { ++ "name": "Ethernet44" ++ }, ++ { ++ "name": "Ethernet45" ++ }, ++ { ++ "name": "Ethernet46" ++ }, ++ { ++ "name": "Ethernet47" ++ }, ++ { ++ "name": "Ethernet48" ++ }, ++ { ++ "name": "Ethernet49" ++ }, ++ { ++ "name": "Ethernet50" ++ }, ++ { ++ "name": "Ethernet51" ++ }, ++ { ++ "name": "Ethernet52" ++ }, ++ { ++ "name": "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_54te-r0/platform_components.json b/device/accton/x86_64-accton_as4630_54te-r0/platform_components.json +new file mode 100644 +index 000000000..5e70a87a4 +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/platform_components.json +@@ -0,0 +1,11 @@ ++{ ++ "chassis": { ++ "AS4630-54TE-O-AC-F": { ++ "component": { ++ "CPLD1": { }, ++ "CPLD2": { }, ++ "BIOS": { } ++ } ++ } ++ } ++} +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/eeprom.py +deleted file mode 100755 +index 7409239d0..000000000 +--- a/device/accton/x86_64-accton_as4630_54te-r0/plugins/eeprom.py ++++ /dev/null +@@ -1,13 +0,0 @@ +-try: +- from sonic_eeprom import eeprom_tlvinfo +- +-except ImportError as e: +- raise ImportError(str(e) + "- required module not found") +- +- +-class board(eeprom_tlvinfo.TlvInfoDecoder): +- _TLV_INFO_MAX_LEN = 256 +- +- def __init__(self, name, path, cpld_root, ro): +- self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" +- super(board, self).__init__(self.eeprom_path, 0, '', True) +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/psuutil.py +deleted file mode 100755 +index 92ae68eb8..000000000 +--- a/device/accton/x86_64-accton_as4630_54te-r0/plugins/psuutil.py ++++ /dev/null +@@ -1,61 +0,0 @@ +-#!/usr/bin/env python +- +-############################################################################# +-# Accton +-# +-# Module contains an implementation of SONiC PSU Base API and +-# provides the PSUs status which are available in the platform +-# +-############################################################################# +- +- +-try: +- from sonic_psu.psu_base import PsuBase +-except ImportError as e: +- raise ImportError(str(e) + "- required module not found") +- +- +-class PsuUtil(PsuBase): +- """Platform-specific PSUutil class""" +- +- def __init__(self): +- PsuBase.__init__(self) +- +- self.psu_path = "/sys/bus/i2c/devices/" +- self.psu_presence = "/psu_present" +- self.psu_oper_status = "/psu_power_good" +- self.psu_mapping = { +- 1: "10-0050", +- 2: "11-0051", +- } +- +- def get_num_psus(self): +- return len(self.psu_mapping) +- +- def get_psu_status(self, index): +- if index is None: +- return False +- +- status = 0 +- node = self.psu_path + self.psu_mapping[index] + self.psu_oper_status +- try: +- with open(node, 'r') as power_status: +- status = int(power_status.read()) +- except IOError: +- return False +- +- return status == 1 +- +- def get_psu_presence(self, index): +- if index is None: +- return False +- +- status = 0 +- node = self.psu_path + self.psu_mapping[index] + self.psu_presence +- try: +- with open(node, 'r') as presence_status: +- status = int(presence_status.read()) +- except IOError: +- return False +- +- return status == 1 +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/sfputil.py +deleted file mode 100755 +index 63e6bd536..000000000 +--- a/device/accton/x86_64-accton_as4630_54te-r0/plugins/sfputil.py ++++ /dev/null +@@ -1,196 +0,0 @@ +-# sfputil.py +-# +-# Platform-specific SFP transceiver interface for SONiC +-# +- +-try: +- import sys +- import time +- from ctypes import create_string_buffer +- from sonic_sfp.sfputilbase import SfpUtilBase +-except ImportError as e: +- raise ImportError("%s - required module not found" % str(e)) +- +-SFP_STATUS_INSERTED = '1' +-SFP_STATUS_REMOVED = '0' +- +- +-class SfpUtil(SfpUtilBase): +- """Platform-specific SfpUtil class""" +- +- PORT_START = 49 +- PORT_END = 54 +- PORTS_IN_BLOCK = 54 +- QSFP_START = 53 +- +- BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" +- BASE_CPLD_PATH = "/sys/bus/i2c/devices/3-0060/" +- +- _port_to_is_present = {} +- _port_to_lp_mode = {} +- +- _port_to_eeprom_mapping = {} +- _port_to_i2c_mapping = { +- 49: [18], +- 50: [19], +- 51: [20], +- 52: [21], +- 53: [22], +- 54: [23], +- } +- +- @property +- def port_start(self): +- return self.PORT_START +- +- @property +- def port_end(self): +- return self.PORT_END +- +- @property +- def qsfp_ports(self): +- return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) +- +- @property +- def port_to_eeprom_mapping(self): +- return self._port_to_eeprom_mapping +- +- def __init__(self): +- eeprom_path = self.BASE_OOM_PATH + "eeprom" +- for x in range(self.port_start, self.port_end + 1): +- self.port_to_eeprom_mapping[x] = eeprom_path.format( +- self._port_to_i2c_mapping[x][0]) +- SfpUtilBase.__init__(self) +- +- def get_presence(self, port_num): +- # Check for invalid port_num +- if port_num < self.port_start or port_num > self.port_end: +- return False +- +- present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num) +- self.__port_to_is_present = present_path +- +- try: +- val_file = open(self.__port_to_is_present) +- content = val_file.readline().rstrip() +- val_file.close() +- except IOError as e: +- print ('Error: unable to access file: %s') % str(e) +- return False +- +- if content == "1": +- return True +- +- return False +- +- def get_low_power_mode(self, port_num): +- # Check for invalid port_num +- if port_num < self.QSFP_START or port_num > self.port_end: +- return False +- +- try: +- eeprom = None +- if not self.get_presence(port_num): +- return False +- eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") +- eeprom.seek(93) +- lpmode = ord(eeprom.read(1)) +- +- # if "Power override" bit is 1 and "Power set" bit is 1 +- if ((lpmode & 0x3) == 0x3): +- return True +- +- # High Power Mode if one of the following conditions is matched: +- # 1. "Power override" bit is 0 +- # 2. "Power override" bit is 1 and "Power set" bit is 0 +- else: +- return False +- +- except IOError as e: +- print ('Error: unable to open file: %s') % str(e) +- return False +- finally: +- if eeprom is not None: +- eeprom.close() +- time.sleep(0.01) +- +- def set_low_power_mode(self, port_num, lpmode): +- # Check for invalid port_num +- if port_num < self.QSFP_START or port_num > self.port_end: +- return False +- +- try: +- eeprom = None +- if not self.get_presence(port_num): +- return False # Port is not present, unable to set the eeprom +- +- # Fill in write buffer +- # 0x3:Low Power Mode, 0x1:High Power Mode +- regval = 0x3 if lpmode else 0x1 +- +- buffer = create_string_buffer(1) +- if sys.version_info[0] >= 3: +- buffer[0] = regval +- else: +- buffer[0] = chr(regval) +- +- # Write to eeprom +- eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") +- eeprom.seek(93) +- eeprom.write(buffer[0]) +- return True +- except IOError as e: +- print ('Error: unable to open file: %s') % str(e) +- return False +- finally: +- if eeprom is not None: +- eeprom.close() +- time.sleep(0.01) +- +- def reset(self, port_num): +- raise NotImplementedError +- +- @property +- def _get_presence_bitmap(self): +- +- bits = [] +- for x in range(self.port_start, self.port_end + 1): +- bits.append(str(int(self.get_presence(x)))) +- +- rev = "".join(bits[::-1]) +- return int(rev, 2) +- +- data = {'present': 0} +- +- def get_transceiver_change_event(self, timeout=0): +- port_dict = {} +- +- if timeout == 0: +- cd_ms = sys.maxsize +- else: +- cd_ms = timeout +- +- # poll per second +- while cd_ms > 0: +- reg_value = self._get_presence_bitmap +- changed_ports = self.data['present'] ^ reg_value +- if changed_ports != 0: +- break +- time.sleep(1) +- cd_ms = cd_ms - 1000 +- +- if changed_ports != 0: +- for port in range(self.port_start, self.port_end + 1): +- # Mask off the bit corresponding to our port +- mask = (1 << (port - self.port_start)) +- if changed_ports & mask: +- if (reg_value & mask) == 0: +- port_dict[port] = SFP_STATUS_REMOVED +- else: +- port_dict[port] = SFP_STATUS_INSERTED +- +- # Update cache +- self.data['present'] = reg_value +- return True, port_dict +- else: +- return True, {} +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/ssd_util.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/ssd_util.py +new file mode 100755 +index 000000000..4b173c5e3 +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-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_54te-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4630_54te-r0/pmon_daemon_control.json +index a3b204e20..44bad6494 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/pmon_daemon_control.json ++++ b/device/accton/x86_64-accton_as4630_54te-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_54te-r0/sensors.conf b/device/accton/x86_64-accton_as4630_54te-r0/sensors.conf +index b22fff04d..cbb82e0df 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sensors.conf ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sensors.conf +@@ -31,10 +31,10 @@ chip "as4630_54te_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_54te-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/chassis.py +index 9f39c903c..9ec4c7ccf 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/chassis.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/chassis.py +@@ -6,27 +6,27 @@ + # + ############################################################################# + +-import subprocess +- + try: ++ import sys + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper ++ from .event import SfpEvent + except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + NUM_FAN_TRAY = 3 + NUM_FAN = 2 + NUM_PSU = 2 +-NUM_THERMAL = 3 ++NUM_THERMAL = 8 + NUM_QSFP = 6 + PORT_START = 49 + PORT_END = 54 +-NUM_COMPONENT = 2 ++NUM_COMPONENT = 3 + HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" + PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" + REBOOT_CAUSE_FILE = "reboot-cause.txt" + PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +-HOST_CHK_CMD = ["docker"] ++HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + SYSLED_FNODE = "/sys/class/leds/diag/brightness" + SYSLED_MODES = { + "0" : "STATUS_LED_COLOR_OFF", +@@ -42,7 +42,6 @@ class Chassis(ChassisBase): + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() +- self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + + self.config_data = {} +@@ -59,6 +58,7 @@ class Chassis(ChassisBase): + for index in range(0, PORT_END): + sfp = Sfp(index) + self._sfp_list.append(sfp) ++ self._sfpevent = SfpEvent(self._sfp_list) + self.sfp_module_initialized = True + + def __initialize_fan(self): +@@ -89,23 +89,6 @@ class Chassis(ChassisBase): + component = Component(index) + self._component_list.append(component) + +- def __initialize_watchdog(self): +- from sonic_platform.watchdog import Watchdog +- self._watchdog = Watchdog() +- +- +- def __is_host(self): +- return subprocess.call(HOST_CHK_CMD) == 0 +- +- def __read_txt_file(self, file_path): +- try: +- with open(file_path, 'r') as fd: +- data = fd.read() +- return data.strip() +- except IOError: +- pass +- return None +- + def get_name(self): + """ + Retrieves the name of the device +@@ -113,7 +96,7 @@ class Chassis(ChassisBase): + string: The name of the device + """ + +- return self._api_helper.hwsku ++ return self._eeprom.get_modelstr() + + def get_presence(self): + """ +@@ -176,6 +159,12 @@ class Chassis(ChassisBase): + + return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + ++ def get_change_event(self, timeout=0): ++ # SFP event ++ if not self.sfp_module_initialized: ++ self.__initialize_sfp() ++ return self._sfpevent.get_sfp_event(timeout) ++ + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index +@@ -234,3 +223,28 @@ class Chassis(ChassisBase): + return False + else: + return self._api_helper.write_txt_file(SYSLED_FNODE, mode) ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return self._eeprom.get_pn() ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return self._eeprom.get_serial() ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ return self._eeprom.get_revisionstr() +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py +index 8137d0f3a..f5dafd007 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py +@@ -6,10 +6,12 @@ + # + ############################################################################# + +- + try: ++ import os ++ import json + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper ++ from sonic_py_common.general import getstatusoutput_noshell + except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +@@ -20,6 +22,7 @@ SYSFS_PATH = "/sys/bus/i2c/devices/" + BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" + COMPONENT_LIST= [ + ("CPLD1", "CPLD 1"), ++ ("CPLD2", "CPLD CPU"), + ("BIOS", "Basic Input/Output System") + + ] +@@ -58,6 +61,15 @@ class Component(ComponentBase): + + return cpld_version + ++ def __get_cpldcpu_version(self): ++ cpld_version = dict() ++ cmd = ["i2cget", "-y", "1", "0x65", "0x01"] ++ status, output1 = getstatusoutput_noshell(cmd) ++ cmd = ["i2cget", "-y", "1", "0x65", "0x02"] ++ status, output2 = getstatusoutput_noshell(cmd) ++ cpld_version[self.name] = "{}{}{}".format(int(output1,16),".",int(output2,16)) ++ return cpld_version ++ + def get_name(self): + """ + Retrieves the name of the component +@@ -85,9 +97,12 @@ class Component(ComponentBase): + + if self.name == "BIOS": + fw_version = self.__get_bios_version() +- elif "CPLD" in self.name: ++ elif self.name == "CPLD1": + cpld_version = self.__get_cpld_version() + fw_version = cpld_version.get(self.name) ++ elif self.name == "CPLD2": ++ cpld_version = self.__get_cpldcpu_version() ++ fw_version = cpld_version.get(self.name) + + return fw_version + +@@ -99,4 +114,85 @@ class Component(ComponentBase): + Returns: + A boolean, True if install successfully, False if not + """ +- raise NotImplementedError ++ ret, output = getstatusoutput_noshell(["tar", "-C", "/tmp", "-xzf", image_path ] ) ++ if ret != 0 : ++ print("Installation failed because of wrong image package") ++ return False ++ ++ if False == os.path.exists("/tmp/install.json") : ++ print("Installation failed without jsonfile") ++ return False ++ ++ input_file = open ('/tmp/install.json') ++ json_array = json.load(input_file) ++ ret = 1 ++ for item in json_array: ++ if item.get('id')==None or item.get('path')==None: ++ continue ++ if self.name == item['id'] and item['path'] and item.get('cpu'): ++ print( "Find", item['id'], item['path'], item['cpu'] ) ++ ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'], item['cpu'] ]) ++ if ret==0: ++ break ++ elif self.name == item['id'] and item['path']: ++ print( "Find", item['id'], item['path'] ) ++ ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'] ]) ++ if ret==0: ++ break ++ ++ if ret==0: ++ return True ++ else : ++ return False ++ ++ def get_presence(self): ++ """ ++ Retrieves the presence of the device ++ Returns: ++ bool: True if device is present, False if not ++ """ ++ return True ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ return 'N/A' ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return 'N/A' ++ ++ def get_status(self): ++ """ ++ Retrieves the operational status of the device ++ Returns: ++ A boolean value, True if device is operating properly, False if not ++ """ ++ return True ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. ++ If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of ++ entPhysicalContainedIn is'0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device ++ or -1 if cannot determine the position ++ """ ++ return -1 ++ ++ def is_replaceable(self): ++ """ ++ Indicate whether this device is replaceable. ++ Returns: ++ bool: True if it is replaceable. ++ """ ++ return False +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py +index 7bf2bb58d..f3bc202eb 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py +@@ -13,7 +13,7 @@ except ImportError as e: + + CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' + CACHE_FILE = 'syseeprom_cache' +- ++NULL = 'N/A' + + class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + +@@ -33,7 +33,7 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + for line in lines: + try: + match = re.search( +- '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) ++ '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)(.+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') +@@ -92,11 +92,46 @@ class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + return self.__parse_output(decode_output) + ++ def _valid_tlv(self, eeprom_data): ++ tlvinfo_type_codes_list = [ ++ self._TLV_CODE_PRODUCT_NAME, ++ self._TLV_CODE_PART_NUMBER, ++ self._TLV_CODE_SERIAL_NUMBER, ++ self._TLV_CODE_MAC_BASE, ++ self._TLV_CODE_MANUF_DATE, ++ self._TLV_CODE_DEVICE_VERSION, ++ self._TLV_CODE_LABEL_REVISION, ++ self._TLV_CODE_PLATFORM_NAME, ++ self._TLV_CODE_ONIE_VERSION, ++ self._TLV_CODE_MAC_SIZE, ++ self._TLV_CODE_MANUF_NAME, ++ self._TLV_CODE_MANUF_COUNTRY, ++ self._TLV_CODE_VENDOR_NAME, ++ self._TLV_CODE_DIAG_VERSION, ++ self._TLV_CODE_SERVICE_TAG, ++ self._TLV_CODE_VENDOR_EXT, ++ self._TLV_CODE_CRC_32 ++ ] ++ ++ for code in tlvinfo_type_codes_list: ++ code_str = "0x{:X}".format(code) ++ eeprom_data[code_str] = eeprom_data.get(code_str, NULL) ++ return eeprom_data ++ + def get_eeprom(self): +- return self._eeprom ++ return self._valid_tlv(self._eeprom) ++ ++ def get_pn(self): ++ return self._eeprom.get('0x22', NULL) + + def get_serial(self): +- return self._eeprom.get('0x23', "Undefined.") ++ return self._eeprom.get('0x23', NULL) + + def get_mac(self): +- return self._eeprom.get('0x24', "Undefined.") ++ return self._eeprom.get('0x24', NULL) ++ ++ def get_modelstr(self): ++ return self._eeprom.get('0x21', NULL) ++ ++ def get_revisionstr(self): ++ return self._eeprom.get('0x27', NULL) +\ No newline at end of file +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/event.py +new file mode 100644 +index 000000000..ade466b2e +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/event.py +@@ -0,0 +1,109 @@ ++try: ++ import time ++ from sonic_py_common.logger import Logger ++ from .sfp import Sfp ++except ImportError as e: ++ raise ImportError(repr(e) + " - required module not found") ++ ++POLL_INTERVAL_IN_SEC = 1 ++ ++# SFP errors that will block eeprom accessing ++SFP_BLOCKING_ERRORS = [ ++ Sfp.SFP_ERROR_BIT_I2C_STUCK, ++ Sfp.SFP_ERROR_BIT_BAD_EEPROM, ++ Sfp.SFP_ERROR_BIT_UNSUPPORTED_CABLE, ++ Sfp.SFP_ERROR_BIT_HIGH_TEMP, ++ Sfp.SFP_ERROR_BIT_BAD_CABLE ++] ++ ++class SfpEvent: ++ ''' Listen to insert/remove sfp events ''' ++ ++ def __init__(self, sfp_list): ++ self._sfp_list = sfp_list ++ self._logger = Logger() ++ self._sfp_change_event_data = {'present': 0} ++ ++ def get_presence_bitmap(self): ++ bitmap = 0 ++ for sfp in self._sfp_list: ++ modpres = sfp.get_presence() ++ i=sfp.get_position_in_parent() - 1 ++ if modpres: ++ bitmap = bitmap | (1 << i) ++ return bitmap ++ ++ def get_sfp_event(self, timeout=2000): ++ port_dict = {} ++ change_dict = {} ++ change_dict['sfp'] = port_dict ++ ++ if timeout < 1000: ++ cd_ms = 1000 ++ else: ++ cd_ms = timeout ++ ++ while cd_ms > 0: ++ bitmap = self.get_presence_bitmap() ++ changed_ports = self._sfp_change_event_data['present'] ^ bitmap ++ if changed_ports != 0: ++ break ++ time.sleep(POLL_INTERVAL_IN_SEC) ++ # timeout=0 means wait for event forever ++ if timeout != 0: ++ cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 ++ ++ if changed_ports != 0: ++ for sfp in self._sfp_list: ++ i=sfp.get_position_in_parent() - 1 ++ if (changed_ports & (1 << i)) == 0: ++ continue ++ ++ if (bitmap & (1 << i)) == 0: ++ port_dict[i+1] = '0' ++ else: ++ # sfp.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 +\ No newline at end of file +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py +index 8f4893124..e14550355 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py +@@ -38,10 +38,6 @@ PSU_CPLD_I2C_MAPPING = { + }, + } + +- +-FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", +- "FAN-3F", "FAN-3R"] +- + class Fan(FanBase): + """Platform-specific Fan class""" + +@@ -63,7 +59,7 @@ class Fan(FanBase): + self.psu_cpld_path = I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + +- FanBase.__init__(self) ++ FanBase.__init__(self) + + + def get_direction(self): +@@ -73,16 +69,14 @@ class Fan(FanBase): + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ +- +- + if not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'direction_', self.fan_tray_index+1) + val=self._api_helper.read_txt_file(dir_str) + if val is not None: + if int(val, 10)==0:#F2B +- direction=self.FAN_DIRECTION_EXHAUST +- else: + direction=self.FAN_DIRECTION_INTAKE ++ else: ++ direction=self.FAN_DIRECTION_EXHAUST + else: + direction=self.FAN_DIRECTION_EXHAUST + +@@ -105,7 +99,7 @@ class Fan(FanBase): + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) +- ++ + """ + speed = 0 + if self.is_psu_fan: +@@ -117,7 +111,7 @@ class Fan(FanBase): + speed=100 + else: + return 0 +- elif self.get_presence(): ++ elif self.get_presence(): + speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage') + speed=self._api_helper.read_txt_file(speed_path) + if speed is None: +@@ -156,7 +150,7 @@ class Fan(FanBase): + A boolean, True if speed is set successfully, False if not + """ + +- if not self.is_psu_fan and self.get_presence(): ++ if not self.is_psu_fan and self.get_presence(): + speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage') + return self._api_helper.write_txt_file(speed_path, int(speed)) + +@@ -179,14 +173,13 @@ class Fan(FanBase): + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ +- status=self.get_presence() +- if status is None: +- return self.STATUS_LED_COLOR_OFF ++ if self.is_psu_fan: ++ return None + + return { +- 1: self.STATUS_LED_COLOR_GREEN, +- 0: self.STATUS_LED_COLOR_RED +- }.get(status, self.STATUS_LED_COLOR_OFF) ++ True: self.STATUS_LED_COLOR_GREEN, ++ False: self.STATUS_LED_COLOR_OFF ++ }.get(self.get_status(), self.STATUS_LED_COLOR_OFF) + + def get_name(self): + """ +@@ -194,11 +187,10 @@ class Fan(FanBase): + Returns: + string: The name of the device + """ +- fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ +- if not self.is_psu_fan \ +- else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) ++ if self.is_psu_fan: ++ return "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + +- return fan_name ++ return "FAN-{}".format(self.fan_tray_index+1) + + def get_presence(self): + """ +@@ -206,8 +198,6 @@ class Fan(FanBase): + Returns: + bool: True if FAN is present, False if not + """ +- +- + if self.is_psu_fan: + present_path="{}{}".format(self.psu_cpld_path, 'psu_present') + else: +@@ -226,6 +216,11 @@ class Fan(FanBase): + A boolean value, True if device is operating properly, False if not + """ + if self.is_psu_fan: ++ psu_fan_path = "{}{}".format(self.psu_cpld_path, 'psu_power_good') ++ val = self._api_helper.read_txt_file(psu_fan_path) ++ if val is None or int(val, 10)==0: ++ return False ++ + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') + val=self._api_helper.read_txt_file(psu_fan_path) + if val is not None: +@@ -268,7 +263,7 @@ class Fan(FanBase): + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ +- return (self.fan_tray_index+1) \ ++ return (self.fan_index+1) \ + if not self.is_psu_fan else (self.psu_index+1) + + def is_replaceable(self): +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py +index e21163c10..b4c2146b9 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py +@@ -10,7 +10,7 @@ try: + except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +-FANS_PER_FANTRAY = 2 ++FANS_PER_FANTRAY = 1 + + + class FanDrawer(FanDrawerBase): +@@ -88,3 +88,25 @@ class FanDrawer(FanDrawerBase): + bool: True if it is replaceable. + """ + return True ++ ++ def set_status_led(self, color): ++ """ ++ Sets the state of the fan module status LED ++ Args: ++ color: A string representing the color with which to set the ++ fan module status LED ++ Returns: ++ bool: True if status LED state is set successfully, False if not ++ """ ++ return False # Not supported ++ ++ def get_status_led(self): ++ """ ++ Gets the state of the fan status LED ++ Returns: ++ A string, one of the predefined STATUS_LED_COLOR_* strings above ++ """ ++ return { ++ True: self.STATUS_LED_COLOR_GREEN, ++ False: self.STATUS_LED_COLOR_OFF ++ }.get(self.get_status(), self.STATUS_LED_COLOR_OFF) +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py +index b19fab85d..f6adee309 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py +@@ -1,8 +1,14 @@ + import os + import struct +-import subprocess ++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 = "" +@@ -14,7 +20,11 @@ class APIHelper(): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): +- return subprocess.call(HOST_CHK_CMD) == 0 ++ try: ++ status, output = getstatusoutput_noshell(HOST_CHK_CMD) ++ return status == 0 ++ except Exception: ++ return False + + def pci_get_value(self, resource, offset): + status = True +@@ -29,11 +39,20 @@ class APIHelper(): + status = False + return status, result + ++ def run_interactive_command(self, cmd): ++ try: ++ os.system(cmd) ++ except Exception: ++ return False ++ return True ++ + def read_txt_file(self, file_path): + try: + with open(file_path, 'r', errors='replace') as fd: + data = fd.read() +- return data.strip() ++ ret = data.strip() ++ if len(ret) > 0: ++ return ret + except IOError: + pass + return None +@@ -46,3 +65,304 @@ class APIHelper(): + 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/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/pcie.py +new file mode 100644 +index 000000000..73d3627db +--- /dev/null ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/pcie.py +@@ -0,0 +1,19 @@ ++############################################################################# ++# Edgecore ++# ++# Module contains an implementation of SONiC Platform Base API and ++# provides the fan status which are available in the platform ++# Base PCIe class ++############################################################################# ++ ++try: ++ from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil ++except ImportError as e: ++ raise ImportError(str(e) + "- required module not found") ++ ++ ++class Pcie(PcieUtil): ++ """Edgecore Platform-specific PCIe class""" ++ ++ def __init__(self, platform_path): ++ PcieUtil.__init__(self, platform_path) +\ No newline at end of file +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py +index 8eab43891..6df7fd3ff 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py +@@ -10,7 +10,7 @@ + + try: + from sonic_platform_base.psu_base import PsuBase +- #from sonic_platform.fan import Fan ++ from sonic_platform.thermal import Thermal + from .helper import APIHelper + except ImportError as e: + raise ImportError(str(e) + "- required module not found") +@@ -58,19 +58,13 @@ class Psu(PsuBase): + self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"] + self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + self.__initialize_fan() +- ''' +- for fan_index in range(0, PSU_NUM_FAN[self.index]): +- #def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): +- #fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) +- fan = Fan(fan_index, 0, True, self.index) +- self._fan_list.append(fan) +- ''' + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + self._fan_list.append(fan) ++ self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index)) + + def get_voltage(self): + """ +@@ -79,12 +73,15 @@ class Psu(PsuBase): + A float number, the output voltage in volts, + e.g. 12.1 + """ ++ if self.get_status() is not True: ++ return 0.0 ++ + vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: +- return 0 ++ return 0.0 + + def get_current(self): + """ +@@ -92,12 +89,15 @@ class Psu(PsuBase): + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ ++ if self.get_status() is not True: ++ return 0.0 ++ + iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: +- return 0 ++ return 0.0 + + def get_power(self): + """ +@@ -105,12 +105,15 @@ class Psu(PsuBase): + Returns: + A float number, the power in watts, e.g. 302.6 + """ ++ if self.get_status() is not True: ++ return 0.0 ++ + pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: +- return 0 ++ return 0.0 + + def get_powergood_status(self): + """ +@@ -156,12 +159,15 @@ class Psu(PsuBase): + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ ++ if self.get_status() is not True: ++ return 0.0 ++ + temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: +- return 0 ++ return 0.0 + + def get_temperature_high_threshold(self): + """ +@@ -170,7 +176,7 @@ class Psu(PsuBase): + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ +- return False #Not supported ++ return self._thermal_list[0].get_high_threshold() + + def get_voltage_high_threshold(self): + """ +@@ -179,12 +185,15 @@ class Psu(PsuBase): + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ ++ if self.get_status() is not True: ++ return 0.0 ++ + vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: +- return 0 ++ return 0.0 + + def get_voltage_low_threshold(self): + """ +@@ -193,12 +202,15 @@ class Psu(PsuBase): + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ ++ if self.get_status() is not True: ++ return 0.0 ++ + vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min') + vout_val=self._api_helper.read_txt_file(vout_path) + if vout_val is not None: + return float(vout_val)/ 1000 + else: +- return 0 ++ return 0.0 + + def get_name(self): + """ +@@ -219,7 +231,7 @@ class Psu(PsuBase): + if val is not None: + return int(val, 10) == 1 + else: +- return 0 ++ return False + + def get_status(self): + """ +@@ -232,7 +244,7 @@ class Psu(PsuBase): + if val is not None: + return int(val, 10) == 1 + else: +- return 0 ++ return False + + def get_model(self): + """ +@@ -275,3 +287,34 @@ class Psu(PsuBase): + bool: True if it is replaceable. + """ + return True ++ ++ def get_revision(self): ++ """ ++ Retrieves the hardware revision of the device ++ ++ Returns: ++ string: Revision value of device ++ """ ++ revision_path = "{}{}".format(self.hwmon_path, 'psu_mfr_revision') ++ revision = self._api_helper.read_txt_file(revision_path) ++ if revision is None: ++ return 'N/A' ++ ++ return revision ++ ++ def get_maximum_supplied_power(self): ++ """ ++ Retrieves the maximum supplied power by PSU ++ Returns: ++ A float number, the maximum power output in Watts. ++ e.g. 1200.1 ++ """ ++ if self.get_status() is not True: ++ return 0.0 ++ ++ pout_max_path = "{}{}".format(self.hwmon_path, 'psu_mfr_pout_max') ++ val=self._api_helper.read_txt_file(pout_max_path) ++ if val is not None: ++ return float(val)/1000 ++ else: ++ return 0.0 +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py +index adab3d294..d6f894b28 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py +@@ -1,5 +1,3 @@ +-#!/usr/bin/env python +- + ############################################################################# + # Edgecore + # +@@ -8,115 +6,26 @@ + # + ############################################################################# + ++import os + import time +-import sys +-import subprocess +-from ctypes import create_string_buffer + + try: +- from sonic_platform_base.sfp_base import SfpBase +- from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom +- from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId +- from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom +- from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId +- #from sonic_platform_base.sonic_sfp.sff8472 import sffbase ++ from sonic_py_common.logger import Logger ++ from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper ++ from sonic_py_common import device_info + except ImportError as e: + raise ImportError(str(e) + "- required module not found") + ++NONE_SFP_TYPE = "NONE-SFP" ++SFP_TYPE = "SFP" ++QSFP_TYPE = "QSFP" ++ + CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0060/" + +-QSFP_INFO_OFFSET = 128 +-QSFP_DOM_OFFSET = 0 +- +-SFP_INFO_OFFSET = 0 +-SFP_DOM_OFFSET = 256 +- +-XCVR_INTFACE_BULK_OFFSET = 0 +-XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +-XCVR_INTFACE_BULK_WIDTH_SFP = 21 +-XCVR_HW_REV_WIDTH_QSFP = 2 +-XCVR_HW_REV_WIDTH_SFP = 4 +-XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +-XCVR_VENDOR_NAME_OFFSET = 20 +-XCVR_VENDOR_NAME_WIDTH = 16 +-XCVR_VENDOR_OUI_OFFSET = 37 +-XCVR_VENDOR_OUI_WIDTH = 3 +-XCVR_VENDOR_PN_OFFSET = 40 +-XCVR_VENDOR_PN_WIDTH = 16 +-XCVR_HW_REV_OFFSET = 56 +-XCVR_HW_REV_WIDTH_OSFP = 2 +-XCVR_HW_REV_WIDTH_SFP = 4 +-XCVR_VENDOR_SN_OFFSET = 68 +-XCVR_VENDOR_SN_WIDTH = 16 +-XCVR_VENDOR_DATE_OFFSET = 84 +-XCVR_VENDOR_DATE_WIDTH = 8 +-XCVR_DOM_CAPABILITY_OFFSET = 92 +-XCVR_DOM_CAPABILITY_WIDTH = 1 +- +-# Offset for values in QSFP eeprom +-QSFP_DOM_REV_OFFSET = 1 +-QSFP_DOM_REV_WIDTH = 1 +-QSFP_TEMPE_OFFSET = 22 +-QSFP_TEMPE_WIDTH = 2 +-QSFP_VOLT_OFFSET = 26 +-QSFP_VOLT_WIDTH = 2 +-QSFP_CHANNL_MON_OFFSET = 34 +-QSFP_CHANNL_MON_WIDTH = 16 +-QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +-QSFP_CONTROL_OFFSET = 86 +-QSFP_CONTROL_WIDTH = 8 +-QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +-QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +-QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +-QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +-QSFP_POWEROVERRIDE_OFFSET = 93 +-QSFP_POWEROVERRIDE_WIDTH = 1 +-QSFP_PAGE03_OFFSET = 384 +-QSFP_MODULE_THRESHOLD_OFFSET = 128 +-QSFP_MODULE_THRESHOLD_WIDTH = 24 +-QSFP_CHANNEL_THRESHOLD_OFFSET = 176 +-QSFP_CHANNEL_THRESHOLD_WIDTH = 16 +- +-qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', +- 'Length OM2(m)', 'Length OM1(m)', +- 'Length Cable Assembly(m)') +- +-qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', +- 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', +- 'Fibre Channel link length/Transmitter Technology', +- 'Fibre Channel transmission media', 'Fibre Channel Speed') +- +- +-# Offset for values in SFP eeprom +-SFP_TEMPE_OFFSET = 96 +-SFP_TEMPE_WIDTH = 2 +-SFP_VOLT_OFFSET = 98 +-SFP_VOLT_WIDTH = 2 +-SFP_CHANNL_MON_OFFSET = 100 +-SFP_CHANNL_MON_WIDTH = 6 +-SFP_MODULE_THRESHOLD_OFFSET = 0 +-SFP_MODULE_THRESHOLD_WIDTH = 40 +-SFP_CHANNL_THRESHOLD_OFFSET = 112 +-SFP_CHANNL_THRESHOLD_WIDTH = 2 +-SFP_STATUS_CONTROL_OFFSET = 110 +-SFP_STATUS_CONTROL_WIDTH = 1 +-SFP_TX_DISABLE_HARD_BIT = 7 +-SFP_TX_DISABLE_SOFT_BIT = 6 +- +-sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', +- 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', +- 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') +- +-sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', +- 'ESCONComplianceCodes', 'SONETComplianceCodes', +- 'EthernetComplianceCodes', 'FibreChannelLinkLength', +- 'FibreChannelTechnology', 'SFP+CableTechnology', +- 'FibreChannelTransmissionMedia', 'FibreChannelSpeed') +- +- +-class Sfp(SfpBase): ++logger = Logger() ++class Sfp(SfpOptoeBase): + """Platform-specific Sfp class""" + + # Port number +@@ -126,10 +35,7 @@ class Sfp(SfpBase): + # Path to sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" +- HOST_CHK_CMD = ["docker"] +- +- PLATFORM = "x86_64-accton_as4630_54te-r0" +- HWSKU = "Accton-AS4630-54TE" ++ HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" + + _port_to_i2c_mapping = { + 49: 18, +@@ -140,510 +46,41 @@ class Sfp(SfpBase): + 54: 23, + } + ++ 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, sfp_index=0): ++ SfpOptoeBase.__init__(self) + self._api_helper=APIHelper() + # Init index +- self.index = sfp_index +- self.port_num = self.index + 1 ++ self.port_num = sfp_index + 1 ++ self.index = self.port_num ++ if self.port_num < self.PORT_START: ++ self.sfp_type = NONE_SFP_TYPE ++ elif self.port_num < 53: ++ self.sfp_type = SFP_TYPE ++ else: ++ self.sfp_type = QSFP_TYPE ++ + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + for x in range(self.PORT_START, self.PORT_END + 1): + self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x]) + +- self.info_dict_keys = ['type', 'vendor_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier', +- 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui', +- 'application_advertisement', 'type_abbrv_name'] +- +- self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', +- 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] +- +- self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', +- 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] +- +- SfpBase.__init__(self) +- +- def _convert_string_to_num(self, value_str): +- if "-inf" in value_str: +- return 'N/A' +- elif "Unknown" in value_str: +- return 'N/A' +- elif 'dBm' in value_str: +- t_str = value_str.rstrip('dBm') +- return float(t_str) +- elif 'mA' in value_str: +- t_str = value_str.rstrip('mA') +- return float(t_str) +- elif 'C' in value_str: +- t_str = value_str.rstrip('C') +- return float(t_str) +- elif 'Volts' in value_str: +- t_str = value_str.rstrip('Volts') +- return float(t_str) +- else: +- return 'N/A' +- +- def __write_txt_file(self, file_path, value): +- try: +- with open(file_path, 'w', buffering=0) as fd: +- fd.write(str(value)) +- except Exception: +- return False +- return True ++ def get_eeprom_path(self): ++ return self.port_to_eeprom_mapping[self.port_num] + + def __is_host(self): +- return subprocess.call(self.HOST_CHK_CMD) == 0 +- +- def __get_path_to_port_config_file(self): +- platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) +- hwsku_path = "/".join([platform_path, self.HWSKU] +- ) if self.__is_host() else self.PMON_HWSKU_PATH +- return "/".join([hwsku_path, "port_config.ini"]) +- +- def __read_eeprom_specific_bytes(self, offset, num_bytes): +- sysfsfile_eeprom = None +- eeprom_raw = [] +- for i in range(0, num_bytes): +- eeprom_raw.append("0x00") +- +- sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] +- try: +- sysfsfile_eeprom = open( +- sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) +- sysfsfile_eeprom.seek(offset) +- raw = sysfsfile_eeprom.read(num_bytes) +- if sys.version_info[0] >= 3: +- for n in range(0, num_bytes): +- eeprom_raw[n] = hex(raw[n])[2:].zfill(2) +- else: +- for n in range(0, num_bytes): +- eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) +- except Exception: +- pass +- finally: +- if sysfsfile_eeprom: +- sysfsfile_eeprom.close() +- +- return eeprom_raw +- +- def get_transceiver_info(self): +- """ +- Retrieves transceiver info of this SFP +- Returns: +- A dict which contains following keys/values : +- ======================================================================== +- keys |Value Format |Information +- ---------------------------|---------------|---------------------------- +- type |1*255VCHAR |type of SFP +- vendor_rev |1*255VCHAR |vendor revision of SFP +- serial |1*255VCHAR |serial number of the SFP +- manufacturer |1*255VCHAR |SFP vendor name +- model |1*255VCHAR |SFP model name +- connector |1*255VCHAR |connector information +- encoding |1*255VCHAR |encoding information +- ext_identifier |1*255VCHAR |extend identifier +- ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance +- cable_length |INT |cable length in m +- nominal_bit_rate |INT |nominal bit rate by 100Mbs +- specification_compliance |1*255VCHAR |specification compliance +- vendor_date |1*255VCHAR |vendor date +- vendor_oui |1*255VCHAR |vendor OUI +- application_advertisement |1*255VCHAR |supported applications advertisement +- ======================================================================== +- """ +- # check present status +- if self.port_num < 49: +- return {} +- elif self.port_num < 53: +- sfpi_obj = sff8472InterfaceId() #SFP +- else: +- sfpi_obj = sff8436InterfaceId() #QSFP +- if not self.get_presence() or not sfpi_obj: +- return {} +- +- if self.port_num < 53: +- offset = SFP_INFO_OFFSET +- sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP) +- else: +- offset = QSFP_INFO_OFFSET +- sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP) +- +- sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( +- sfp_interface_bulk_raw, 0) +- +- sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) +- sfp_vendor_name_data = sfpi_obj.parse_vendor_name( +- sfp_vendor_name_raw, 0) +- +- sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) +- sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( +- sfp_vendor_pn_raw, 0) +- +- if self.port_num < 53: +- sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) +- else: +- sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP) +- +- sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( +- sfp_vendor_rev_raw, 0) +- +- sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) +- sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( +- sfp_vendor_sn_raw, 0) +- +- sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) +- if sfp_vendor_oui_raw is not None: +- sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( +- sfp_vendor_oui_raw, 0) +- +- sfp_vendor_date_raw = self.__read_eeprom_specific_bytes( +- (offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) +- sfp_vendor_date_data = sfpi_obj.parse_vendor_date( +- sfp_vendor_date_raw, 0) +- +- transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') +- compliance_code_dict = dict() +- +- if sfp_interface_bulk_data: +- transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] +- transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] +- transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] +- transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] +- transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] +- transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] +- +- transceiver_info_dict['manufacturer'] = sfp_vendor_name_data[ +- 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' +- transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' +- transceiver_info_dict['vendor_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' +- transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' +- transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' +- transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ +- 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' +- transceiver_info_dict['cable_type'] = "Unknown" +- transceiver_info_dict['cable_length'] = "Unknown" +- +- if self.port_num < 53: +- for key in sfp_cable_length_tup: +- if key in sfp_interface_bulk_data['data']: +- transceiver_info_dict['cable_type'] = key +- transceiver_info_dict['cable_length'] = str( +- sfp_interface_bulk_data['data'][key]['value']) +- +- for key in sfp_compliance_code_tup: +- if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: +- compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] +- +- transceiver_info_dict['specification_compliance'] = str( +- compliance_code_dict) +- transceiver_info_dict['nominal_bit_rate'] = str( +- sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) +- else: +- for key in qsfp_cable_length_tup: +- if key in sfp_interface_bulk_data['data']: +- transceiver_info_dict['cable_type'] = key +- transceiver_info_dict['cable_length'] = str( +- sfp_interface_bulk_data['data'][key]['value']) +- +- for key in qsfp_compliance_code_tup: +- if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: +- compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] +- +- transceiver_info_dict['specification_compliance'] = str( +- compliance_code_dict) +- transceiver_info_dict['nominal_bit_rate'] = str( +- sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) +- +- +- return transceiver_info_dict +- +- def get_transceiver_bulk_status(self): +- """ +- Retrieves transceiver bulk status of this SFP +- Returns: +- A dict which contains following keys/values : +- ======================================================================== +- keys |Value Format |Information +- ---------------------------|---------------|---------------------------- +- rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. +- tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. +- reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. +- lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. +- tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. +- tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 +- | |to channel 3. +- temperature |INT |module temperature in Celsius +- voltage |INT |supply voltage in mV +- txbias |INT |TX Bias Current in mA, n is the channel number, +- | |for example, tx2bias stands for tx bias of channel 2. +- rxpower |INT |received optical power in mW, n is the channel number, +- | |for example, rx2power stands for rx power of channel 2. +- txpower |INT |TX output power in mW, n is the channel number, +- | |for example, tx2power stands for tx power of channel 2. +- ======================================================================== +- """ +- # check present status +- if self.port_num < 53: #SFP case +- sfpd_obj = sff8472Dom() +- if not self.get_presence() or not sfpd_obj: +- return {} +- +- eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) +- sfpi_obj = sff8472InterfaceId(eeprom_ifraw) +- cal_type = sfpi_obj.get_calibration_type() +- sfpd_obj._calibration_type = cal_type +- +- offset = SFP_DOM_OFFSET +- transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') +- dom_temperature_raw = self.__read_eeprom_specific_bytes( +- (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) +- +- if dom_temperature_raw is not None: +- dom_temperature_data = sfpd_obj.parse_temperature( +- dom_temperature_raw, 0) +- transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] +- +- dom_voltage_raw = self.__read_eeprom_specific_bytes( +- (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) +- if dom_voltage_raw is not None: +- dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) +- transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] +- +- dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( +- (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) +- if dom_channel_monitor_raw is not None: +- dom_voltage_data = sfpd_obj.parse_channel_monitor_params( +- dom_channel_monitor_raw, 0) +- transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] +- transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] +- transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] +- +- else: #QSFP case +- sfpd_obj = sff8436Dom() +- sfpi_obj = sff8436InterfaceId() +- +- if not self.get_presence() or not sfpi_obj or not sfpd_obj: +- return {} +- +- transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') +- offset = QSFP_DOM_OFFSET +- offset_xcvr = QSFP_INFO_OFFSET +- +- # QSFP capability byte parse, through this byte can know whether it support tx_power or not. +- # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, +- # need to add more code for determining the capability and version compliance +- # in SFF-8636 dom capability definitions evolving with the versions. +- qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( +- (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) +- if qsfp_dom_capability_raw is not None: +- qspf_dom_capability_data = sfpi_obj.parse_dom_capability( +- qsfp_dom_capability_raw, 0) +- else: +- return None +- +- dom_temperature_raw = self.__read_eeprom_specific_bytes( +- (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) +- if dom_temperature_raw is not None: +- dom_temperature_data = sfpd_obj.parse_temperature( +- dom_temperature_raw, 0) +- transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] +- +- dom_voltage_raw = self.__read_eeprom_specific_bytes( +- (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) +- if dom_voltage_raw is not None: +- dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) +- transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] +- +- qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( +- (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) +- if qsfp_dom_rev_raw is not None: +- qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) +- qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] +- +- # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 +- # and claimed that it support tx_power with one indicator bit. +- dom_channel_monitor_data = {} +- dom_channel_monitor_raw = None +- qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] +- if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): +- dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( +- (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) +- if dom_channel_monitor_raw is not None: +- dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( +- dom_channel_monitor_raw, 0) +- +- else: +- dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( +- (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) +- if dom_channel_monitor_raw is not None: +- dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( +- dom_channel_monitor_raw, 0) +- transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] +- transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] +- transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] +- transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] +- +- if dom_channel_monitor_raw: +- transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] +- transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] +- transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] +- transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] +- transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] +- transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] +- transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] +- transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] +- #End of else +- +- +- for key in transceiver_dom_info_dict: +- transceiver_dom_info_dict[key] = self._convert_string_to_num( +- transceiver_dom_info_dict[key]) +- +- transceiver_dom_info_dict['rx_los'] = self.get_rx_los() +- transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() +- transceiver_dom_info_dict['reset_status'] = self.get_reset_status() +- transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() +- +- return transceiver_dom_info_dict +- +- def get_transceiver_threshold_info(self): +- """ +- Retrieves transceiver threshold info of this SFP +- Returns: +- A dict which contains following keys/values : +- ======================================================================== +- keys |Value Format |Information +- ---------------------------|---------------|---------------------------- +- temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. +- templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. +- temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. +- templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. +- vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. +- vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. +- vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. +- vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. +- rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. +- rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. +- rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. +- rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. +- txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. +- txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. +- txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. +- txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. +- txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. +- txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. +- txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. +- txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. +- ======================================================================== +- """ +- # check present status +- if self.port_num < 53: +- sfpd_obj = sff8472Dom() +- +- if not self.get_presence() and not sfpd_obj: +- return {} +- +- eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) +- sfpi_obj = sff8472InterfaceId(eeprom_ifraw) +- cal_type = sfpi_obj.get_calibration_type() +- sfpd_obj._calibration_type = cal_type +- +- offset = SFP_DOM_OFFSET +- transceiver_dom_threshold_info_dict = dict.fromkeys( +- self.threshold_dict_keys, 'N/A') +- dom_module_threshold_raw = self.__read_eeprom_specific_bytes( +- (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) +- if dom_module_threshold_raw is not None: +- dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold( +- dom_module_threshold_raw, 0) +- +- transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] +- transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] +- transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] +- transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] +- transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] +- transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] +- transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ +- 'data']['VoltageHighWarning']['value'] +- transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] +- transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] +- transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] +- transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] +- transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] +- transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] +- transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] +- transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] +- transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] +- transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] +- transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] +- transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] +- transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] +- +- for key in transceiver_dom_threshold_info_dict: +- transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( +- transceiver_dom_threshold_info_dict[key]) +- +- return transceiver_dom_threshold_info_dict +- +- +- else: +- sfpd_obj = sff8436Dom() +- +- if not self.get_presence() or not sfpd_obj: +- return {} +- +- offset = QSFP_PAGE03_OFFSET +- transceiver_dom_threshold_dict = dict.fromkeys( +- self.threshold_dict_keys, 'N/A') +- dom_thres_raw = self.__read_eeprom_specific_bytes( +- offset + QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None +- +- if dom_thres_raw: +- module_threshold_values = sfpd_obj.parse_module_threshold_values( +- dom_thres_raw, 0) +- module_threshold_data = module_threshold_values.get('data') +- if module_threshold_data: +- transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] +- transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] +- transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] +- transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] +- transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] +- transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] +- transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] +- transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] +- +- dom_thres_raw = self.__read_eeprom_specific_bytes( +- offset + QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None +- channel_threshold_values = sfpd_obj.parse_channel_threshold_values( +- dom_thres_raw, 0) +- channel_threshold_data = channel_threshold_values.get('data') +- if channel_threshold_data: +- transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] +- transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] +- transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] +- transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] +- transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" +- transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" +- transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" +- transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" +- transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] +- transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] +- transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] +- transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] +- +- for key in transceiver_dom_threshold_dict: +- transceiver_dom_threshold_dict[key] = self._convert_string_to_num( +- transceiver_dom_threshold_dict[key]) +- +- return transceiver_dom_threshold_dict ++ return os.system(self.HOST_CHK_CMD) == 0 + + def get_reset_status(self): + """ +@@ -651,7 +88,7 @@ class Sfp(SfpBase): + Returns: + A Boolean, True if reset enabled, False if disabled + """ +- if self.port_num < 53: # non-QSFP ports don't support it. ++ if self.port_num < 53: #Copper port and sfp ports aren't supported. + return False + + reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num)) +@@ -660,7 +97,7 @@ class Sfp(SfpBase): + if val is not None: + return int(val, 10) == 1 + else: +- return False ++ return False # CPLD port doesn't support this feature + + def get_rx_los(self): + """ +@@ -669,34 +106,29 @@ class Sfp(SfpBase): + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ +- rx_los = False ++ rx_los = [False] + + if self.port_num < 49: #Copper port, no sysfs +- return False ++ return [False] + + if self.port_num < 53: +- rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num) ++ rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num) + rx_los=self._api_helper.read_txt_file(rx_path) +- if rx_los is None: +- return False +- #status_control_raw = self.__read_eeprom_specific_bytes( +- # SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) +- #if status_control_raw: +- # data = int(status_control_raw[0], 16) +- # rx_los = (sffbase().test_bit(data, 1) != 0) +- ++ if rx_los is not None: ++ if rx_los == '1': ++ return [True] ++ else: ++ return [False] ++ else: ++ return [False] + else: +- rx_los_list = [] +- dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( +- QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None +- if dom_channel_monitor_raw is not None: +- rx_los_data = int(dom_channel_monitor_raw[0], 16) +- rx_los_list.append(rx_los_data & 0x01 != 0) +- rx_los_list.append(rx_los_data & 0x02 != 0) +- rx_los_list.append(rx_los_data & 0x04 != 0) +- rx_los_list.append(rx_los_data & 0x08 != 0) +- rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3] +- return rx_los ++ api = self.get_xcvr_api() ++ if api is not None: ++ rx_los = api.get_rx_los() ++ if isinstance(rx_los, list) and "N/A" in rx_los: ++ return [False for _ in rx_los] ++ return rx_los ++ return None + + def get_tx_fault(self): + """ +@@ -705,33 +137,28 @@ class Sfp(SfpBase): + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ +- tx_fault = False ++ tx_fault = [False] + if self.port_num < 49: #Copper port, no sysfs +- return False ++ return [False] + + if self.port_num < 53: +- tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num) ++ tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num) + tx_fault=self._api_helper.read_txt_file(tx_path) +- if tx_fault is None: +- return False +- #status_control_raw = self.__read_eeprom_specific_bytes( +- # SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) +- #if status_control_raw: +- # data = int(status_control_raw[0], 16) +- # tx_fault = (sffbase().test_bit(data, 2) != 0) ++ if tx_fault is not None: ++ if tx_fault == '1': ++ return [True] ++ else: ++ return [False] ++ else: ++ return [False] + else: +- tx_fault_list = [] +- dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( +- QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None +- if dom_channel_monitor_raw is not None: +- tx_fault_data = int(dom_channel_monitor_raw[0], 16) +- tx_fault_list.append(tx_fault_data & 0x01 != 0) +- tx_fault_list.append(tx_fault_data & 0x02 != 0) +- tx_fault_list.append(tx_fault_data & 0x04 != 0) +- tx_fault_list.append(tx_fault_data & 0x08 != 0) +- tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3] +- +- return tx_fault ++ api = self.get_xcvr_api() ++ if api is not None: ++ tx_fault = api.get_tx_fault() ++ if isinstance(tx_fault, list) and "N/A" in tx_fault: ++ return [False for _ in tx_fault] ++ return tx_fault ++ return None + + def get_tx_disable(self): + """ +@@ -742,70 +169,19 @@ class Sfp(SfpBase): + if self.port_num < 49: #Copper port, no sysfs + return False + +- if self.port_num < 53: +- tx_disable = False ++ if self.port_num < 53: ++ tx_disable = False + + tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) + tx_disable=self._api_helper.read_txt_file(tx_path) +- +- +- #status_control_raw = self.__read_eeprom_specific_bytes( +- # SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) +- #if status_control_raw: +- # data = int(status_control_raw[0], 16) +- # tx_disable_hard = (sffbase().test_bit( +- # data, SFP_TX_DISABLE_HARD_BIT) != 0) +- # tx_disable_soft = (sffbase().test_bit( +- # data, SFP_TX_DISABLE_SOFT_BIT) != 0) +- # tx_disable = tx_disable_hard | tx_disable_soft + if tx_disable is not None: +- return tx_disable ++ return tx_disable + else: + return False + + else: +- tx_disable_list = [] +- +- sfpd_obj = sff8436Dom() +- if sfpd_obj is None: +- return False +- +- dom_control_raw = self.__read_eeprom_specific_bytes( +- QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None +- if dom_control_raw is not None: +- dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) +- tx_disable_list.append( +- 'On' == dom_control_data['data']['TX1Disable']['value']) +- tx_disable_list.append( +- 'On' == dom_control_data['data']['TX2Disable']['value']) +- tx_disable_list.append( +- 'On' == dom_control_data['data']['TX3Disable']['value']) +- tx_disable_list.append( +- 'On' == dom_control_data['data']['TX4Disable']['value']) +- +- return tx_disable_list +- +- def get_tx_disable_channel(self): +- """ +- Retrieves the TX disabled channels in this SFP +- Returns: +- A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent +- TX channels which have been disabled in this SFP. +- As an example, a returned value of 0x5 indicates that channel 0 +- and channel 2 have been disabled. +- """ +- if self.port_num < 53: +- # SFP doesn't support this feature +- return False +- else: +- tx_disable_list = self.get_tx_disable() +- if tx_disable_list is None: +- return 0 +- tx_disabled = 0 +- for i in range(len(tx_disable_list)): +- if tx_disable_list[i]: +- tx_disabled |= 1 << i +- return tx_disabled ++ api = self.get_xcvr_api() ++ return api.get_tx_disable() if api is not None else None + + def get_lpmode(self): + """ +@@ -813,7 +189,7 @@ class Sfp(SfpBase): + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ +- if self.port_num < 53: ++ if self.port_num < 53: + # SFP doesn't support this feature + return False + else: +@@ -821,124 +197,14 @@ class Sfp(SfpBase): + power_override = self.get_power_override() + return power_set and power_override + +- +- def get_power_set(self): +- +- if self.port_num < 53: ++ def get_power_set(self): ++ if self.port_num < 53: + # SFP doesn't support this feature + return False + else: +- power_set = False +- +- sfpd_obj = sff8436Dom() +- if sfpd_obj is None: +- return False +- +- dom_control_raw = self.__read_eeprom_specific_bytes( +- QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None +- if dom_control_raw is not None: +- dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) +- power_set = ( +- 'On' == dom_control_data['data']['PowerSet']['value']) +- +- return power_set +- +- def get_power_override(self): +- """ +- Retrieves the power-override status of this SFP +- Returns: +- A Boolean, True if power-override is enabled, False if disabled +- """ +- if self.port_num < 53: +- return False # SFP doesn't support this feature +- else: +- power_override = False +- +- +- sfpd_obj = sff8436Dom() +- if sfpd_obj is None: +- return False +- +- dom_control_raw = self.__read_eeprom_specific_bytes( +- QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None +- if dom_control_raw is not None: +- dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) +- power_override = ( +- 'On' == dom_control_data['data']['PowerOverride']['value']) +- +- return power_override +- +- def get_temperature(self): +- """ +- Retrieves the temperature of this SFP +- Returns: +- An integer number of current temperature in Celsius +- """ +- transceiver_dom_info_dict = self.get_transceiver_bulk_status() +- return transceiver_dom_info_dict.get("temperature", "N/A") +- +- def get_voltage(self): +- """ +- Retrieves the supply voltage of this SFP +- Returns: +- An integer number of supply voltage in mV +- """ +- transceiver_dom_info_dict = self.get_transceiver_bulk_status() +- return transceiver_dom_info_dict.get("voltage", "N/A") +- +- def get_tx_bias(self): +- """ +- Retrieves the TX bias current of this SFP +- Returns: +- A list of four integer numbers, representing TX bias in mA +- for channel 0 to channel 4. +- Ex. ['110.09', '111.12', '108.21', '112.09'] +- """ +- transceiver_dom_info_dict = self.get_transceiver_bulk_status() ++ api = self.get_xcvr_api() ++ return api.get_power_set() if api is not None else None + +- tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") +- if self.port_num < 53: +- return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] +- +- tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A") +- tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A") +- tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A") +- return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] if transceiver_dom_info_dict else [] +- +- def get_rx_power(self): +- """ +- Retrieves the received optical power for this SFP +- Returns: +- A list of four integer numbers, representing received optical +- power in mW for channel 0 to channel 4. +- Ex. ['1.77', '1.71', '1.68', '1.70'] +- """ +- transceiver_dom_info_dict = self.get_transceiver_bulk_status() +- +- rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") +- if self.port_num < 53: +- return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] +- rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A") +- rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A") +- rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A") +- return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] if transceiver_dom_info_dict else [] +- +- def get_tx_power(self): +- """ +- Retrieves the TX power of this SFP +- Returns: +- A list of four integer numbers, representing TX power in mW +- for channel 0 to channel 4. +- Ex. ['1.86', '1.86', '1.86', '1.86'] +- """ +- transceiver_dom_info_dict = self.get_transceiver_bulk_status() +- tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") +- if self.port_num < 53: +- return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] +- tx2_pw = transceiver_dom_info_dict.get("tx2power", "N/A") +- tx3_pw = transceiver_dom_info_dict.get("tx3power", "N/A") +- tx4_pw = transceiver_dom_info_dict.get("tx4power", "N/A") +- return [tx1_pw, tx2_pw, tx3_pw, tx4_pw] + + def reset(self): + """ +@@ -947,7 +213,7 @@ class Sfp(SfpBase): + A boolean, True if successful, False if not + """ + # Check for invalid port_num +- if self.port_num < 53: # non-QSFP ports don't support it. ++ if self.port_num < 49: #Copper port, no sysfs + return False + + reset_path = "{}{}{}".format(CPLD_I2C_PATH, 'module_reset_', self.port_num) +@@ -974,8 +240,8 @@ class Sfp(SfpBase): + return False + + if self.port_num < 53: +- tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) +- ret = self.__write_txt_file(tx_path, 1 if tx_disable else 0) ++ tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) ++ ret = self._api_helper.write_txt_file(tx_path, 1 if tx_disable else 0) + if ret is not None: + time.sleep(0.01) + return ret +@@ -985,78 +251,8 @@ class Sfp(SfpBase): + else: + if not self.get_presence(): + return False +- sysfsfile_eeprom = None +- try: +- tx_disable_ctl = 0xf if tx_disable else 0x0 +- buffer = create_string_buffer(1) +- if sys.version_info[0] >= 3: +- buffer[0] = tx_disable_ctl +- else: +- buffer[0] = chr(tx_disable_ctl) +- # Write to eeprom +- sysfsfile_eeprom = open( +- self.port_to_eeprom_mapping[self.port_num], "r+b") +- sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) +- sysfsfile_eeprom.write(buffer[0]) +- except IOError as e: +- print ('Error: unable to open file: ',str(e)) +- return False +- finally: +- if sysfsfile_eeprom is not None: +- sysfsfile_eeprom.close() +- time.sleep(0.01) +- return True +- +- def tx_disable_channel(self, channel, disable): +- """ +- Sets the tx_disable for specified SFP channels +- Args: +- channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, +- e.g. 0x5 for channel 0 and channel 2. +- disable : A boolean, True to disable TX channels specified in channel, +- False to enable +- Returns: +- A boolean, True if successful, False if not +- """ +- +- if self.port_num < 53: +- return False # SFP doesn't support this feature +- else: +- if not self.get_presence(): +- return False +- +- sysfsfile_eeprom = None +- try: +- channel_state = self.get_tx_disable_channel() +- +- for i in range(4): +- channel_mask = (1 << i) +- if not (channel & channel_mask): +- continue +- +- if disable: +- channel_state |= channel_mask +- else: +- channel_state &= ~channel_mask +- +- buffer = create_string_buffer(1) +- if sys.version_info[0] >= 3: +- buffer[0] = channel_state +- else: +- buffer[0] = chr(channel_state) +- # Write to eeprom +- sysfsfile_eeprom = open( +- self.port_to_eeprom_mapping[self.port_num], "r+b") +- sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) +- sysfsfile_eeprom.write(buffer[0]) +- except IOError as e: +- print ('Error: unable to open file: ', str(e)) +- return False +- finally: +- if sysfsfile_eeprom is not None: +- sysfsfile_eeprom.close() +- time.sleep(0.01) +- return True ++ api = self.get_xcvr_api() ++ return api.tx_disable(tx_disable) if api is not None else None + + def set_lpmode(self, lpmode): + """ +@@ -1070,12 +266,23 @@ class Sfp(SfpBase): + if self.port_num < 53: + return False # SFP doesn't support this feature + else: ++ ''' ++ use power override to control lpmode ++ ''' ++ if not self.get_presence(): ++ return False ++ api = self.get_xcvr_api() ++ if api is None: ++ return False ++ if api.get_lpmode_support() == False: ++ logger.log_notice("The transceiver of port {} doesn't support to set low power mode.". format(self.port_num)) ++ return True + if lpmode is True: +- self.set_power_override(True, True) ++ ret = api.set_power_override(True, True) + else: +- self.set_power_override(False, False) ++ ret = api.set_power_override(True, False) + +- return True ++ return ret + + def set_power_override(self, power_override, power_set): + """ +@@ -1099,24 +306,8 @@ class Sfp(SfpBase): + else: + if not self.get_presence(): + return False +- try: +- power_override_bit = (1 << 0) if power_override else 0 +- power_set_bit = (1 << 1) if power_set else (1 << 3) +- +- buffer = create_string_buffer(1) +- if sys.version_info[0] >= 3: +- buffer[0] = (power_override_bit | power_set_bit) +- else: +- buffer[0] = chr(power_override_bit | power_set_bit) +- # Write to eeprom +- with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd: +- fd.seek(QSFP_POWEROVERRIDE_OFFSET) +- fd.write(buffer[0]) +- time.sleep(0.01) +- except Exception: +- print ('Error: unable to open file: ', str(e)) +- return False +- return True ++ api = self.get_xcvr_api() ++ return api.set_power_override(power_override, power_set) if api is not None else None + + def get_name(self): + """ +@@ -1125,9 +316,9 @@ class Sfp(SfpBase): + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() +- sfputil_helper.read_porttab_mappings( +- self.__get_path_to_port_config_file()) +- name = sfputil_helper.logical[self.index] or "Unknown" ++ port_config_file_path = device_info.get_path_to_port_config_file() ++ sfputil_helper.read_porttab_mappings(port_config_file_path) ++ name = sfputil_helper.logical[self.port_num - 1] or "Unknown" + return name + + def get_presence(self): +@@ -1139,11 +330,11 @@ class Sfp(SfpBase): + if self.port_num < 49: #Copper port, no sysfs + return False + +- present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num) ++ present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num) + val=self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10)==1 +- else: ++ else: + return False + + def get_model(self): +@@ -1170,7 +361,7 @@ class Sfp(SfpBase): + Returns: + A boolean value, True if device is operating properly, False if not + """ +- return self.get_presence() and self.get_transceiver_bulk_status() ++ return self.get_presence() and not self.get_reset_status() + + def get_position_in_parent(self): + """ +@@ -1188,3 +379,150 @@ class Sfp(SfpBase): + bool: True if it is replaceable. + """ + return True ++ ++ def __validate_eeprom_sfp(self): ++ checksum_test = 0 ++ eeprom_raw = self.read_eeprom(0, 96) ++ if eeprom_raw is None: ++ return None ++ ++ for i in range(0, 63): ++ checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF ++ else: ++ if checksum_test != eeprom_raw[63]: ++ return False ++ ++ checksum_test = 0 ++ for i in range(64, 95): ++ checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF ++ else: ++ if checksum_test != eeprom_raw[95]: ++ return False ++ ++ api = self.get_xcvr_api() ++ if api is None: ++ return False ++ ++ if api.is_flat_memory(): ++ return True ++ ++ checksum_test = 0 ++ eeprom_raw = self.read_eeprom(384, 96) ++ if eeprom_raw is None: ++ return None ++ ++ for i in range(0, 95): ++ checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF ++ else: ++ if checksum_test != eeprom_raw[95]: ++ return False ++ ++ return True ++ ++ def __validate_eeprom_qsfp(self): ++ checksum_test = 0 ++ eeprom_raw = self.read_eeprom(128, 96) ++ if eeprom_raw is None: ++ return None ++ ++ for i in range(0, 63): ++ checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF ++ else: ++ if checksum_test != eeprom_raw[63]: ++ return False ++ ++ checksum_test = 0 ++ for i in range(64, 95): ++ checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF ++ else: ++ if checksum_test != eeprom_raw[95]: ++ return False ++ ++ api = self.get_xcvr_api() ++ if api is None: ++ return False ++ ++ if api.is_flat_memory(): ++ return True ++ ++ return True ++ ++ def validate_eeprom(self): ++ id_byte_raw = self.read_eeprom(0, 1) ++ if id_byte_raw is None: ++ return None ++ ++ id = id_byte_raw[0] ++ if id in self.QSFP_TYPE_CODE_LIST: ++ return self.__validate_eeprom_qsfp() ++ elif id in self.SFP_TYPE_CODE_LIST: ++ return self.__validate_eeprom_sfp() ++ else: ++ return False ++ ++ def validate_temperature(self): ++ temperature = self.get_temperature() ++ if temperature is None: ++ return None ++ ++ threshold_dict = self.get_transceiver_threshold_info() ++ if threshold_dict is None: ++ return None ++ ++ if isinstance(temperature, float) is not True: ++ return True ++ ++ if isinstance(threshold_dict['temphighalarm'], float) is not True: ++ return True ++ ++ return threshold_dict['temphighalarm'] > temperature ++ ++ def __get_error_description(self): ++ if not self.get_presence(): ++ return self.SFP_STATUS_UNPLUGGED ++ ++ err_stat = self.SFP_STATUS_BIT_INSERTED ++ ++ status = self.validate_eeprom() ++ if status is not True: ++ err_stat = (err_stat | self.SFP_ERROR_BIT_BAD_EEPROM) ++ ++ status = self.validate_temperature() ++ if status is not True: ++ err_stat = (err_stat | self.SFP_ERROR_BIT_HIGH_TEMP) ++ ++ if err_stat is self.SFP_STATUS_BIT_INSERTED: ++ return self.SFP_STATUS_OK ++ else: ++ err_desc = '' ++ cnt = 0 ++ for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT: ++ if (err_stat & key) != 0: ++ if cnt > 0: ++ err_desc = err_desc + "|" ++ cnt = cnt + 1 ++ err_desc = err_desc + self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT[key] ++ ++ return err_desc ++ ++ def get_error_description(self): ++ """ ++ Retrives the error descriptions of the SFP module ++ ++ Returns: ++ String that represents the current error descriptions of vendor specific errors ++ In case there are multiple errors, they should be joined by '|', ++ like: "Bad EEPROM|Unsupported cable" ++ """ ++ if self.port_num < 49: ++ # RJ45 doesn't support this feature ++ return None ++ else: ++ api = self.get_xcvr_api() ++ if api is not None: ++ try: ++ return api.get_error_description() ++ except NotImplementedError: ++ return self.__get_error_description() ++ else: ++ return self.__get_error_description() +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py +index 7a453c594..04a714510 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py ++++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py +@@ -12,56 +12,189 @@ import glob + + try: + from sonic_platform_base.thermal_base import ThermalBase ++ from .helper import DeviceThreshold + except ImportError as e: + raise ImportError(str(e) + "- required module not found") + ++PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" ++PSU_I2C_MAPPING = { ++ 0: { ++ "num": 10, ++ "addr": "58" ++ }, ++ 1: { ++ "num": 11, ++ "addr": "59" ++ }, ++} ++ ++PSU_CPLD_I2C_MAPPING = { ++ 0: { ++ "num": 10, ++ "addr": "50" ++ }, ++ 1: { ++ "num": 11, ++ "addr": "51" ++ }, ++} ++ ++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(ThermalBase): + """Platform-specific Thermal class""" + + THERMAL_NAME_LIST = [] ++ PSU_THERMAL_NAME_LIST = [] + SYSFS_PATH = "/sys/bus/i2c/devices" ++ CPU_SYSFS_PATH = "/sys/devices/platform" + +- def __init__(self, thermal_index=0): +- self.THERMAL_NAME_LIST = [] +- self.SYSFS_PATH = "/sys/bus/i2c/devices" ++ def __init__(self, thermal_index=0, is_psu=False, psu_index=0): + self.index = thermal_index ++ self.is_psu = is_psu ++ self.psu_index = psu_index ++ self.min_temperature = None ++ self.max_temperature = None ++ ++ if self.is_psu: ++ psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["num"] ++ psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"] ++ self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus, ++ psu_i2c_addr) ++ psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"] ++ psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"] ++ self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr) + # Add thermal name +- self.THERMAL_NAME_LIST.append("Temp sensor 1") +- self.THERMAL_NAME_LIST.append("Temp sensor 2") +- self.THERMAL_NAME_LIST.append("Temp sensor 3") ++ self.THERMAL_NAME_LIST.append("MB_temp(0x48)") ++ self.THERMAL_NAME_LIST.append("CB_temp(0x4B)") ++ self.THERMAL_NAME_LIST.append("FB_temp(0x4A)") ++ self.THERMAL_NAME_LIST.append("CPU_Package_temp") ++ self.THERMAL_NAME_LIST.append("CPU_Core_0_temp") ++ self.THERMAL_NAME_LIST.append("CPU_Core_1_temp") ++ self.THERMAL_NAME_LIST.append("CPU_Core_2_temp") ++ self.THERMAL_NAME_LIST.append("CPU_Core_3_temp") ++ self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1") ++ self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1") ++ ++ # Threshold Configuration ++ self.__conf = DeviceThreshold(self.get_name()) ++ # Default threshold. ++ self.__default_threshold = DEFAULT_THRESHOLD[self.get_name()] + + # Set hwmon path + i2c_path = { +- 0: "14-0048/hwmon/hwmon*/", +- 1: "24-004b/hwmon/hwmon*/", +- 2: "25-004a/hwmon/hwmon*/" ++ 0: {"hwmon_path":"14-0048/hwmon/hwmon*/", "ss_index":1}, ++ 1: {"hwmon_path":"24-004b/hwmon/hwmon*/", "ss_index":1}, ++ 2: {"hwmon_path":"25-004a/hwmon/hwmon*/", "ss_index":1}, ++ 3: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":1}, ++ 4: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":4}, ++ 5: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":8}, ++ 6: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":10}, ++ 7: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":14} + }.get(self.index, None) + +- self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path) ++ self.is_cpu = False ++ if self.index in range(3,8): ++ self.is_cpu = True ++ self.hwmon_path = "{}/{}".format(self.CPU_SYSFS_PATH, i2c_path["hwmon_path"]) ++ else: ++ self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path["hwmon_path"]) + self.ss_key = self.THERMAL_NAME_LIST[self.index] +- self.ss_index = 1 ++ self.ss_index = i2c_path["ss_index"] + + def __read_txt_file(self, file_path): + for filename in glob.glob(file_path): + try: +- with open(filename, 'r') as fd: +- data =fd.readline().rstrip() +- return data ++ with open(filename, 'r') as fd: ++ data =fd.readline().strip() ++ if len(data) > 0: ++ return data + except IOError as e: + pass + + return None + + def __get_temp(self, temp_file): +- temp_file_path = os.path.join(self.hwmon_path, temp_file) ++ if not self.is_psu: ++ temp_file_path = os.path.join(self.hwmon_path, temp_file) ++ else: ++ temp_file_path = temp_file + raw_temp = self.__read_txt_file(temp_file_path) + if raw_temp is not None: + return float(raw_temp)/1000 + else: +- return 0 ++ return 0 + + def __set_threshold(self, file_name, temperature): ++ if self.is_psu: ++ return True + temp_file_path = os.path.join(self.hwmon_path, file_name) + for filename in glob.glob(temp_file_path): + try: +@@ -79,41 +212,153 @@ class Thermal(ThermalBase): + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ +- temp_file = "temp{}_input".format(self.ss_index) +- return self.__get_temp(temp_file) ++ if not self.is_psu: ++ temp_file = "temp{}_input".format(self.ss_index) ++ else: ++ temp_file = self.psu_hwmon_path + "psu_temp1_input" + +- def get_high_threshold(self): +- """ +- Retrieves the high threshold temperature of thermal +- Returns: +- A float number, the high threshold temperature of thermal in Celsius +- up to nearest thousandth of one degree Celsius, e.g. 30.125 +- """ +- temp_file = "temp{}_max".format(self.ss_index) +- return self.__get_temp(temp_file) ++ current = self.__get_temp(temp_file) ++ ++ 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): +- """ +- Sets the high threshold temperature of thermal +- Args : +- temperature: A float number up to nearest thousandth of one degree Celsius, +- e.g. 30.125 +- Returns: +- A boolean, True if threshold is set successfully, False if not +- """ +- temp_file = "temp{}_max".format(self.ss_index) +- temperature = temperature *1000 +- self.__set_threshold(temp_file, 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) ++ ++ raise NotImplementedError ++ ++ 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) ++ ++ raise NotImplementedError ++ ++ 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_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ +- return self.THERMAL_NAME_LIST[self.index] ++ if self.is_psu: ++ return self.PSU_THERMAL_NAME_LIST[self.psu_index] ++ else: ++ return self.THERMAL_NAME_LIST[self.index] + + def get_presence(self): + """ +@@ -121,6 +366,15 @@ class Thermal(ThermalBase): + Returns: + bool: True if Thermal is present, False if not + """ ++ if self.is_cpu: ++ return True ++ ++ if self.is_psu: ++ val = self.__read_txt_file(self.cpld_path + "psu_present") ++ if val is not None: ++ return int(val, 10) == 1 ++ else: ++ return False + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + raw_txt = self.__read_txt_file(temp_file_path) +@@ -135,11 +389,78 @@ class Thermal(ThermalBase): + Returns: + A boolean value, True if device is operating properly, False if not + """ ++ if self.is_cpu: ++ return True ++ ++ if self.is_psu: ++ temp_file = self.psu_hwmon_path + "psu_temp_fault" ++ psu_temp_fault = self.__read_txt_file(temp_file) ++ if psu_temp_fault is None: ++ psu_temp_fault = '1' ++ return self.get_presence() and (not int(psu_temp_fault)) + + file_str = "temp{}_input".format(self.ss_index) + file_path = os.path.join(self.hwmon_path, file_str) + raw_txt = self.__read_txt_file(file_path) + if raw_txt is None: + return False +- else: ++ else: + return int(raw_txt) != 0 ++ ++ def get_model(self): ++ """ ++ Retrieves the model number (or part number) of the device ++ Returns: ++ string: Model/part number of device ++ """ ++ ++ return "N/A" ++ ++ def get_serial(self): ++ """ ++ Retrieves the serial number of the device ++ Returns: ++ string: Serial number of device ++ """ ++ return "N/A" ++ ++ def get_position_in_parent(self): ++ """ ++ Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position ++ for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned ++ Returns: ++ integer: The 1-based relative physical position in parent device or -1 if cannot determine the position ++ """ ++ return self.index+1 ++ ++ def is_replaceable(self): ++ """ ++ Retrieves whether thermal module is replaceable ++ Returns: ++ A boolean value, True if replaceable, False if not ++ """ ++ return False ++ ++ def get_minimum_recorded(self): ++ """ ++ Retrieves the minimum recorded temperature of thermal ++ Returns: ++ A float number, the minimum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.min_temperature is None: ++ self.get_temperature() ++ ++ return self.min_temperature ++ ++ def get_maximum_recorded(self): ++ """ ++ Retrieves the maximum recorded temperature of thermal ++ Returns: ++ A float number, the maximum recorded temperature of thermal in Celsius ++ up to nearest thousandth of one degree Celsius, e.g. 30.125 ++ """ ++ if self.max_temperature is None: ++ self.get_temperature() ++ ++ return self.max_temperature +diff --git a/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json +index 91a29558b..97f9aa305 100644 +--- a/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json ++++ b/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json +@@ -1,9 +1,7 @@ + { + "services_to_ignore": [], + "devices_to_ignore": [ +- "asic", +- "psu.temperature" +- ++ "asic" + ], + "user_defined_checkers": [], + "polling_interval": 60, +diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c +index 3a99f19a9..5813d8918 100755 +--- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c ++++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c +@@ -91,7 +91,6 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, + struct as4630_54te_psu_data *data = as4630_54te_psu_update_device(dev); + u8 status = 0; + +- //printk("data->status=0x%x, attr->index=%d,data->index=%d \n", data->status, attr->index, data->index); + if (attr->index == PSU_PRESENT) { + if(data->index==0) + status = !( (data->status >> 5) & 0x1); +@@ -102,7 +101,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); +@@ -261,13 +260,14 @@ static struct as4630_54te_psu_data *as4630_54te_psu_update_device(struct device + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; ++ u8 serial_offset; + int power_good = 0; + + dev_dbg(&client->dev, "Starting as4630_54te update\n"); + + /* Read psu status */ + status = as4630_54te_cpld_read(0x60, 0x22); +- //printk("status=0x%x in %s\n", status, __FUNCTION__); ++ + if (status < 0) { + dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); + } +@@ -278,29 +278,49 @@ static struct as4630_54te_psu_data *as4630_54te_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); +- ++ if(data->index==0) ++ power_good = ( (data->status >> 6) & 0x1); ++ else ++ power_good = ( (data->status >> 2) & 0x1); ++ + if (power_good) { + status = as4630_54te_psu_read_block(client, 0x20, data->model_name, +- ARRAY_SIZE(data->model_name)-1); ++ ARRAY_SIZE(data->model_name)-1); ++ + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); +- printk("unable to read model name from (0x%x)\n", client->addr); + } + else { ++ data->model_name[8] = '-'; + data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; +- + } +- /* Read from offset 0x2e ~ 0x3d (16 bytes) */ +- status = as4630_54te_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); ++ if(!strncmp(data->model_name, "YM-1151D", strlen("YM-1151D"))) ++ { ++ if (!strncmp(data->model_name, "YM-1151D-A03R", strlen("YM-1151D-A03R"))) ++ { ++ data->model_name[strlen("YM-1151D-A03R")] = '\0'; ++ serial_offset = 0x2E; /* YM-1151D-A03R, F2B dir */ ++ } ++ else ++ { ++ data->model_name[strlen("YM-1151D-A02R")] = '\0'; ++ serial_offset = 0x35; /* YM-1151D-A02R, B2F dir */ ++ } ++ } ++ else ++ serial_offset = 0x2E; ++ ++ /* Read from offset 0x2e ~ 0x3f (16 bytes) */ ++ status = as4630_54te_psu_read_block(client, serial_offset, 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(0x2e)\n", client->addr); +- printk("unable to read model name from (0x%x) offset(0x2e)\n", client->addr); + } ++ + data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; ++ + } + + data->last_updated = jiffies; +diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service +index 587e6a1ca..b0c5fe6a7 100644 +--- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service ++++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service +@@ -1,6 +1,6 @@ + [Unit] + Description=Accton AS4630-54TE Platform Monitoring service +-Before=pmon.service ++Before=pmon.service system-health.service + After=sysinit.target + DefaultDependencies=no + +diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/udev/70-persistent-net.rules b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/udev/70-persistent-net.rules +new file mode 100644 +index 000000000..11ca59a6f +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/udev/70-persistent-net.rules +@@ -0,0 +1,3 @@ ++ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:08:00.0", NAME:="eth0" ++ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:06:00.1", NAME:="eth1" ++ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:06:00.0", NAME:="eth3" +\ No newline at end of file +diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py +index aa5076c2c..005d9d6b1 100755 +--- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py ++++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py +@@ -87,6 +87,9 @@ class device_monitor(object): + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" ++ ++ self.thermal = ThermalUtil() ++ self.fan = FanUtil() + # set up logging to file + logging.basicConfig( + filename=log_file, +@@ -138,8 +141,8 @@ class device_monitor(object): + LEVEL_TEMP_CRITICAL: [100, 16, 240000, 300000], + } + temp = [0, 0, 0] +- thermal = ThermalUtil() +- fan = FanUtil() ++ thermal = self.thermal ++ fan = self.fan + ori_duty_cycle = fan.get_fan_duty_cycle() + new_duty_cycle = 0 + +diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh +index 82f4d5e02..cdc3c04fc 100755 +--- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh ++++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh +@@ -1,8 +1,7 @@ + #!/bin/bash + +-#Due to the hardware design, as4630-54te 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 +\ No newline at end of file +diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/restart_ixgbe.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/restart_ixgbe.sh +new file mode 100755 +index 000000000..57c14e5ba +--- /dev/null ++++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/restart_ixgbe.sh +@@ -0,0 +1,8 @@ ++#!/bin/bash ++ ++/etc/init.d/netfilter-persistent stop ++modprobe -r ixgbe ++udevadm control --reload-rules ++udevadm trigger ++modprobe ixgbe ++/etc/init.d/netfilter-persistent start +diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules +index c47aa3b3e..cfbfeaed7 100755 +--- a/platform/broadcom/sonic-platform-modules-accton/debian/rules ++++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules +@@ -27,6 +27,7 @@ MODULE_DIR := modules + UTILS_DIR := utils + SERVICE_DIR := service + CONF_DIR := conf ++UDEV_DIR := udev + + %: + dh $@ --with systemd,python3 --buildsystem=pybuild +@@ -70,9 +71,15 @@ binary-indep: + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} usr/local/bin; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} lib/systemd/system; \ ++ if [ -d $(MOD_SRC_DIR)/$${mod}/$(UDEV_DIR) ]; then \ ++ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} etc/udev/rules.d; \ ++ fi; \ + cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ ++ if [ -f $(MOD_SRC_DIR)/$${mod}/$(UDEV_DIR)/* ]; then \ ++ cp $(MOD_SRC_DIR)/$${mod}/$(UDEV_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/etc/udev/rules.d/; \ ++ fi; \ + $(PYTHON3) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + done) + # Resuming debhelper scripts diff --git a/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hwsku.json b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hwsku.json new file mode 100755 index 0000000000..faf0aac092 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/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_54te-r0/Accton-AS4630-54TE/hx5-as4630-48x1G+4x25G+2x100G.bcm b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hx5-as4630-48x1G+4x25G+2x100G.bcm new file mode 100755 index 0000000000..1a02415067 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/hx5-as4630-48x1G+4x25G+2x100G.bcm @@ -0,0 +1,502 @@ +stable_size=76303168 + +#polarity/lanemap is using TH2 style. +core_clock_frequency=893 +dpp_clock_ratio=2:3 + +ptp_ts_pll_fref=50000000 +ptp_bs_fref_0=50000000 +ptp_bs_fref_1=50000000 + +#oversubscribe_mode=1 + +pbmp_xport_xe=0x1FFFFFFE000000000000 + +parity_enable=0 +mem_cache_enable=1 + +l2_mem_entries=32768 +#l3_mem_entries=49152 +#fpem_mem_entries=16384 +l2xmsg_mode=1 +l3_alpm_enable=2 +ipv6_lpm_128b_enable=1 +port_flex_enable=1 +pcie_hot_swap_timeout_usec=10000 +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 + +#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 +port_phy_addr_2=0x41 +port_phy_addr_3=0x42 +port_phy_addr_4=0x43 +port_phy_addr_5=0x44 +port_phy_addr_6=0x45 +port_phy_addr_7=0x46 +port_phy_addr_8=0x47 +phy_port_primary_and_offset_1=0x0100 +phy_port_primary_and_offset_2=0x0101 +phy_port_primary_and_offset_3=0x0102 +phy_port_primary_and_offset_4=0x0103 +phy_port_primary_and_offset_5=0x0104 +phy_port_primary_and_offset_6=0x0105 +phy_port_primary_and_offset_7=0x0106 +phy_port_primary_and_offset_8=0x0107 +dport_map_port_1=26 +dport_map_port_2=25 +dport_map_port_3=28 +dport_map_port_4=27 +dport_map_port_5=30 +dport_map_port_6=29 +dport_map_port_7=32 +dport_map_port_8=31 +portmap_1=1:1 +portmap_2=2:1 +portmap_3=3:1 +portmap_4=4:1 +portmap_5=5:1 +portmap_6=6:1 +portmap_7=7:1 +portmap_8=8:1 +phy_chain_rx_lane_map_physical{1.0}=0x3210 +phy_chain_rx_lane_map_physical{2.0}=0x3210 +phy_chain_rx_lane_map_physical{3.0}=0x3210 +phy_chain_rx_lane_map_physical{4.0}=0x3210 +phy_chain_rx_lane_map_physical{5.0}=0x3210 +phy_chain_rx_lane_map_physical{6.0}=0x3210 +phy_chain_rx_lane_map_physical{7.0}=0x3210 +phy_chain_rx_lane_map_physical{8.0}=0x3210 +phy_chain_tx_lane_map_physical{1.0}=0x3210 +phy_chain_tx_lane_map_physical{2.0}=0x3210 +phy_chain_tx_lane_map_physical{3.0}=0x3210 +phy_chain_tx_lane_map_physical{4.0}=0x3210 +phy_chain_tx_lane_map_physical{5.0}=0x3210 +phy_chain_tx_lane_map_physical{6.0}=0x3210 +phy_chain_tx_lane_map_physical{7.0}=0x3210 +phy_chain_tx_lane_map_physical{8.0}=0x3210 +phy_chain_rx_polarity_flip_physical{1.0}=0x0 +phy_chain_rx_polarity_flip_physical{2.0}=0x0 +phy_chain_rx_polarity_flip_physical{3.0}=0x0 +phy_chain_rx_polarity_flip_physical{4.0}=0x0 +phy_chain_rx_polarity_flip_physical{5.0}=0x0 +phy_chain_rx_polarity_flip_physical{6.0}=0x0 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_rx_polarity_flip_physical{8.0}=0x0 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_tx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_tx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x0 +phy_chain_tx_polarity_flip_physical{8.0}=0x0 + + +#PHY5 U57 x1x, MDC/MDIO2, PHYADDR:0x09-0x10, 0x11 +port_phy_addr_9=0x49 +port_phy_addr_10=0x4A +port_phy_addr_11=0x4B +port_phy_addr_12=0x4C +port_phy_addr_13=0x4D +port_phy_addr_14=0x4E +port_phy_addr_15=0x4F +port_phy_addr_16=0x50 +phy_port_primary_and_offset_9=0x0900 +phy_port_primary_and_offset_10=0x0901 +phy_port_primary_and_offset_11=0x0902 +phy_port_primary_and_offset_12=0x0903 +phy_port_primary_and_offset_13=0x0904 +phy_port_primary_and_offset_14=0x0905 +phy_port_primary_and_offset_15=0x0906 +phy_port_primary_and_offset_16=0x0907 +dport_map_port_9=34 +dport_map_port_10=33 +dport_map_port_11=36 +dport_map_port_12=35 +dport_map_port_13=38 +dport_map_port_14=37 +dport_map_port_15=40 +dport_map_port_16=39 +portmap_9=9:1 +portmap_10=10:1 +portmap_11=11:1 +portmap_12=12:1 +portmap_13=13:1 +portmap_14=14:1 +portmap_15=15:1 +portmap_16=16:1 +phy_chain_rx_lane_map_physical{9.0}=0x3210 +phy_chain_rx_lane_map_physical{10.0}=0x3210 +phy_chain_rx_lane_map_physical{11.0}=0x3210 +phy_chain_rx_lane_map_physical{12.0}=0x3210 +phy_chain_rx_lane_map_physical{13.0}=0x3210 +phy_chain_rx_lane_map_physical{14.0}=0x3210 +phy_chain_rx_lane_map_physical{15.0}=0x3210 +phy_chain_rx_lane_map_physical{16.0}=0x3210 +phy_chain_tx_lane_map_physical{9.0}=0x3210 +phy_chain_tx_lane_map_physical{10.0}=0x3210 +phy_chain_tx_lane_map_physical{11.0}=0x3210 +phy_chain_tx_lane_map_physical{12.0}=0x3210 +phy_chain_tx_lane_map_physical{13.0}=0x3210 +phy_chain_tx_lane_map_physical{14.0}=0x3210 +phy_chain_tx_lane_map_physical{15.0}=0x3210 +phy_chain_tx_lane_map_physical{16.0}=0x3210 +phy_chain_rx_polarity_flip_physical{9.0}=0x0 +phy_chain_rx_polarity_flip_physical{10.0}=0x0 +phy_chain_rx_polarity_flip_physical{11.0}=0x0 +phy_chain_rx_polarity_flip_physical{12.0}=0x0 +phy_chain_rx_polarity_flip_physical{13.0}=0x0 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x0 +phy_chain_rx_polarity_flip_physical{16.0}=0x0 +phy_chain_tx_polarity_flip_physical{9.0}=0x0 +phy_chain_tx_polarity_flip_physical{10.0}=0x0 +phy_chain_tx_polarity_flip_physical{11.0}=0x0 +phy_chain_tx_polarity_flip_physical{12.0}=0x0 +phy_chain_tx_polarity_flip_physical{13.0}=0x0 +phy_chain_tx_polarity_flip_physical{14.0}=0x0 +phy_chain_tx_polarity_flip_physical{15.0}=0x0 +phy_chain_tx_polarity_flip_physical{16.0}=0x0 + +#MCQ1 +port_gmii_mode_17=1 #Q mode + +#PHY6 U58 11x, MDC/MDIO2, PHYADDR:0x12-0x19, 0x1A +port_phy_addr_17=0x52 +port_phy_addr_18=0x53 +port_phy_addr_19=0x54 +port_phy_addr_20=0x55 +port_phy_addr_21=0x56 +port_phy_addr_22=0x57 +port_phy_addr_23=0x58 +port_phy_addr_24=0x59 +phy_port_primary_and_offset_17=0x1100 +phy_port_primary_and_offset_18=0x1101 +phy_port_primary_and_offset_19=0x1102 +phy_port_primary_and_offset_20=0x1103 +phy_port_primary_and_offset_21=0x1104 +phy_port_primary_and_offset_22=0x1105 +phy_port_primary_and_offset_23=0x1106 +phy_port_primary_and_offset_24=0x1107 +dport_map_port_17=42 +dport_map_port_18=41 +dport_map_port_19=44 +dport_map_port_20=43 +dport_map_port_21=46 +dport_map_port_22=45 +dport_map_port_23=48 +dport_map_port_24=47 +portmap_17=17:1 +portmap_18=18:1 +portmap_19=19:1 +portmap_20=20:1 +portmap_21=21:1 +portmap_22=22:1 +portmap_23=23:1 +portmap_24=24:1 +phy_chain_rx_lane_map_physical{17.0}=0x3210 +phy_chain_rx_lane_map_physical{18.0}=0x3210 +phy_chain_rx_lane_map_physical{19.0}=0x3210 +phy_chain_rx_lane_map_physical{20.0}=0x3210 +phy_chain_rx_lane_map_physical{21.0}=0x3210 +phy_chain_rx_lane_map_physical{22.0}=0x3210 +phy_chain_rx_lane_map_physical{23.0}=0x3210 +phy_chain_rx_lane_map_physical{24.0}=0x3210 +phy_chain_tx_lane_map_physical{17.0}=0x3210 +phy_chain_tx_lane_map_physical{18.0}=0x3210 +phy_chain_tx_lane_map_physical{19.0}=0x3210 +phy_chain_tx_lane_map_physical{20.0}=0x3210 +phy_chain_tx_lane_map_physical{21.0}=0x3210 +phy_chain_tx_lane_map_physical{22.0}=0x3210 +phy_chain_tx_lane_map_physical{23.0}=0x3210 +phy_chain_tx_lane_map_physical{24.0}=0x3210 +phy_chain_rx_polarity_flip_physical{17.0}=0x0 +phy_chain_rx_polarity_flip_physical{18.0}=0x0 +phy_chain_rx_polarity_flip_physical{19.0}=0x0 +phy_chain_rx_polarity_flip_physical{20.0}=0x0 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 +phy_chain_tx_polarity_flip_physical{17.0}=0x0 +phy_chain_tx_polarity_flip_physical{18.0}=0x0 +phy_chain_tx_polarity_flip_physical{19.0}=0x0 +phy_chain_tx_polarity_flip_physical{20.0}=0x0 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_tx_polarity_flip_physical{24.0}=0x0 + +#PHY1 U53 xx1, MDC/MDIO0, PHYADDR:0x00-0x07, 0x08 +port_phy_addr_25=0x00 +port_phy_addr_26=0x01 +port_phy_addr_27=0x02 +port_phy_addr_28=0x03 +port_phy_addr_29=0x04 +port_phy_addr_30=0x05 +port_phy_addr_31=0x06 +port_phy_addr_32=0x07 +phy_port_primary_and_offset_25=0x1900 +phy_port_primary_and_offset_26=0x1901 +phy_port_primary_and_offset_27=0x1902 +phy_port_primary_and_offset_28=0x1903 +phy_port_primary_and_offset_29=0x1904 +phy_port_primary_and_offset_30=0x1905 +phy_port_primary_and_offset_31=0x1906 +phy_port_primary_and_offset_32=0x1907 +dport_map_port_25=2 +dport_map_port_26=1 +dport_map_port_27=4 +dport_map_port_28=3 +dport_map_port_29=6 +dport_map_port_30=5 +dport_map_port_31=8 +dport_map_port_32=7 +portmap_25=25:1 +portmap_26=26:1 +portmap_27=27:1 +portmap_28=28:1 +portmap_29=29:1 +portmap_30=30:1 +portmap_31=31:1 +portmap_32=32:1 +phy_chain_rx_lane_map_physical{25.0}=0x3210 +phy_chain_rx_lane_map_physical{26.0}=0x3210 +phy_chain_rx_lane_map_physical{27.0}=0x3210 +phy_chain_rx_lane_map_physical{28.0}=0x3210 +phy_chain_rx_lane_map_physical{29.0}=0x3210 +phy_chain_rx_lane_map_physical{30.0}=0x3210 +phy_chain_rx_lane_map_physical{31.0}=0x3210 +phy_chain_rx_lane_map_physical{32.0}=0x3210 +phy_chain_tx_lane_map_physical{25.0}=0x3210 +phy_chain_tx_lane_map_physical{26.0}=0x3210 +phy_chain_tx_lane_map_physical{27.0}=0x3210 +phy_chain_tx_lane_map_physical{28.0}=0x3210 +phy_chain_tx_lane_map_physical{29.0}=0x3210 +phy_chain_tx_lane_map_physical{30.0}=0x3210 +phy_chain_tx_lane_map_physical{31.0}=0x3210 +phy_chain_tx_lane_map_physical{32.0}=0x3210 +phy_chain_rx_polarity_flip_physical{25.0}=0x0 +phy_chain_rx_polarity_flip_physical{26.0}=0x0 +phy_chain_rx_polarity_flip_physical{27.0}=0x0 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 +phy_chain_rx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{30.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x0 +phy_chain_tx_polarity_flip_physical{25.0}=0x0 +phy_chain_tx_polarity_flip_physical{26.0}=0x0 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_tx_polarity_flip_physical{28.0}=0x0 +phy_chain_tx_polarity_flip_physical{29.0}=0x0 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x0 + +#MCQ2 +port_gmii_mode_33=1 #Q mode + +#PHY2 U54 x1x, MDC/MDIO0, PHYADDR:0x09-0x10, 0x11 +port_phy_addr_33=0x0D +port_phy_addr_34=0x0E +port_phy_addr_35=0x0F +port_phy_addr_36=0x10 +port_phy_addr_37=0x09 +port_phy_addr_38=0x0A +port_phy_addr_39=0x0B +port_phy_addr_40=0x0C +phy_port_primary_and_offset_33=0x2504 +phy_port_primary_and_offset_34=0x2505 +phy_port_primary_and_offset_35=0x2506 +phy_port_primary_and_offset_36=0x2507 +phy_port_primary_and_offset_37=0x2500 +phy_port_primary_and_offset_38=0x2501 +phy_port_primary_and_offset_39=0x2502 +phy_port_primary_and_offset_40=0x2503 +dport_map_port_33=14 +dport_map_port_34=13 +dport_map_port_35=16 +dport_map_port_36=15 +dport_map_port_37=10 +dport_map_port_38=9 +dport_map_port_39=12 +dport_map_port_40=11 +portmap_33=33:1 +portmap_34=34:1 +portmap_35=35:1 +portmap_36=36:1 +portmap_37=37:1 +portmap_38=38:1 +portmap_39=39:1 +portmap_40=40:1 +phy_chain_rx_lane_map_physical{33.0}=0x3210 +phy_chain_rx_lane_map_physical{34.0}=0x3210 +phy_chain_rx_lane_map_physical{35.0}=0x3210 +phy_chain_rx_lane_map_physical{36.0}=0x3210 +phy_chain_rx_lane_map_physical{37.0}=0x3210 +phy_chain_rx_lane_map_physical{38.0}=0x3210 +phy_chain_rx_lane_map_physical{39.0}=0x3210 +phy_chain_rx_lane_map_physical{40.0}=0x3210 +phy_chain_tx_lane_map_physical{33.0}=0x3210 +phy_chain_tx_lane_map_physical{34.0}=0x3210 +phy_chain_tx_lane_map_physical{35.0}=0x3210 +phy_chain_tx_lane_map_physical{36.0}=0x3210 +phy_chain_tx_lane_map_physical{37.0}=0x3210 +phy_chain_tx_lane_map_physical{38.0}=0x3210 +phy_chain_tx_lane_map_physical{39.0}=0x3210 +phy_chain_tx_lane_map_physical{40.0}=0x3210 +phy_chain_rx_polarity_flip_physical{33.0}=0x1 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x1 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_polarity_flip_physical{37.0}=0x1 +phy_chain_rx_polarity_flip_physical{38.0}=0x1 +phy_chain_rx_polarity_flip_physical{39.0}=0x1 +phy_chain_rx_polarity_flip_physical{40.0}=0x1 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_tx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x1 +phy_chain_tx_polarity_flip_physical{36.0}=0x1 +phy_chain_tx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x1 +phy_chain_tx_polarity_flip_physical{39.0}=0x1 +phy_chain_tx_polarity_flip_physical{40.0}=0x1 + +#PHY3 U55 11x, MDC/MDIO0, PHYADDR:0x12-0x19, 0x1A +port_phy_addr_41=0x16 +port_phy_addr_42=0x17 +port_phy_addr_43=0x18 +port_phy_addr_44=0x19 +port_phy_addr_45=0x12 +port_phy_addr_46=0x13 +port_phy_addr_47=0x14 +port_phy_addr_48=0x15 +phy_port_primary_and_offset_41=0x2D00 +phy_port_primary_and_offset_42=0x2D01 +phy_port_primary_and_offset_43=0x2D02 +phy_port_primary_and_offset_44=0x2D03 +phy_port_primary_and_offset_45=0x2D04 +phy_port_primary_and_offset_46=0x2D05 +phy_port_primary_and_offset_47=0x2D06 +phy_port_primary_and_offset_48=0x2D07 +dport_map_port_41=22 +dport_map_port_42=21 +dport_map_port_43=24 +dport_map_port_44=23 +dport_map_port_45=18 +dport_map_port_46=17 +dport_map_port_47=20 +dport_map_port_48=19 +portmap_41=41:1 +portmap_42=42:1 +portmap_43=43:1 +portmap_44=44:1 +portmap_45=45:1 +portmap_46=46:1 +portmap_47=47:1 +portmap_48=48:1 +phy_chain_rx_lane_map_physical{41.0}=0x3210 +phy_chain_rx_lane_map_physical{42.0}=0x3210 +phy_chain_rx_lane_map_physical{43.0}=0x3210 +phy_chain_rx_lane_map_physical{44.0}=0x3210 +phy_chain_rx_lane_map_physical{45.0}=0x3210 +phy_chain_rx_lane_map_physical{46.0}=0x3210 +phy_chain_rx_lane_map_physical{47.0}=0x3210 +phy_chain_rx_lane_map_physical{48.0}=0x3210 +phy_chain_tx_lane_map_physical{41.0}=0x3210 +phy_chain_tx_lane_map_physical{42.0}=0x3210 +phy_chain_tx_lane_map_physical{43.0}=0x3210 +phy_chain_tx_lane_map_physical{44.0}=0x3210 +phy_chain_tx_lane_map_physical{45.0}=0x3210 +phy_chain_tx_lane_map_physical{46.0}=0x3210 +phy_chain_tx_lane_map_physical{47.0}=0x3210 +phy_chain_tx_lane_map_physical{48.0}=0x3210 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 +phy_chain_rx_polarity_flip_physical{45.0}=0x1 +phy_chain_rx_polarity_flip_physical{46.0}=0x1 +phy_chain_rx_polarity_flip_physical{47.0}=0x1 +phy_chain_rx_polarity_flip_physical{48.0}=0x1 +phy_chain_tx_polarity_flip_physical{41.0}=0x1 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_tx_polarity_flip_physical{44.0}=0x1 +phy_chain_tx_polarity_flip_physical{45.0}=0x1 +phy_chain_tx_polarity_flip_physical{46.0}=0x1 +phy_chain_tx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x1 + +#3x PM4x25 (3 * 4 = 12 physical ports) +#FC0 +dport_map_port_49=51 +dport_map_port_50=50 +dport_map_port_51=49 +dport_map_port_52=52 +portmap_49=65:25 +portmap_50=66:25 +portmap_51=67:25 +portmap_52=68:25 +#FC1 +dport_map_port_53=57 +dport_map_port_54=58 +dport_map_port_55=59 +dport_map_port_56=60 +portmap_53=69:100:4 +#portmap_55=71:50 +#portmap_54=70:25 +#portmap_55=71:25 +#portmap_56=72:25 +#FC2 +dport_map_port_57=53 +dport_map_port_58=54 +dport_map_port_59=55 +dport_map_port_60=56 +portmap_57=73:100:4 +#portmap_59=75:50 +#portmap_58=74:25 +#portmap_59=75:25 +#portmap_60=76:25 + +#4x PM4x10 (4 * 4 = 16 physical ports) +#MC0 No connection +#MC1 No connection +#MC2 No connection +#MC3 No connection +#portmap_=49:10 +#portmap_=50:10 +#portmap_=51:10 +#portmap_=52:10 + +#portmap_=53:10 +#portmap_=54:10 +#portmap_=55:10 +#portmap_=56:10 + +#portmap_=57:10 +#portmap_=58:10 +#portmap_=59:10 +#portmap_=60:10 + +#portmap_=61:10 +#portmap_=62:10 +#portmap_=63:10 +#portmap_=64:10 diff --git a/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/port_config.ini b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/port_config.ini index 7040875faf..c30f99f480 100755 --- a/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/port_config.ini +++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/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 +# name lanes alias index speed autoneg +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_54te-r0/Accton-AS4630-54TE/sai.profile b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/sai.profile new file mode 100755 index 0000000000..5329410fe8 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/Accton-AS4630-54TE/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/hx5-as4630-48x1G+4x25G+2x100G.bcm diff --git a/device/accton/x86_64-accton_as4630_54te-r0/installer.conf b/device/accton/x86_64-accton_as4630_54te-r0/installer.conf index 925a32fc0c..d5f9419d77 100755 --- a/device/accton/x86_64-accton_as4630_54te-r0/installer.conf +++ b/device/accton/x86_64-accton_as4630_54te-r0/installer.conf @@ -1,3 +1,4 @@ CONSOLE_PORT=0x3f8 CONSOLE_DEV=0 CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="pcie_aspm=off" diff --git a/device/accton/x86_64-accton_as4630_54te-r0/led_proc_init.soc b/device/accton/x86_64-accton_as4630_54te-r0/led_proc_init.soc new file mode 100644 index 0000000000..696632b6ea --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/led_proc_init.soc @@ -0,0 +1,3 @@ +#m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin +led start +#led auto on diff --git a/device/accton/x86_64-accton_as4630_54te-r0/pcie.yaml b/device/accton/x86_64-accton_as4630_54te-r0/pcie.yaml new file mode 100644 index 0000000000..c7e99c8678 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-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_54te-r0/platform.json b/device/accton/x86_64-accton_as4630_54te-r0/platform.json new file mode 100644 index 0000000000..af158fc72a --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/platform.json @@ -0,0 +1,820 @@ +{ + "chassis": { + "name": "AS4630-54TE", + "thermal_manager":false, + "status_led": { + "controllable": true, + "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_GREEN_BLINK", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] + }, + "components": [ + { + "name": "CPLD1" + }, + { + "name": "CPLD2" + }, + { + "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", + "status_led": { + "controllable": false + }, + "num_fans" : 1, + "fans": [ + { + "name": "FAN-1", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray2", + "status_led": { + "controllable": false + }, + "num_fans" : 1, + "fans": [ + { + "name": "FAN-2", + "speed": { + "controllable": true, + "minimum": 7 + }, + "status_led": { + "controllable": false + } + } + ] + }, + { + "name": "FanTray3", + "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": true, + "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] + }, + "fans": [ + { + "name": "PSU-1 FAN-1" + } + ], + "thermals": [ + { + "name": "PSU-1 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ] + }, + { + "name": "PSU-2", + "status_led": { + "controllable": true, + "colors": ["STATUS_LED_COLOR_GREEN", "STATUS_LED_COLOR_AMBER", "STATUS_LED_COLOR_OFF"] + }, + "fans": [ + { + "name": "PSU-2 FAN-1" + } + ], + "thermals": [ + { + "name": "PSU-2 temp sensor 1", + "controllable": false, + "low-crit-threshold": false, + "high-crit-threshold": false + } + ] + } + ], + "thermals": [ + { + "name": "MB_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": "Ethernet0" + }, + { + "name": "Ethernet1" + }, + { + "name": "Ethernet2" + }, + { + "name": "Ethernet3" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet5" + }, + { + "name": "Ethernet6" + }, + { + "name": "Ethernet7" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet9" + }, + { + "name": "Ethernet10" + }, + { + "name": "Ethernet11" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet13" + }, + { + "name": "Ethernet14" + }, + { + "name": "Ethernet15" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet17" + }, + { + "name": "Ethernet18" + }, + { + "name": "Ethernet19" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet21" + }, + { + "name": "Ethernet22" + }, + { + "name": "Ethernet23" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet25" + }, + { + "name": "Ethernet26" + }, + { + "name": "Ethernet27" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet29" + }, + { + "name": "Ethernet30" + }, + { + "name": "Ethernet31" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet33" + }, + { + "name": "Ethernet34" + }, + { + "name": "Ethernet35" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet37" + }, + { + "name": "Ethernet38" + }, + { + "name": "Ethernet39" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet41" + }, + { + "name": "Ethernet42" + }, + { + "name": "Ethernet43" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet45" + }, + { + "name": "Ethernet46" + }, + { + "name": "Ethernet47" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet49" + }, + { + "name": "Ethernet50" + }, + { + "name": "Ethernet51" + }, + { + "name": "Ethernet52" + }, + { + "name": "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_54te-r0/platform_components.json b/device/accton/x86_64-accton_as4630_54te-r0/platform_components.json new file mode 100644 index 0000000000..5e70a87a41 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/platform_components.json @@ -0,0 +1,11 @@ +{ + "chassis": { + "AS4630-54TE-O-AC-F": { + "component": { + "CPLD1": { }, + "CPLD2": { }, + "BIOS": { } + } + } + } +} diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/eeprom.py deleted file mode 100755 index 7409239d01..0000000000 --- a/device/accton/x86_64-accton_as4630_54te-r0/plugins/eeprom.py +++ /dev/null @@ -1,13 +0,0 @@ -try: - from sonic_eeprom import eeprom_tlvinfo - -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - - -class board(eeprom_tlvinfo.TlvInfoDecoder): - _TLV_INFO_MAX_LEN = 256 - - def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/sys/bus/i2c/devices/1-0057/eeprom" - super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/psuutil.py deleted file mode 100755 index 92ae68eb87..0000000000 --- a/device/accton/x86_64-accton_as4630_54te-r0/plugins/psuutil.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python - -############################################################################# -# Accton -# -# Module contains an implementation of SONiC PSU Base API and -# provides the PSUs status which are available in the platform -# -############################################################################# - - -try: - from sonic_psu.psu_base import PsuBase -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - - -class PsuUtil(PsuBase): - """Platform-specific PSUutil class""" - - def __init__(self): - PsuBase.__init__(self) - - self.psu_path = "/sys/bus/i2c/devices/" - self.psu_presence = "/psu_present" - self.psu_oper_status = "/psu_power_good" - self.psu_mapping = { - 1: "10-0050", - 2: "11-0051", - } - - def get_num_psus(self): - return len(self.psu_mapping) - - def get_psu_status(self, index): - if index is None: - return False - - status = 0 - node = self.psu_path + self.psu_mapping[index] + self.psu_oper_status - try: - with open(node, 'r') as power_status: - status = int(power_status.read()) - except IOError: - return False - - return status == 1 - - def get_psu_presence(self, index): - if index is None: - return False - - status = 0 - node = self.psu_path + self.psu_mapping[index] + self.psu_presence - try: - with open(node, 'r') as presence_status: - status = int(presence_status.read()) - except IOError: - return False - - return status == 1 diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/sfputil.py deleted file mode 100755 index 63e6bd5364..0000000000 --- a/device/accton/x86_64-accton_as4630_54te-r0/plugins/sfputil.py +++ /dev/null @@ -1,196 +0,0 @@ -# sfputil.py -# -# Platform-specific SFP transceiver interface for SONiC -# - -try: - import sys - import time - from ctypes import create_string_buffer - from sonic_sfp.sfputilbase import SfpUtilBase -except ImportError as e: - raise ImportError("%s - required module not found" % str(e)) - -SFP_STATUS_INSERTED = '1' -SFP_STATUS_REMOVED = '0' - - -class SfpUtil(SfpUtilBase): - """Platform-specific SfpUtil class""" - - PORT_START = 49 - PORT_END = 54 - PORTS_IN_BLOCK = 54 - QSFP_START = 53 - - BASE_OOM_PATH = "/sys/bus/i2c/devices/{0}-0050/" - BASE_CPLD_PATH = "/sys/bus/i2c/devices/3-0060/" - - _port_to_is_present = {} - _port_to_lp_mode = {} - - _port_to_eeprom_mapping = {} - _port_to_i2c_mapping = { - 49: [18], - 50: [19], - 51: [20], - 52: [21], - 53: [22], - 54: [23], - } - - @property - def port_start(self): - return self.PORT_START - - @property - def port_end(self): - return self.PORT_END - - @property - def qsfp_ports(self): - return range(self.PORT_START, self.PORTS_IN_BLOCK + 1) - - @property - def port_to_eeprom_mapping(self): - return self._port_to_eeprom_mapping - - def __init__(self): - eeprom_path = self.BASE_OOM_PATH + "eeprom" - for x in range(self.port_start, self.port_end + 1): - self.port_to_eeprom_mapping[x] = eeprom_path.format( - self._port_to_i2c_mapping[x][0]) - SfpUtilBase.__init__(self) - - def get_presence(self, port_num): - # Check for invalid port_num - if port_num < self.port_start or port_num > self.port_end: - return False - - present_path = self.BASE_CPLD_PATH + "module_present_" + str(port_num) - self.__port_to_is_present = present_path - - try: - val_file = open(self.__port_to_is_present) - content = val_file.readline().rstrip() - val_file.close() - except IOError as e: - print ('Error: unable to access file: %s') % str(e) - return False - - if content == "1": - return True - - return False - - def get_low_power_mode(self, port_num): - # Check for invalid port_num - if port_num < self.QSFP_START or port_num > self.port_end: - return False - - try: - eeprom = None - if not self.get_presence(port_num): - return False - eeprom = open(self.port_to_eeprom_mapping[port_num], "rb") - eeprom.seek(93) - lpmode = ord(eeprom.read(1)) - - # if "Power override" bit is 1 and "Power set" bit is 1 - if ((lpmode & 0x3) == 0x3): - return True - - # High Power Mode if one of the following conditions is matched: - # 1. "Power override" bit is 0 - # 2. "Power override" bit is 1 and "Power set" bit is 0 - else: - return False - - except IOError as e: - print ('Error: unable to open file: %s') % str(e) - return False - finally: - if eeprom is not None: - eeprom.close() - time.sleep(0.01) - - def set_low_power_mode(self, port_num, lpmode): - # Check for invalid port_num - if port_num < self.QSFP_START or port_num > self.port_end: - return False - - try: - eeprom = None - if not self.get_presence(port_num): - return False # Port is not present, unable to set the eeprom - - # Fill in write buffer - # 0x3:Low Power Mode, 0x1:High Power Mode - regval = 0x3 if lpmode else 0x1 - - buffer = create_string_buffer(1) - if sys.version_info[0] >= 3: - buffer[0] = regval - else: - buffer[0] = chr(regval) - - # Write to eeprom - eeprom = open(self.port_to_eeprom_mapping[port_num], "r+b") - eeprom.seek(93) - eeprom.write(buffer[0]) - return True - except IOError as e: - print ('Error: unable to open file: %s') % str(e) - return False - finally: - if eeprom is not None: - eeprom.close() - time.sleep(0.01) - - def reset(self, port_num): - raise NotImplementedError - - @property - def _get_presence_bitmap(self): - - bits = [] - for x in range(self.port_start, self.port_end + 1): - bits.append(str(int(self.get_presence(x)))) - - rev = "".join(bits[::-1]) - return int(rev, 2) - - data = {'present': 0} - - def get_transceiver_change_event(self, timeout=0): - port_dict = {} - - if timeout == 0: - cd_ms = sys.maxsize - else: - cd_ms = timeout - - # poll per second - while cd_ms > 0: - reg_value = self._get_presence_bitmap - changed_ports = self.data['present'] ^ reg_value - if changed_ports != 0: - break - time.sleep(1) - cd_ms = cd_ms - 1000 - - if changed_ports != 0: - for port in range(self.port_start, self.port_end + 1): - # Mask off the bit corresponding to our port - mask = (1 << (port - self.port_start)) - if changed_ports & mask: - if (reg_value & mask) == 0: - port_dict[port] = SFP_STATUS_REMOVED - else: - port_dict[port] = SFP_STATUS_INSERTED - - # Update cache - self.data['present'] = reg_value - return True, port_dict - else: - return True, {} diff --git a/device/accton/x86_64-accton_as4630_54te-r0/plugins/ssd_util.py b/device/accton/x86_64-accton_as4630_54te-r0/plugins/ssd_util.py new file mode 100755 index 0000000000..4b173c5e38 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-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_54te-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as4630_54te-r0/pmon_daemon_control.json index a3b204e20d..44bad64942 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/pmon_daemon_control.json +++ b/device/accton/x86_64-accton_as4630_54te-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_54te-r0/sensors.conf b/device/accton/x86_64-accton_as4630_54te-r0/sensors.conf index b22fff04d0..cbb82e0dfc 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sensors.conf +++ b/device/accton/x86_64-accton_as4630_54te-r0/sensors.conf @@ -31,10 +31,10 @@ chip "as4630_54te_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_54te-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/chassis.py index 9f39c903c6..9ec4c7ccf6 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/chassis.py @@ -6,27 +6,27 @@ # ############################################################################# -import subprocess - try: + import sys from sonic_platform_base.chassis_base import ChassisBase from .helper import APIHelper + from .event import SfpEvent except ImportError as e: raise ImportError(str(e) + "- required module not found") NUM_FAN_TRAY = 3 NUM_FAN = 2 NUM_PSU = 2 -NUM_THERMAL = 3 +NUM_THERMAL = 8 NUM_QSFP = 6 PORT_START = 49 PORT_END = 54 -NUM_COMPONENT = 2 +NUM_COMPONENT = 3 HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" REBOOT_CAUSE_FILE = "reboot-cause.txt" PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" -HOST_CHK_CMD = ["docker"] +HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" SYSLED_FNODE = "/sys/class/leds/diag/brightness" SYSLED_MODES = { "0" : "STATUS_LED_COLOR_OFF", @@ -42,7 +42,6 @@ class Chassis(ChassisBase): def __init__(self): ChassisBase.__init__(self) self._api_helper = APIHelper() - self._api_helper = APIHelper() self.is_host = self._api_helper.is_host() self.config_data = {} @@ -59,6 +58,7 @@ def __initialize_sfp(self): for index in range(0, PORT_END): sfp = Sfp(index) self._sfp_list.append(sfp) + self._sfpevent = SfpEvent(self._sfp_list) self.sfp_module_initialized = True def __initialize_fan(self): @@ -89,23 +89,6 @@ def __initialize_components(self): component = Component(index) self._component_list.append(component) - def __initialize_watchdog(self): - from sonic_platform.watchdog import Watchdog - self._watchdog = Watchdog() - - - def __is_host(self): - return subprocess.call(HOST_CHK_CMD) == 0 - - def __read_txt_file(self, file_path): - try: - with open(file_path, 'r') as fd: - data = fd.read() - return data.strip() - except IOError: - pass - return None - def get_name(self): """ Retrieves the name of the device @@ -113,7 +96,7 @@ def get_name(self): string: The name of the device """ - return self._api_helper.hwsku + return self._eeprom.get_modelstr() def get_presence(self): """ @@ -176,6 +159,12 @@ def get_reboot_cause(self): return ('REBOOT_CAUSE_NON_HARDWARE', sw_reboot_cause) + def get_change_event(self, timeout=0): + # SFP event + if not self.sfp_module_initialized: + self.__initialize_sfp() + return self._sfpevent.get_sfp_event(timeout) + def get_sfp(self, index): """ Retrieves sfp represented by (1-based) index @@ -234,3 +223,28 @@ def set_status_led(self, color): return False else: return self._api_helper.write_txt_file(SYSLED_FNODE, mode) + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._eeprom.get_serial() + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return self._eeprom.get_revisionstr() diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py index 8137d0f3a7..f5dafd0073 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/component.py @@ -6,10 +6,12 @@ # ############################################################################# - try: + import os + import json from sonic_platform_base.component_base import ComponentBase from .helper import APIHelper + from sonic_py_common.general import getstatusoutput_noshell except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -20,6 +22,7 @@ BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" COMPONENT_LIST= [ ("CPLD1", "CPLD 1"), + ("CPLD2", "CPLD CPU"), ("BIOS", "Basic Input/Output System") ] @@ -58,6 +61,15 @@ def __get_cpld_version(self): return cpld_version + def __get_cpldcpu_version(self): + cpld_version = dict() + cmd = ["i2cget", "-y", "1", "0x65", "0x01"] + status, output1 = getstatusoutput_noshell(cmd) + cmd = ["i2cget", "-y", "1", "0x65", "0x02"] + status, output2 = getstatusoutput_noshell(cmd) + cpld_version[self.name] = "{}{}{}".format(int(output1,16),".",int(output2,16)) + return cpld_version + def get_name(self): """ Retrieves the name of the component @@ -85,9 +97,12 @@ def get_firmware_version(self): if self.name == "BIOS": fw_version = self.__get_bios_version() - elif "CPLD" in self.name: + elif self.name == "CPLD1": cpld_version = self.__get_cpld_version() fw_version = cpld_version.get(self.name) + elif self.name == "CPLD2": + cpld_version = self.__get_cpldcpu_version() + fw_version = cpld_version.get(self.name) return fw_version @@ -99,4 +114,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 False == os.path.exists("/tmp/install.json") : + print("Installation failed without jsonfile") + return False + + input_file = open ('/tmp/install.json') + json_array = json.load(input_file) + ret = 1 + for item in json_array: + if item.get('id')==None or item.get('path')==None: + continue + if self.name == item['id'] and item['path'] and item.get('cpu'): + print( "Find", item['id'], item['path'], item['cpu'] ) + ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'], item['cpu'] ]) + if ret==0: + break + elif self.name == item['id'] and item['path']: + print( "Find", item['id'], item['path'] ) + ret, output = getstatusoutput_noshell(["/tmp/run_install.sh", item['id'], item['path'] ]) + if ret==0: + break + + if ret==0: + return True + else : + return False + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return True + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + If the agent cannot determine the parent-relative position + for some reason, or if the associated value of + entPhysicalContainedIn is'0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device + or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py index 7bf2bb58d1..f3bc202ebd 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/eeprom.py @@ -13,7 +13,7 @@ CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' CACHE_FILE = 'syseeprom_cache' - +NULL = 'N/A' class Tlv(eeprom_tlvinfo.TlvInfoDecoder): @@ -33,7 +33,7 @@ def __parse_output(self, decode_output): for line in lines: try: match = re.search( - '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + '(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)(.+)', line) if match is not None: idx = match.group(1) value = match.group(3).rstrip('\0') @@ -92,11 +92,46 @@ def _load_eeprom(self): return self.__parse_output(decode_output) + def _valid_tlv(self, eeprom_data): + tlvinfo_type_codes_list = [ + self._TLV_CODE_PRODUCT_NAME, + self._TLV_CODE_PART_NUMBER, + self._TLV_CODE_SERIAL_NUMBER, + self._TLV_CODE_MAC_BASE, + self._TLV_CODE_MANUF_DATE, + self._TLV_CODE_DEVICE_VERSION, + self._TLV_CODE_LABEL_REVISION, + self._TLV_CODE_PLATFORM_NAME, + self._TLV_CODE_ONIE_VERSION, + self._TLV_CODE_MAC_SIZE, + self._TLV_CODE_MANUF_NAME, + self._TLV_CODE_MANUF_COUNTRY, + self._TLV_CODE_VENDOR_NAME, + self._TLV_CODE_DIAG_VERSION, + self._TLV_CODE_SERVICE_TAG, + self._TLV_CODE_VENDOR_EXT, + self._TLV_CODE_CRC_32 + ] + + for code in tlvinfo_type_codes_list: + code_str = "0x{:X}".format(code) + eeprom_data[code_str] = eeprom_data.get(code_str, NULL) + return eeprom_data + def get_eeprom(self): - return self._eeprom + return self._valid_tlv(self._eeprom) + + def get_pn(self): + return self._eeprom.get('0x22', NULL) def get_serial(self): - return self._eeprom.get('0x23', "Undefined.") + return self._eeprom.get('0x23', NULL) def get_mac(self): - return self._eeprom.get('0x24', "Undefined.") + return self._eeprom.get('0x24', NULL) + + def get_modelstr(self): + return self._eeprom.get('0x21', NULL) + + def get_revisionstr(self): + return self._eeprom.get('0x27', NULL) \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/event.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/event.py new file mode 100644 index 0000000000..ade466b2e3 --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/event.py @@ -0,0 +1,109 @@ +try: + import time + from sonic_py_common.logger import Logger + from .sfp import Sfp +except ImportError as e: + raise ImportError(repr(e) + " - required module not found") + +POLL_INTERVAL_IN_SEC = 1 + +# SFP errors that will block eeprom accessing +SFP_BLOCKING_ERRORS = [ + Sfp.SFP_ERROR_BIT_I2C_STUCK, + Sfp.SFP_ERROR_BIT_BAD_EEPROM, + Sfp.SFP_ERROR_BIT_UNSUPPORTED_CABLE, + Sfp.SFP_ERROR_BIT_HIGH_TEMP, + Sfp.SFP_ERROR_BIT_BAD_CABLE +] + +class SfpEvent: + ''' Listen to insert/remove sfp events ''' + + def __init__(self, sfp_list): + self._sfp_list = sfp_list + self._logger = Logger() + self._sfp_change_event_data = {'present': 0} + + def get_presence_bitmap(self): + bitmap = 0 + for sfp in self._sfp_list: + modpres = sfp.get_presence() + i=sfp.get_position_in_parent() - 1 + if modpres: + bitmap = bitmap | (1 << i) + return bitmap + + def get_sfp_event(self, timeout=2000): + port_dict = {} + change_dict = {} + change_dict['sfp'] = port_dict + + if timeout < 1000: + cd_ms = 1000 + else: + cd_ms = timeout + + while cd_ms > 0: + bitmap = self.get_presence_bitmap() + changed_ports = self._sfp_change_event_data['present'] ^ bitmap + if changed_ports != 0: + break + time.sleep(POLL_INTERVAL_IN_SEC) + # timeout=0 means wait for event forever + if timeout != 0: + cd_ms = cd_ms - POLL_INTERVAL_IN_SEC * 1000 + + if changed_ports != 0: + for sfp in self._sfp_list: + i=sfp.get_position_in_parent() - 1 + if (changed_ports & (1 << i)) == 0: + continue + + if (bitmap & (1 << i)) == 0: + port_dict[i+1] = '0' + else: + # sfp.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 \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py index 8f48931244..e145503551 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan.py @@ -38,10 +38,6 @@ }, } - -FAN_NAME_LIST = ["FAN-1F", "FAN-1R", "FAN-2F", "FAN-2R", - "FAN-3F", "FAN-3R"] - class Fan(FanBase): """Platform-specific Fan class""" @@ -63,7 +59,7 @@ def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): self.psu_cpld_path = I2C_PATH.format( self.psu_i2c_num, self.psu_i2c_addr) - FanBase.__init__(self) + FanBase.__init__(self) def get_direction(self): @@ -73,16 +69,14 @@ def get_direction(self): A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST depending on fan direction """ - - if not self.is_psu_fan: dir_str = "{}{}{}".format(CPLD_FAN_I2C_PATH, 'direction_', self.fan_tray_index+1) val=self._api_helper.read_txt_file(dir_str) if val is not None: if int(val, 10)==0:#F2B - direction=self.FAN_DIRECTION_EXHAUST - else: direction=self.FAN_DIRECTION_INTAKE + else: + direction=self.FAN_DIRECTION_EXHAUST else: direction=self.FAN_DIRECTION_EXHAUST @@ -105,7 +99,7 @@ def get_speed(self): Returns: An integer, the percentage of full fan speed, in the range 0 (off) to 100 (full speed) - + """ speed = 0 if self.is_psu_fan: @@ -117,7 +111,7 @@ def get_speed(self): speed=100 else: return 0 - elif self.get_presence(): + elif self.get_presence(): speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage') speed=self._api_helper.read_txt_file(speed_path) if speed is None: @@ -156,7 +150,7 @@ def set_speed(self, speed): A boolean, True if speed is set successfully, False if not """ - if not self.is_psu_fan and self.get_presence(): + if not self.is_psu_fan and self.get_presence(): speed_path = "{}{}".format(CPLD_FAN_I2C_PATH, 'duty_cycle_percentage') return self._api_helper.write_txt_file(speed_path, int(speed)) @@ -179,14 +173,13 @@ def get_status_led(self): Returns: A string, one of the predefined STATUS_LED_COLOR_* strings above """ - status=self.get_presence() - if status is None: - return self.STATUS_LED_COLOR_OFF + if self.is_psu_fan: + return None return { - 1: self.STATUS_LED_COLOR_GREEN, - 0: self.STATUS_LED_COLOR_RED - }.get(status, self.STATUS_LED_COLOR_OFF) + True: self.STATUS_LED_COLOR_GREEN, + False: self.STATUS_LED_COLOR_OFF + }.get(self.get_status(), self.STATUS_LED_COLOR_OFF) def get_name(self): """ @@ -194,11 +187,10 @@ def get_name(self): Returns: string: The name of the device """ - fan_name = FAN_NAME_LIST[self.fan_tray_index*2 + self.fan_index] \ - if not self.is_psu_fan \ - else "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) + if self.is_psu_fan: + return "PSU-{} FAN-{}".format(self.psu_index+1, self.fan_index+1) - return fan_name + return "FAN-{}".format(self.fan_tray_index+1) def get_presence(self): """ @@ -206,8 +198,6 @@ def get_presence(self): Returns: bool: True if FAN is present, False if not """ - - if self.is_psu_fan: present_path="{}{}".format(self.psu_cpld_path, 'psu_present') else: @@ -226,6 +216,11 @@ def get_status(self): A boolean value, True if device is operating properly, False if not """ if self.is_psu_fan: + psu_fan_path = "{}{}".format(self.psu_cpld_path, 'psu_power_good') + val = self._api_helper.read_txt_file(psu_fan_path) + if val is None or int(val, 10)==0: + return False + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_fault') val=self._api_helper.read_txt_file(psu_fan_path) if val is not None: @@ -268,7 +263,7 @@ def get_position_in_parent(self): integer: The 1-based relative physical position in parent device or -1 if cannot determine the position """ - return (self.fan_tray_index+1) \ + return (self.fan_index+1) \ if not self.is_psu_fan else (self.psu_index+1) def is_replaceable(self): diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py index e21163c106..b4c2146b9f 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/fan_drawer.py @@ -10,7 +10,7 @@ except ImportError as e: raise ImportError(str(e) + "- required module not found") -FANS_PER_FANTRAY = 2 +FANS_PER_FANTRAY = 1 class FanDrawer(FanDrawerBase): @@ -88,3 +88,25 @@ def is_replaceable(self): bool: True if it is replaceable. """ return True + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + Args: + color: A string representing the color with which to set the + fan module status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + return False # Not supported + + def get_status_led(self): + """ + Gets the state of the fan status LED + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return { + True: self.STATUS_LED_COLOR_GREEN, + False: self.STATUS_LED_COLOR_OFF + }.get(self.get_status(), self.STATUS_LED_COLOR_OFF) diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py index b19fab85de..f6adee3098 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/helper.py @@ -1,8 +1,14 @@ import os import struct -import subprocess +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 = "" @@ -14,7 +20,11 @@ def __init__(self): (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() def is_host(self): - return subprocess.call(HOST_CHK_CMD) == 0 + try: + status, output = getstatusoutput_noshell(HOST_CHK_CMD) + return status == 0 + except Exception: + return False def pci_get_value(self, resource, offset): status = True @@ -29,11 +39,20 @@ def pci_get_value(self, resource, offset): status = False return status, result + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + def read_txt_file(self, file_path): try: with open(file_path, 'r', errors='replace') as fd: data = fd.read() - return data.strip() + ret = data.strip() + if len(ret) > 0: + return ret except IOError: pass return None @@ -46,3 +65,304 @@ def write_txt_file(self, file_path, value): 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/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/pcie.py new file mode 100644 index 0000000000..73d3627dbf --- /dev/null +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/pcie.py @@ -0,0 +1,19 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# Base PCIe class +############################################################################# + +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Pcie(PcieUtil): + """Edgecore Platform-specific PCIe class""" + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) \ No newline at end of file diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py index 8eab43891b..6df7fd3ffb 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/psu.py @@ -10,7 +10,7 @@ try: from sonic_platform_base.psu_base import PsuBase - #from sonic_platform.fan import Fan + from sonic_platform.thermal import Thermal from .helper import APIHelper except ImportError as e: raise ImportError(str(e) + "- required module not found") @@ -58,19 +58,13 @@ def __init__(self, psu_index=0): self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"] self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) self.__initialize_fan() - ''' - for fan_index in range(0, PSU_NUM_FAN[self.index]): - #def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): - #fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) - fan = Fan(fan_index, 0, True, self.index) - self._fan_list.append(fan) - ''' def __initialize_fan(self): from sonic_platform.fan import Fan for fan_index in range(0, PSU_NUM_FAN[self.index]): fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) self._fan_list.append(fan) + self._thermal_list.append(Thermal(is_psu=True, psu_index=self.index)) def get_voltage(self): """ @@ -79,12 +73,15 @@ def get_voltage(self): A float number, the output voltage in volts, e.g. 12.1 """ + if self.get_status() is not True: + return 0.0 + vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out') vout_val=self._api_helper.read_txt_file(vout_path) if vout_val is not None: return float(vout_val)/ 1000 else: - return 0 + return 0.0 def get_current(self): """ @@ -92,12 +89,15 @@ def get_current(self): Returns: A float number, the electric current in amperes, e.g 15.4 """ + if self.get_status() is not True: + return 0.0 + iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out') val=self._api_helper.read_txt_file(iout_path) if val is not None: return float(val)/1000 else: - return 0 + return 0.0 def get_power(self): """ @@ -105,12 +105,15 @@ def get_power(self): Returns: A float number, the power in watts, e.g. 302.6 """ + if self.get_status() is not True: + return 0.0 + pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out') val=self._api_helper.read_txt_file(pout_path) if val is not None: return float(val)/1000 else: - return 0 + return 0.0 def get_powergood_status(self): """ @@ -156,12 +159,15 @@ def get_temperature(self): A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ + if self.get_status() is not True: + return 0.0 + temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input') val=self._api_helper.read_txt_file(temp_path) if val is not None: return float(val)/1000 else: - return 0 + return 0.0 def get_temperature_high_threshold(self): """ @@ -170,7 +176,7 @@ def get_temperature_high_threshold(self): A float number, the high threshold temperature of PSU in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - return False #Not supported + return self._thermal_list[0].get_high_threshold() def get_voltage_high_threshold(self): """ @@ -179,12 +185,15 @@ def get_voltage_high_threshold(self): A float number, the high threshold output voltage in volts, e.g. 12.1 """ + if self.get_status() is not True: + return 0.0 + vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_max') vout_val=self._api_helper.read_txt_file(vout_path) if vout_val is not None: return float(vout_val)/ 1000 else: - return 0 + return 0.0 def get_voltage_low_threshold(self): """ @@ -193,12 +202,15 @@ def get_voltage_low_threshold(self): A float number, the low threshold output voltage in volts, e.g. 12.1 """ + if self.get_status() is not True: + return 0.0 + vout_path = "{}{}".format(self.hwmon_path, 'psu_mfr_vout_min') vout_val=self._api_helper.read_txt_file(vout_path) if vout_val is not None: return float(vout_val)/ 1000 else: - return 0 + return 0.0 def get_name(self): """ @@ -219,7 +231,7 @@ def get_presence(self): if val is not None: return int(val, 10) == 1 else: - return 0 + return False def get_status(self): """ @@ -232,7 +244,7 @@ def get_status(self): if val is not None: return int(val, 10) == 1 else: - return 0 + return False def get_model(self): """ @@ -275,3 +287,34 @@ def is_replaceable(self): bool: True if it is replaceable. """ return True + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + revision_path = "{}{}".format(self.hwmon_path, 'psu_mfr_revision') + revision = self._api_helper.read_txt_file(revision_path) + if revision is None: + return 'N/A' + + return revision + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + if self.get_status() is not True: + return 0.0 + + pout_max_path = "{}{}".format(self.hwmon_path, 'psu_mfr_pout_max') + val=self._api_helper.read_txt_file(pout_max_path) + if val is not None: + return float(val)/1000 + else: + return 0.0 diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py index adab3d294c..d6f894b280 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/sfp.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python - ############################################################################# # Edgecore # @@ -8,115 +6,26 @@ # ############################################################################# +import os import time -import sys -import subprocess -from ctypes import create_string_buffer try: - from sonic_platform_base.sfp_base import SfpBase - from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom - from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId - from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom - from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId - #from sonic_platform_base.sonic_sfp.sff8472 import sffbase + from sonic_py_common.logger import Logger + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper from .helper import APIHelper + from sonic_py_common import device_info except ImportError as e: raise ImportError(str(e) + "- required module not found") +NONE_SFP_TYPE = "NONE-SFP" +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" + CPLD_I2C_PATH = "/sys/bus/i2c/devices/3-0060/" -QSFP_INFO_OFFSET = 128 -QSFP_DOM_OFFSET = 0 - -SFP_INFO_OFFSET = 0 -SFP_DOM_OFFSET = 256 - -XCVR_INTFACE_BULK_OFFSET = 0 -XCVR_INTFACE_BULK_WIDTH_QSFP = 20 -XCVR_INTFACE_BULK_WIDTH_SFP = 21 -XCVR_HW_REV_WIDTH_QSFP = 2 -XCVR_HW_REV_WIDTH_SFP = 4 -XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 -XCVR_VENDOR_NAME_OFFSET = 20 -XCVR_VENDOR_NAME_WIDTH = 16 -XCVR_VENDOR_OUI_OFFSET = 37 -XCVR_VENDOR_OUI_WIDTH = 3 -XCVR_VENDOR_PN_OFFSET = 40 -XCVR_VENDOR_PN_WIDTH = 16 -XCVR_HW_REV_OFFSET = 56 -XCVR_HW_REV_WIDTH_OSFP = 2 -XCVR_HW_REV_WIDTH_SFP = 4 -XCVR_VENDOR_SN_OFFSET = 68 -XCVR_VENDOR_SN_WIDTH = 16 -XCVR_VENDOR_DATE_OFFSET = 84 -XCVR_VENDOR_DATE_WIDTH = 8 -XCVR_DOM_CAPABILITY_OFFSET = 92 -XCVR_DOM_CAPABILITY_WIDTH = 1 - -# Offset for values in QSFP eeprom -QSFP_DOM_REV_OFFSET = 1 -QSFP_DOM_REV_WIDTH = 1 -QSFP_TEMPE_OFFSET = 22 -QSFP_TEMPE_WIDTH = 2 -QSFP_VOLT_OFFSET = 26 -QSFP_VOLT_WIDTH = 2 -QSFP_CHANNL_MON_OFFSET = 34 -QSFP_CHANNL_MON_WIDTH = 16 -QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 -QSFP_CONTROL_OFFSET = 86 -QSFP_CONTROL_WIDTH = 8 -QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 -QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 -QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 -QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 -QSFP_POWEROVERRIDE_OFFSET = 93 -QSFP_POWEROVERRIDE_WIDTH = 1 -QSFP_PAGE03_OFFSET = 384 -QSFP_MODULE_THRESHOLD_OFFSET = 128 -QSFP_MODULE_THRESHOLD_WIDTH = 24 -QSFP_CHANNEL_THRESHOLD_OFFSET = 176 -QSFP_CHANNEL_THRESHOLD_WIDTH = 16 - -qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', - 'Length OM2(m)', 'Length OM1(m)', - 'Length Cable Assembly(m)') - -qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', - 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', - 'Fibre Channel link length/Transmitter Technology', - 'Fibre Channel transmission media', 'Fibre Channel Speed') - - -# Offset for values in SFP eeprom -SFP_TEMPE_OFFSET = 96 -SFP_TEMPE_WIDTH = 2 -SFP_VOLT_OFFSET = 98 -SFP_VOLT_WIDTH = 2 -SFP_CHANNL_MON_OFFSET = 100 -SFP_CHANNL_MON_WIDTH = 6 -SFP_MODULE_THRESHOLD_OFFSET = 0 -SFP_MODULE_THRESHOLD_WIDTH = 40 -SFP_CHANNL_THRESHOLD_OFFSET = 112 -SFP_CHANNL_THRESHOLD_WIDTH = 2 -SFP_STATUS_CONTROL_OFFSET = 110 -SFP_STATUS_CONTROL_WIDTH = 1 -SFP_TX_DISABLE_HARD_BIT = 7 -SFP_TX_DISABLE_SOFT_BIT = 6 - -sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', - 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', - 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') - -sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', - 'ESCONComplianceCodes', 'SONETComplianceCodes', - 'EthernetComplianceCodes', 'FibreChannelLinkLength', - 'FibreChannelTechnology', 'SFP+CableTechnology', - 'FibreChannelTransmissionMedia', 'FibreChannelSpeed') - - -class Sfp(SfpBase): +logger = Logger() +class Sfp(SfpOptoeBase): """Platform-specific Sfp class""" # Port number @@ -126,10 +35,7 @@ class Sfp(SfpBase): # Path to sysfs PLATFORM_ROOT_PATH = "/usr/share/sonic/device" PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" - HOST_CHK_CMD = ["docker"] - - PLATFORM = "x86_64-accton_as4630_54te-r0" - HWSKU = "Accton-AS4630-54TE" + HOST_CHK_CMD = "which systemctl > /dev/null 2>&1" _port_to_i2c_mapping = { 49: 18, @@ -140,510 +46,41 @@ class Sfp(SfpBase): 54: 23, } + 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, sfp_index=0): + SfpOptoeBase.__init__(self) self._api_helper=APIHelper() # Init index - self.index = sfp_index - self.port_num = self.index + 1 + self.port_num = sfp_index + 1 + self.index = self.port_num + if self.port_num < self.PORT_START: + self.sfp_type = NONE_SFP_TYPE + elif self.port_num < 53: + self.sfp_type = SFP_TYPE + else: + self.sfp_type = QSFP_TYPE + # Init eeprom path eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' self.port_to_eeprom_mapping = {} for x in range(self.PORT_START, self.PORT_END + 1): self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x]) - self.info_dict_keys = ['type', 'vendor_rev', 'serial', 'manufacturer', 'model', 'connector', 'encoding', 'ext_identifier', - 'ext_rateselect_compliance', 'cable_type', 'cable_length', 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui', - 'application_advertisement', 'type_abbrv_name'] - - self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', - 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] - - self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', - 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] - - SfpBase.__init__(self) - - def _convert_string_to_num(self, value_str): - if "-inf" in value_str: - return 'N/A' - elif "Unknown" in value_str: - return 'N/A' - elif 'dBm' in value_str: - t_str = value_str.rstrip('dBm') - return float(t_str) - elif 'mA' in value_str: - t_str = value_str.rstrip('mA') - return float(t_str) - elif 'C' in value_str: - t_str = value_str.rstrip('C') - return float(t_str) - elif 'Volts' in value_str: - t_str = value_str.rstrip('Volts') - return float(t_str) - else: - return 'N/A' - - def __write_txt_file(self, file_path, value): - try: - with open(file_path, 'w', buffering=0) as fd: - fd.write(str(value)) - except Exception: - return False - return True + def get_eeprom_path(self): + return self.port_to_eeprom_mapping[self.port_num] def __is_host(self): - return subprocess.call(self.HOST_CHK_CMD) == 0 - - def __get_path_to_port_config_file(self): - platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) - hwsku_path = "/".join([platform_path, self.HWSKU] - ) if self.__is_host() else self.PMON_HWSKU_PATH - return "/".join([hwsku_path, "port_config.ini"]) - - def __read_eeprom_specific_bytes(self, offset, num_bytes): - sysfsfile_eeprom = None - eeprom_raw = [] - for i in range(0, num_bytes): - eeprom_raw.append("0x00") - - sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] - try: - sysfsfile_eeprom = open( - sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) - sysfsfile_eeprom.seek(offset) - raw = sysfsfile_eeprom.read(num_bytes) - if sys.version_info[0] >= 3: - for n in range(0, num_bytes): - eeprom_raw[n] = hex(raw[n])[2:].zfill(2) - else: - for n in range(0, num_bytes): - eeprom_raw[n] = hex(ord(raw[n]))[2:].zfill(2) - except Exception: - pass - finally: - if sysfsfile_eeprom: - sysfsfile_eeprom.close() - - return eeprom_raw - - def get_transceiver_info(self): - """ - Retrieves transceiver info of this SFP - Returns: - A dict which contains following keys/values : - ======================================================================== - keys |Value Format |Information - ---------------------------|---------------|---------------------------- - type |1*255VCHAR |type of SFP - vendor_rev |1*255VCHAR |vendor revision of SFP - serial |1*255VCHAR |serial number of the SFP - manufacturer |1*255VCHAR |SFP vendor name - model |1*255VCHAR |SFP model name - connector |1*255VCHAR |connector information - encoding |1*255VCHAR |encoding information - ext_identifier |1*255VCHAR |extend identifier - ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance - cable_length |INT |cable length in m - nominal_bit_rate |INT |nominal bit rate by 100Mbs - specification_compliance |1*255VCHAR |specification compliance - vendor_date |1*255VCHAR |vendor date - vendor_oui |1*255VCHAR |vendor OUI - application_advertisement |1*255VCHAR |supported applications advertisement - ======================================================================== - """ - # check present status - if self.port_num < 49: - return {} - elif self.port_num < 53: - sfpi_obj = sff8472InterfaceId() #SFP - else: - sfpi_obj = sff8436InterfaceId() #QSFP - if not self.get_presence() or not sfpi_obj: - return {} - - if self.port_num < 53: - offset = SFP_INFO_OFFSET - sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP) - else: - offset = QSFP_INFO_OFFSET - sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP) - - sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk( - sfp_interface_bulk_raw, 0) - - sfp_vendor_name_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) - sfp_vendor_name_data = sfpi_obj.parse_vendor_name( - sfp_vendor_name_raw, 0) - - sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) - sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn( - sfp_vendor_pn_raw, 0) - - if self.port_num < 53: - sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) - else: - sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP) - - sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev( - sfp_vendor_rev_raw, 0) - - sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) - sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn( - sfp_vendor_sn_raw, 0) - - sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) - if sfp_vendor_oui_raw is not None: - sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui( - sfp_vendor_oui_raw, 0) - - sfp_vendor_date_raw = self.__read_eeprom_specific_bytes( - (offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) - sfp_vendor_date_data = sfpi_obj.parse_vendor_date( - sfp_vendor_date_raw, 0) - - transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') - compliance_code_dict = dict() - - if sfp_interface_bulk_data: - transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] - transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] - transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] - transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] - transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] - transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] - - transceiver_info_dict['manufacturer'] = sfp_vendor_name_data[ - 'data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' - transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' - transceiver_info_dict['vendor_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' - transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' - transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' - transceiver_info_dict['vendor_date'] = sfp_vendor_date_data[ - 'data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' - transceiver_info_dict['cable_type'] = "Unknown" - transceiver_info_dict['cable_length'] = "Unknown" - - if self.port_num < 53: - for key in sfp_cable_length_tup: - if key in sfp_interface_bulk_data['data']: - transceiver_info_dict['cable_type'] = key - transceiver_info_dict['cable_length'] = str( - sfp_interface_bulk_data['data'][key]['value']) - - for key in sfp_compliance_code_tup: - if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: - compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] - - transceiver_info_dict['specification_compliance'] = str( - compliance_code_dict) - transceiver_info_dict['nominal_bit_rate'] = str( - sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) - else: - for key in qsfp_cable_length_tup: - if key in sfp_interface_bulk_data['data']: - transceiver_info_dict['cable_type'] = key - transceiver_info_dict['cable_length'] = str( - sfp_interface_bulk_data['data'][key]['value']) - - for key in qsfp_compliance_code_tup: - if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: - compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] - - transceiver_info_dict['specification_compliance'] = str( - compliance_code_dict) - transceiver_info_dict['nominal_bit_rate'] = str( - sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) - - - return transceiver_info_dict - - def get_transceiver_bulk_status(self): - """ - Retrieves transceiver bulk status of this SFP - Returns: - A dict which contains following keys/values : - ======================================================================== - keys |Value Format |Information - ---------------------------|---------------|---------------------------- - rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. - tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. - reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. - lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. - tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. - tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 - | |to channel 3. - temperature |INT |module temperature in Celsius - voltage |INT |supply voltage in mV - txbias |INT |TX Bias Current in mA, n is the channel number, - | |for example, tx2bias stands for tx bias of channel 2. - rxpower |INT |received optical power in mW, n is the channel number, - | |for example, rx2power stands for rx power of channel 2. - txpower |INT |TX output power in mW, n is the channel number, - | |for example, tx2power stands for tx power of channel 2. - ======================================================================== - """ - # check present status - if self.port_num < 53: #SFP case - sfpd_obj = sff8472Dom() - if not self.get_presence() or not sfpd_obj: - return {} - - eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) - sfpi_obj = sff8472InterfaceId(eeprom_ifraw) - cal_type = sfpi_obj.get_calibration_type() - sfpd_obj._calibration_type = cal_type - - offset = SFP_DOM_OFFSET - transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') - dom_temperature_raw = self.__read_eeprom_specific_bytes( - (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) - - if dom_temperature_raw is not None: - dom_temperature_data = sfpd_obj.parse_temperature( - dom_temperature_raw, 0) - transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] - - dom_voltage_raw = self.__read_eeprom_specific_bytes( - (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) - if dom_voltage_raw is not None: - dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) - transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] - - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) - if dom_channel_monitor_raw is not None: - dom_voltage_data = sfpd_obj.parse_channel_monitor_params( - dom_channel_monitor_raw, 0) - transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] - transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] - transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] - - else: #QSFP case - sfpd_obj = sff8436Dom() - sfpi_obj = sff8436InterfaceId() - - if not self.get_presence() or not sfpi_obj or not sfpd_obj: - return {} - - transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') - offset = QSFP_DOM_OFFSET - offset_xcvr = QSFP_INFO_OFFSET - - # QSFP capability byte parse, through this byte can know whether it support tx_power or not. - # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, - # need to add more code for determining the capability and version compliance - # in SFF-8636 dom capability definitions evolving with the versions. - qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( - (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) - if qsfp_dom_capability_raw is not None: - qspf_dom_capability_data = sfpi_obj.parse_dom_capability( - qsfp_dom_capability_raw, 0) - else: - return None - - dom_temperature_raw = self.__read_eeprom_specific_bytes( - (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) - if dom_temperature_raw is not None: - dom_temperature_data = sfpd_obj.parse_temperature( - dom_temperature_raw, 0) - transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] - - dom_voltage_raw = self.__read_eeprom_specific_bytes( - (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) - if dom_voltage_raw is not None: - dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) - transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] - - qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( - (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) - if qsfp_dom_rev_raw is not None: - qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) - qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] - - # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 - # and claimed that it support tx_power with one indicator bit. - dom_channel_monitor_data = {} - dom_channel_monitor_raw = None - qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] - if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) - if dom_channel_monitor_raw is not None: - dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( - dom_channel_monitor_raw, 0) - - else: - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) - if dom_channel_monitor_raw is not None: - dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( - dom_channel_monitor_raw, 0) - transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] - transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] - transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] - transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] - - if dom_channel_monitor_raw: - transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] - transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] - transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] - transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] - transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] - transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] - transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] - transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] - #End of else - - - for key in transceiver_dom_info_dict: - transceiver_dom_info_dict[key] = self._convert_string_to_num( - transceiver_dom_info_dict[key]) - - transceiver_dom_info_dict['rx_los'] = self.get_rx_los() - transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() - transceiver_dom_info_dict['reset_status'] = self.get_reset_status() - transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() - - return transceiver_dom_info_dict - - def get_transceiver_threshold_info(self): - """ - Retrieves transceiver threshold info of this SFP - Returns: - A dict which contains following keys/values : - ======================================================================== - keys |Value Format |Information - ---------------------------|---------------|---------------------------- - temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. - templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. - temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. - templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. - vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. - vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. - vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. - vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. - rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. - rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. - rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. - rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. - txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. - txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. - txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. - txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. - txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. - txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. - txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. - txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. - ======================================================================== - """ - # check present status - if self.port_num < 53: - sfpd_obj = sff8472Dom() - - if not self.get_presence() and not sfpd_obj: - return {} - - eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) - sfpi_obj = sff8472InterfaceId(eeprom_ifraw) - cal_type = sfpi_obj.get_calibration_type() - sfpd_obj._calibration_type = cal_type - - offset = SFP_DOM_OFFSET - transceiver_dom_threshold_info_dict = dict.fromkeys( - self.threshold_dict_keys, 'N/A') - dom_module_threshold_raw = self.__read_eeprom_specific_bytes( - (offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) - if dom_module_threshold_raw is not None: - dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold( - dom_module_threshold_raw, 0) - - transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] - transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] - transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] - transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] - transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] - transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] - transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data[ - 'data']['VoltageHighWarning']['value'] - transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] - transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] - transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] - transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] - transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] - transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] - - for key in transceiver_dom_threshold_info_dict: - transceiver_dom_threshold_info_dict[key] = self._convert_string_to_num( - transceiver_dom_threshold_info_dict[key]) - - return transceiver_dom_threshold_info_dict - - - else: - sfpd_obj = sff8436Dom() - - if not self.get_presence() or not sfpd_obj: - return {} - - offset = QSFP_PAGE03_OFFSET - transceiver_dom_threshold_dict = dict.fromkeys( - self.threshold_dict_keys, 'N/A') - dom_thres_raw = self.__read_eeprom_specific_bytes( - offset + QSFP_MODULE_THRESHOLD_OFFSET, QSFP_MODULE_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None - - if dom_thres_raw: - module_threshold_values = sfpd_obj.parse_module_threshold_values( - dom_thres_raw, 0) - module_threshold_data = module_threshold_values.get('data') - if module_threshold_data: - transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] - transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] - transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] - transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] - transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] - transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] - transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] - transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] - - dom_thres_raw = self.__read_eeprom_specific_bytes( - offset + QSFP_CHANNEL_THRESHOLD_OFFSET, QSFP_CHANNEL_THRESHOLD_WIDTH) if self.get_presence() and sfpd_obj else None - channel_threshold_values = sfpd_obj.parse_channel_threshold_values( - dom_thres_raw, 0) - channel_threshold_data = channel_threshold_values.get('data') - if channel_threshold_data: - transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] - transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] - transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] - transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] - transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" - transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" - transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" - transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" - transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] - transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] - transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] - transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] - - for key in transceiver_dom_threshold_dict: - transceiver_dom_threshold_dict[key] = self._convert_string_to_num( - transceiver_dom_threshold_dict[key]) - - return transceiver_dom_threshold_dict + return os.system(self.HOST_CHK_CMD) == 0 def get_reset_status(self): """ @@ -651,7 +88,7 @@ def get_reset_status(self): Returns: A Boolean, True if reset enabled, False if disabled """ - if self.port_num < 53: # non-QSFP ports don't support it. + if self.port_num < 53: #Copper port and sfp ports aren't supported. return False reset_path="{}{}{}".format(CPLD_I2C_PATH , "module_reset_" , str(self.port_num)) @@ -660,7 +97,7 @@ def get_reset_status(self): if val is not None: return int(val, 10) == 1 else: - return False + return False # CPLD port doesn't support this feature def get_rx_los(self): """ @@ -669,34 +106,29 @@ def get_rx_los(self): A Boolean, True if SFP has RX LOS, False if not. Note : RX LOS status is latched until a call to get_rx_los or a reset. """ - rx_los = False + rx_los = [False] if self.port_num < 49: #Copper port, no sysfs - return False + return [False] if self.port_num < 53: - rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num) + rx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_rx_los_', self.port_num) rx_los=self._api_helper.read_txt_file(rx_path) - if rx_los is None: - return False - #status_control_raw = self.__read_eeprom_specific_bytes( - # SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) - #if status_control_raw: - # data = int(status_control_raw[0], 16) - # rx_los = (sffbase().test_bit(data, 1) != 0) - + if rx_los is not None: + if rx_los == '1': + return [True] + else: + return [False] + else: + return [False] else: - rx_los_list = [] - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) if self.get_presence() else None - if dom_channel_monitor_raw is not None: - rx_los_data = int(dom_channel_monitor_raw[0], 16) - rx_los_list.append(rx_los_data & 0x01 != 0) - rx_los_list.append(rx_los_data & 0x02 != 0) - rx_los_list.append(rx_los_data & 0x04 != 0) - rx_los_list.append(rx_los_data & 0x08 != 0) - rx_los = rx_los_list[0] and rx_los_list[1] and rx_los_list[2] and rx_los_list[3] - return rx_los + api = self.get_xcvr_api() + if api is not None: + rx_los = api.get_rx_los() + if isinstance(rx_los, list) and "N/A" in rx_los: + return [False for _ in rx_los] + return rx_los + return None def get_tx_fault(self): """ @@ -705,33 +137,28 @@ def get_tx_fault(self): A Boolean, True if SFP has TX fault, False if not Note : TX fault status is lached until a call to get_tx_fault or a reset. """ - tx_fault = False + tx_fault = [False] if self.port_num < 49: #Copper port, no sysfs - return False + return [False] if self.port_num < 53: - tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num) + tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_fault_', self.port_num) tx_fault=self._api_helper.read_txt_file(tx_path) - if tx_fault is None: - return False - #status_control_raw = self.__read_eeprom_specific_bytes( - # SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) - #if status_control_raw: - # data = int(status_control_raw[0], 16) - # tx_fault = (sffbase().test_bit(data, 2) != 0) + if tx_fault is not None: + if tx_fault == '1': + return [True] + else: + return [False] + else: + return [False] else: - tx_fault_list = [] - dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( - QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) if self.get_presence() else None - if dom_channel_monitor_raw is not None: - tx_fault_data = int(dom_channel_monitor_raw[0], 16) - tx_fault_list.append(tx_fault_data & 0x01 != 0) - tx_fault_list.append(tx_fault_data & 0x02 != 0) - tx_fault_list.append(tx_fault_data & 0x04 != 0) - tx_fault_list.append(tx_fault_data & 0x08 != 0) - tx_fault = tx_fault_list[0] and tx_fault_list[1] and tx_fault_list[2] and tx_fault_list[3] - - return tx_fault + api = self.get_xcvr_api() + if api is not None: + tx_fault = api.get_tx_fault() + if isinstance(tx_fault, list) and "N/A" in tx_fault: + return [False for _ in tx_fault] + return tx_fault + return None def get_tx_disable(self): """ @@ -742,70 +169,19 @@ def get_tx_disable(self): if self.port_num < 49: #Copper port, no sysfs return False - if self.port_num < 53: - tx_disable = False + if self.port_num < 53: + tx_disable = False tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) tx_disable=self._api_helper.read_txt_file(tx_path) - - - #status_control_raw = self.__read_eeprom_specific_bytes( - # SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) - #if status_control_raw: - # data = int(status_control_raw[0], 16) - # tx_disable_hard = (sffbase().test_bit( - # data, SFP_TX_DISABLE_HARD_BIT) != 0) - # tx_disable_soft = (sffbase().test_bit( - # data, SFP_TX_DISABLE_SOFT_BIT) != 0) - # tx_disable = tx_disable_hard | tx_disable_soft if tx_disable is not None: - return tx_disable + return tx_disable else: return False else: - tx_disable_list = [] - - sfpd_obj = sff8436Dom() - if sfpd_obj is None: - return False - - dom_control_raw = self.__read_eeprom_specific_bytes( - QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None - if dom_control_raw is not None: - dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) - tx_disable_list.append( - 'On' == dom_control_data['data']['TX1Disable']['value']) - tx_disable_list.append( - 'On' == dom_control_data['data']['TX2Disable']['value']) - tx_disable_list.append( - 'On' == dom_control_data['data']['TX3Disable']['value']) - tx_disable_list.append( - 'On' == dom_control_data['data']['TX4Disable']['value']) - - return tx_disable_list - - def get_tx_disable_channel(self): - """ - Retrieves the TX disabled channels in this SFP - Returns: - A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent - TX channels which have been disabled in this SFP. - As an example, a returned value of 0x5 indicates that channel 0 - and channel 2 have been disabled. - """ - if self.port_num < 53: - # SFP doesn't support this feature - return False - else: - tx_disable_list = self.get_tx_disable() - if tx_disable_list is None: - return 0 - tx_disabled = 0 - for i in range(len(tx_disable_list)): - if tx_disable_list[i]: - tx_disabled |= 1 << i - return tx_disabled + api = self.get_xcvr_api() + return api.get_tx_disable() if api is not None else None def get_lpmode(self): """ @@ -813,7 +189,7 @@ def get_lpmode(self): Returns: A Boolean, True if lpmode is enabled, False if disabled """ - if self.port_num < 53: + if self.port_num < 53: # SFP doesn't support this feature return False else: @@ -821,124 +197,14 @@ def get_lpmode(self): power_override = self.get_power_override() return power_set and power_override - - def get_power_set(self): - - if self.port_num < 53: + def get_power_set(self): + if self.port_num < 53: # SFP doesn't support this feature return False else: - power_set = False - - sfpd_obj = sff8436Dom() - if sfpd_obj is None: - return False - - dom_control_raw = self.__read_eeprom_specific_bytes( - QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None - if dom_control_raw is not None: - dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) - power_set = ( - 'On' == dom_control_data['data']['PowerSet']['value']) - - return power_set - - def get_power_override(self): - """ - Retrieves the power-override status of this SFP - Returns: - A Boolean, True if power-override is enabled, False if disabled - """ - if self.port_num < 53: - return False # SFP doesn't support this feature - else: - power_override = False - - - sfpd_obj = sff8436Dom() - if sfpd_obj is None: - return False - - dom_control_raw = self.__read_eeprom_specific_bytes( - QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) if self.get_presence() else None - if dom_control_raw is not None: - dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) - power_override = ( - 'On' == dom_control_data['data']['PowerOverride']['value']) - - return power_override - - def get_temperature(self): - """ - Retrieves the temperature of this SFP - Returns: - An integer number of current temperature in Celsius - """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() - return transceiver_dom_info_dict.get("temperature", "N/A") - - def get_voltage(self): - """ - Retrieves the supply voltage of this SFP - Returns: - An integer number of supply voltage in mV - """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() - return transceiver_dom_info_dict.get("voltage", "N/A") - - def get_tx_bias(self): - """ - Retrieves the TX bias current of this SFP - Returns: - A list of four integer numbers, representing TX bias in mA - for channel 0 to channel 4. - Ex. ['110.09', '111.12', '108.21', '112.09'] - """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() + api = self.get_xcvr_api() + return api.get_power_set() if api is not None else None - tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") - if self.port_num < 53: - return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] - - tx2_bs = transceiver_dom_info_dict.get("tx2bias", "N/A") - tx3_bs = transceiver_dom_info_dict.get("tx3bias", "N/A") - tx4_bs = transceiver_dom_info_dict.get("tx4bias", "N/A") - return [tx1_bs, tx2_bs, tx3_bs, tx4_bs] if transceiver_dom_info_dict else [] - - def get_rx_power(self): - """ - Retrieves the received optical power for this SFP - Returns: - A list of four integer numbers, representing received optical - power in mW for channel 0 to channel 4. - Ex. ['1.77', '1.71', '1.68', '1.70'] - """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() - - rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") - if self.port_num < 53: - return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] - rx2_pw = transceiver_dom_info_dict.get("rx2power", "N/A") - rx3_pw = transceiver_dom_info_dict.get("rx3power", "N/A") - rx4_pw = transceiver_dom_info_dict.get("rx4power", "N/A") - return [rx1_pw, rx2_pw, rx3_pw, rx4_pw] if transceiver_dom_info_dict else [] - - def get_tx_power(self): - """ - Retrieves the TX power of this SFP - Returns: - A list of four integer numbers, representing TX power in mW - for channel 0 to channel 4. - Ex. ['1.86', '1.86', '1.86', '1.86'] - """ - transceiver_dom_info_dict = self.get_transceiver_bulk_status() - tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") - if self.port_num < 53: - return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] - tx2_pw = transceiver_dom_info_dict.get("tx2power", "N/A") - tx3_pw = transceiver_dom_info_dict.get("tx3power", "N/A") - tx4_pw = transceiver_dom_info_dict.get("tx4power", "N/A") - return [tx1_pw, tx2_pw, tx3_pw, tx4_pw] def reset(self): """ @@ -947,7 +213,7 @@ def reset(self): A boolean, True if successful, False if not """ # Check for invalid port_num - if self.port_num < 53: # non-QSFP ports don't support it. + if self.port_num < 49: #Copper port, no sysfs return False reset_path = "{}{}{}".format(CPLD_I2C_PATH, 'module_reset_', self.port_num) @@ -974,8 +240,8 @@ def tx_disable(self, tx_disable): return False if self.port_num < 53: - tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) - ret = self.__write_txt_file(tx_path, 1 if tx_disable else 0) + tx_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_tx_disable_', self.port_num) + ret = self._api_helper.write_txt_file(tx_path, 1 if tx_disable else 0) if ret is not None: time.sleep(0.01) return ret @@ -985,78 +251,8 @@ def tx_disable(self, tx_disable): else: if not self.get_presence(): return False - sysfsfile_eeprom = None - try: - tx_disable_ctl = 0xf if tx_disable else 0x0 - buffer = create_string_buffer(1) - if sys.version_info[0] >= 3: - buffer[0] = tx_disable_ctl - else: - buffer[0] = chr(tx_disable_ctl) - # Write to eeprom - sysfsfile_eeprom = open( - self.port_to_eeprom_mapping[self.port_num], "r+b") - sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) - sysfsfile_eeprom.write(buffer[0]) - except IOError as e: - print ('Error: unable to open file: ',str(e)) - return False - finally: - if sysfsfile_eeprom is not None: - sysfsfile_eeprom.close() - time.sleep(0.01) - return True - - def tx_disable_channel(self, channel, disable): - """ - Sets the tx_disable for specified SFP channels - Args: - channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, - e.g. 0x5 for channel 0 and channel 2. - disable : A boolean, True to disable TX channels specified in channel, - False to enable - Returns: - A boolean, True if successful, False if not - """ - - if self.port_num < 53: - return False # SFP doesn't support this feature - else: - if not self.get_presence(): - return False - - sysfsfile_eeprom = None - try: - channel_state = self.get_tx_disable_channel() - - for i in range(4): - channel_mask = (1 << i) - if not (channel & channel_mask): - continue - - if disable: - channel_state |= channel_mask - else: - channel_state &= ~channel_mask - - buffer = create_string_buffer(1) - if sys.version_info[0] >= 3: - buffer[0] = channel_state - else: - buffer[0] = chr(channel_state) - # Write to eeprom - sysfsfile_eeprom = open( - self.port_to_eeprom_mapping[self.port_num], "r+b") - sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) - sysfsfile_eeprom.write(buffer[0]) - except IOError as e: - print ('Error: unable to open file: ', str(e)) - return False - finally: - if sysfsfile_eeprom is not None: - sysfsfile_eeprom.close() - time.sleep(0.01) - return True + api = self.get_xcvr_api() + return api.tx_disable(tx_disable) if api is not None else None def set_lpmode(self, lpmode): """ @@ -1070,12 +266,23 @@ def set_lpmode(self, lpmode): if self.port_num < 53: return False # SFP doesn't support this feature else: + ''' + use power override to control lpmode + ''' + if not self.get_presence(): + return False + api = self.get_xcvr_api() + if api is None: + return False + if api.get_lpmode_support() == False: + logger.log_notice("The transceiver of port {} doesn't support to set low power mode.". format(self.port_num)) + return True if lpmode is True: - self.set_power_override(True, True) + ret = api.set_power_override(True, True) else: - self.set_power_override(False, False) + ret = api.set_power_override(True, False) - return True + return ret def set_power_override(self, power_override, power_set): """ @@ -1099,24 +306,8 @@ def set_power_override(self, power_override, power_set): else: if not self.get_presence(): return False - try: - power_override_bit = (1 << 0) if power_override else 0 - power_set_bit = (1 << 1) if power_set else (1 << 3) - - buffer = create_string_buffer(1) - if sys.version_info[0] >= 3: - buffer[0] = (power_override_bit | power_set_bit) - else: - buffer[0] = chr(power_override_bit | power_set_bit) - # Write to eeprom - with open(self.port_to_eeprom_mapping[self.port_num], "r+b") as fd: - fd.seek(QSFP_POWEROVERRIDE_OFFSET) - fd.write(buffer[0]) - time.sleep(0.01) - except Exception: - print ('Error: unable to open file: ', str(e)) - return False - return True + api = self.get_xcvr_api() + return api.set_power_override(power_override, power_set) if api is not None else None def get_name(self): """ @@ -1125,9 +316,9 @@ def get_name(self): string: The name of the device """ sfputil_helper = SfpUtilHelper() - sfputil_helper.read_porttab_mappings( - self.__get_path_to_port_config_file()) - name = sfputil_helper.logical[self.index] or "Unknown" + port_config_file_path = device_info.get_path_to_port_config_file() + sfputil_helper.read_porttab_mappings(port_config_file_path) + name = sfputil_helper.logical[self.port_num - 1] or "Unknown" return name def get_presence(self): @@ -1139,11 +330,11 @@ def get_presence(self): if self.port_num < 49: #Copper port, no sysfs return False - present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num) + present_path = "{}{}{}".format(CPLD_I2C_PATH, '/module_present_', self.port_num) val=self._api_helper.read_txt_file(present_path) if val is not None: return int(val, 10)==1 - else: + else: return False def get_model(self): @@ -1170,7 +361,7 @@ def get_status(self): Returns: A boolean value, True if device is operating properly, False if not """ - return self.get_presence() and self.get_transceiver_bulk_status() + return self.get_presence() and not self.get_reset_status() def get_position_in_parent(self): """ @@ -1188,3 +379,150 @@ def is_replaceable(self): bool: True if it is replaceable. """ return True + + def __validate_eeprom_sfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(0, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + checksum_test = 0 + eeprom_raw = self.read_eeprom(384, 96) + if eeprom_raw is None: + return None + + for i in range(0, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + return True + + def __validate_eeprom_qsfp(self): + checksum_test = 0 + eeprom_raw = self.read_eeprom(128, 96) + if eeprom_raw is None: + return None + + for i in range(0, 63): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[63]: + return False + + checksum_test = 0 + for i in range(64, 95): + checksum_test = (checksum_test + eeprom_raw[i]) & 0xFF + else: + if checksum_test != eeprom_raw[95]: + return False + + api = self.get_xcvr_api() + if api is None: + return False + + if api.is_flat_memory(): + return True + + return True + + def validate_eeprom(self): + id_byte_raw = self.read_eeprom(0, 1) + if id_byte_raw is None: + return None + + id = id_byte_raw[0] + if id in self.QSFP_TYPE_CODE_LIST: + return self.__validate_eeprom_qsfp() + elif id in self.SFP_TYPE_CODE_LIST: + return self.__validate_eeprom_sfp() + else: + return False + + def validate_temperature(self): + temperature = self.get_temperature() + if temperature is None: + return None + + threshold_dict = self.get_transceiver_threshold_info() + if threshold_dict is None: + return None + + if isinstance(temperature, float) is not True: + return True + + if isinstance(threshold_dict['temphighalarm'], float) is not True: + return True + + return threshold_dict['temphighalarm'] > temperature + + def __get_error_description(self): + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + + err_stat = self.SFP_STATUS_BIT_INSERTED + + status = self.validate_eeprom() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_BAD_EEPROM) + + status = self.validate_temperature() + if status is not True: + err_stat = (err_stat | self.SFP_ERROR_BIT_HIGH_TEMP) + + if err_stat is self.SFP_STATUS_BIT_INSERTED: + return self.SFP_STATUS_OK + else: + err_desc = '' + cnt = 0 + for key in self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT: + if (err_stat & key) != 0: + if cnt > 0: + err_desc = err_desc + "|" + cnt = cnt + 1 + err_desc = err_desc + self.SFP_ERROR_BIT_TO_DESCRIPTION_DICT[key] + + return err_desc + + def get_error_description(self): + """ + Retrives the error descriptions of the SFP module + + Returns: + String that represents the current error descriptions of vendor specific errors + In case there are multiple errors, they should be joined by '|', + like: "Bad EEPROM|Unsupported cable" + """ + if self.port_num < 49: + # RJ45 doesn't support this feature + return None + else: + api = self.get_xcvr_api() + if api is not None: + try: + return api.get_error_description() + except NotImplementedError: + return self.__get_error_description() + else: + return self.__get_error_description() diff --git a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py index 7a453c594f..04a7145104 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py +++ b/device/accton/x86_64-accton_as4630_54te-r0/sonic_platform/thermal.py @@ -12,56 +12,189 @@ try: from sonic_platform_base.thermal_base import ThermalBase + from .helper import DeviceThreshold except ImportError as e: raise ImportError(str(e) + "- required module not found") +PSU_I2C_PATH = "/sys/bus/i2c/devices/{}-00{}/" +PSU_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "58" + }, + 1: { + "num": 11, + "addr": "59" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 10, + "addr": "50" + }, + 1: { + "num": 11, + "addr": "51" + }, +} + +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(ThermalBase): """Platform-specific Thermal class""" THERMAL_NAME_LIST = [] + PSU_THERMAL_NAME_LIST = [] SYSFS_PATH = "/sys/bus/i2c/devices" + CPU_SYSFS_PATH = "/sys/devices/platform" - def __init__(self, thermal_index=0): - self.THERMAL_NAME_LIST = [] - self.SYSFS_PATH = "/sys/bus/i2c/devices" + def __init__(self, thermal_index=0, is_psu=False, psu_index=0): self.index = thermal_index + self.is_psu = is_psu + self.psu_index = psu_index + self.min_temperature = None + self.max_temperature = None + + if self.is_psu: + psu_i2c_bus = PSU_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_I2C_MAPPING[psu_index]["addr"] + self.psu_hwmon_path = PSU_I2C_PATH.format(psu_i2c_bus, + psu_i2c_addr) + psu_i2c_bus = PSU_CPLD_I2C_MAPPING[psu_index]["num"] + psu_i2c_addr = PSU_CPLD_I2C_MAPPING[psu_index]["addr"] + self.cpld_path = PSU_I2C_PATH.format(psu_i2c_bus, psu_i2c_addr) # Add thermal name - self.THERMAL_NAME_LIST.append("Temp sensor 1") - self.THERMAL_NAME_LIST.append("Temp sensor 2") - self.THERMAL_NAME_LIST.append("Temp sensor 3") + self.THERMAL_NAME_LIST.append("MB_temp(0x48)") + self.THERMAL_NAME_LIST.append("CB_temp(0x4B)") + self.THERMAL_NAME_LIST.append("FB_temp(0x4A)") + self.THERMAL_NAME_LIST.append("CPU_Package_temp") + self.THERMAL_NAME_LIST.append("CPU_Core_0_temp") + self.THERMAL_NAME_LIST.append("CPU_Core_1_temp") + self.THERMAL_NAME_LIST.append("CPU_Core_2_temp") + self.THERMAL_NAME_LIST.append("CPU_Core_3_temp") + self.PSU_THERMAL_NAME_LIST.append("PSU-1 temp sensor 1") + self.PSU_THERMAL_NAME_LIST.append("PSU-2 temp sensor 1") + + # Threshold Configuration + self.__conf = DeviceThreshold(self.get_name()) + # Default threshold. + self.__default_threshold = DEFAULT_THRESHOLD[self.get_name()] # Set hwmon path i2c_path = { - 0: "14-0048/hwmon/hwmon*/", - 1: "24-004b/hwmon/hwmon*/", - 2: "25-004a/hwmon/hwmon*/" + 0: {"hwmon_path":"14-0048/hwmon/hwmon*/", "ss_index":1}, + 1: {"hwmon_path":"24-004b/hwmon/hwmon*/", "ss_index":1}, + 2: {"hwmon_path":"25-004a/hwmon/hwmon*/", "ss_index":1}, + 3: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":1}, + 4: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":4}, + 5: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":8}, + 6: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":10}, + 7: {"hwmon_path":"coretemp.0/hwmon/hwmon*/", "ss_index":14} }.get(self.index, None) - self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path) + self.is_cpu = False + if self.index in range(3,8): + self.is_cpu = True + self.hwmon_path = "{}/{}".format(self.CPU_SYSFS_PATH, i2c_path["hwmon_path"]) + else: + self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path["hwmon_path"]) self.ss_key = self.THERMAL_NAME_LIST[self.index] - self.ss_index = 1 + self.ss_index = i2c_path["ss_index"] def __read_txt_file(self, file_path): for filename in glob.glob(file_path): try: - with open(filename, 'r') as fd: - data =fd.readline().rstrip() - return data + with open(filename, 'r') as fd: + data =fd.readline().strip() + if len(data) > 0: + return data except IOError as e: pass return None def __get_temp(self, temp_file): - temp_file_path = os.path.join(self.hwmon_path, temp_file) + if not self.is_psu: + temp_file_path = os.path.join(self.hwmon_path, temp_file) + else: + temp_file_path = temp_file raw_temp = self.__read_txt_file(temp_file_path) if raw_temp is not None: return float(raw_temp)/1000 else: - return 0 + return 0 def __set_threshold(self, file_name, temperature): + if self.is_psu: + return True temp_file_path = os.path.join(self.hwmon_path, file_name) for filename in glob.glob(temp_file_path): try: @@ -79,41 +212,153 @@ def get_temperature(self): A float number of current temperature in Celsius up to nearest thousandth of one degree Celsius, e.g. 30.125 """ - temp_file = "temp{}_input".format(self.ss_index) - return self.__get_temp(temp_file) + if not self.is_psu: + temp_file = "temp{}_input".format(self.ss_index) + else: + temp_file = self.psu_hwmon_path + "psu_temp1_input" - def get_high_threshold(self): - """ - Retrieves the high threshold temperature of thermal - Returns: - A float number, the high threshold temperature of thermal in Celsius - up to nearest thousandth of one degree Celsius, e.g. 30.125 - """ - temp_file = "temp{}_max".format(self.ss_index) - return self.__get_temp(temp_file) + current = self.__get_temp(temp_file) + + 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): - """ - Sets the high threshold temperature of thermal - Args : - temperature: A float number up to nearest thousandth of one degree Celsius, - e.g. 30.125 - Returns: - A boolean, True if threshold is set successfully, False if not - """ - temp_file = "temp{}_max".format(self.ss_index) - temperature = temperature *1000 - self.__set_threshold(temp_file, 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) + + raise NotImplementedError + + 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) + + raise NotImplementedError + + 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_name(self): """ Retrieves the name of the thermal device Returns: string: The name of the thermal device """ - return self.THERMAL_NAME_LIST[self.index] + if self.is_psu: + return self.PSU_THERMAL_NAME_LIST[self.psu_index] + else: + return self.THERMAL_NAME_LIST[self.index] def get_presence(self): """ @@ -121,6 +366,15 @@ def get_presence(self): Returns: bool: True if Thermal is present, False if not """ + if self.is_cpu: + return True + + if self.is_psu: + val = self.__read_txt_file(self.cpld_path + "psu_present") + if val is not None: + return int(val, 10) == 1 + else: + return False temp_file = "temp{}_input".format(self.ss_index) temp_file_path = os.path.join(self.hwmon_path, temp_file) raw_txt = self.__read_txt_file(temp_file_path) @@ -135,11 +389,78 @@ def get_status(self): Returns: A boolean value, True if device is operating properly, False if not """ + if self.is_cpu: + return True + + if self.is_psu: + temp_file = self.psu_hwmon_path + "psu_temp_fault" + psu_temp_fault = self.__read_txt_file(temp_file) + if psu_temp_fault is None: + psu_temp_fault = '1' + return self.get_presence() and (not int(psu_temp_fault)) file_str = "temp{}_input".format(self.ss_index) file_path = os.path.join(self.hwmon_path, file_str) raw_txt = self.__read_txt_file(file_path) if raw_txt is None: return False - else: + else: return int(raw_txt) != 0 + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + + return "N/A" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return "N/A" + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. If the agent cannot determine the parent-relative position + for some reason, or if the associated value of entPhysicalContainedIn is '0', then the value '-1' is returned + Returns: + integer: The 1-based relative physical position in parent device or -1 if cannot determine the position + """ + return self.index+1 + + def is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.min_temperature is None: + self.get_temperature() + + return self.min_temperature + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + if self.max_temperature is None: + self.get_temperature() + + return self.max_temperature diff --git a/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json index 91a29558b4..97f9aa3053 100644 --- a/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json +++ b/device/accton/x86_64-accton_as4630_54te-r0/system_health_monitoring_config.json @@ -1,9 +1,7 @@ { "services_to_ignore": [], "devices_to_ignore": [ - "asic", - "psu.temperature" - + "asic" ], "user_defined_checkers": [], "polling_interval": 60, diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c index 3a99f19a9c..5813d89185 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/modules/x86-64-accton-as4630-54te-psu.c @@ -91,7 +91,6 @@ static ssize_t show_status(struct device *dev, struct device_attribute *da, struct as4630_54te_psu_data *data = as4630_54te_psu_update_device(dev); u8 status = 0; - //printk("data->status=0x%x, attr->index=%d,data->index=%d \n", data->status, attr->index, data->index); if (attr->index == PSU_PRESENT) { if(data->index==0) status = !( (data->status >> 5) & 0x1); @@ -102,7 +101,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); @@ -261,13 +260,14 @@ static struct as4630_54te_psu_data *as4630_54te_psu_update_device(struct device if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || !data->valid) { int status; + u8 serial_offset; int power_good = 0; dev_dbg(&client->dev, "Starting as4630_54te update\n"); /* Read psu status */ status = as4630_54te_cpld_read(0x60, 0x22); - //printk("status=0x%x in %s\n", status, __FUNCTION__); + if (status < 0) { dev_dbg(&client->dev, "cpld reg 0x60 err %d\n", status); } @@ -278,29 +278,49 @@ static struct as4630_54te_psu_data *as4630_54te_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); - + if(data->index==0) + power_good = ( (data->status >> 6) & 0x1); + else + power_good = ( (data->status >> 2) & 0x1); + if (power_good) { status = as4630_54te_psu_read_block(client, 0x20, data->model_name, - ARRAY_SIZE(data->model_name)-1); + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { data->model_name[0] = '\0'; dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); - printk("unable to read model name from (0x%x)\n", client->addr); } else { + data->model_name[8] = '-'; data->model_name[ARRAY_SIZE(data->model_name)-1] = '\0'; - } - /* Read from offset 0x2e ~ 0x3d (16 bytes) */ - status = as4630_54te_psu_read_block(client, 0x35,data->serial_number, MAX_SERIAL_NUMBER); + if(!strncmp(data->model_name, "YM-1151D", strlen("YM-1151D"))) + { + if (!strncmp(data->model_name, "YM-1151D-A03R", strlen("YM-1151D-A03R"))) + { + data->model_name[strlen("YM-1151D-A03R")] = '\0'; + serial_offset = 0x2E; /* YM-1151D-A03R, F2B dir */ + } + else + { + data->model_name[strlen("YM-1151D-A02R")] = '\0'; + serial_offset = 0x35; /* YM-1151D-A02R, B2F dir */ + } + } + else + serial_offset = 0x2E; + + /* Read from offset 0x2e ~ 0x3f (16 bytes) */ + status = as4630_54te_psu_read_block(client, serial_offset, 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(0x2e)\n", client->addr); - printk("unable to read model name from (0x%x) offset(0x2e)\n", client->addr); } + data->serial_number[MAX_SERIAL_NUMBER-1]='\0'; + } data->last_updated = jiffies; diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service index 587e6a1caf..b0c5fe6a78 100644 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/service/as4630-54te-platform-monitor.service @@ -1,6 +1,6 @@ [Unit] Description=Accton AS4630-54TE Platform Monitoring service -Before=pmon.service +Before=pmon.service system-health.service After=sysinit.target DefaultDependencies=no diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/udev/70-persistent-net.rules b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/udev/70-persistent-net.rules new file mode 100644 index 0000000000..11ca59a6ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/udev/70-persistent-net.rules @@ -0,0 +1,3 @@ +ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:08:00.0", NAME:="eth0" +ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:06:00.1", NAME:="eth1" +ACTION=="add", SUBSYSTEM=="net", DRIVERS=="ixgbe", KERNELS=="0000:06:00.0", NAME:="eth3" \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py index aa5076c2ca..005d9d6b1e 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/accton_as4630_54te_monitor.py @@ -87,6 +87,9 @@ class device_monitor(object): def __init__(self, log_file, log_level): """Needs a logger and a logger level.""" + + self.thermal = ThermalUtil() + self.fan = FanUtil() # set up logging to file logging.basicConfig( filename=log_file, @@ -138,8 +141,8 @@ def manage_fans(self): LEVEL_TEMP_CRITICAL: [100, 16, 240000, 300000], } temp = [0, 0, 0] - thermal = ThermalUtil() - fan = FanUtil() + thermal = self.thermal + fan = self.fan ori_duty_cycle = fan.get_fan_duty_cycle() new_duty_cycle = 0 diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh index 82f4d5e021..cdc3c04fcc 100755 --- a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/handle_mgmt_interface.sh @@ -1,8 +1,7 @@ #!/bin/bash -#Due to the hardware design, as4630-54te 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 \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/restart_ixgbe.sh b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/restart_ixgbe.sh new file mode 100755 index 0000000000..57c14e5ba0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as4630-54te/utils/restart_ixgbe.sh @@ -0,0 +1,8 @@ +#!/bin/bash + +/etc/init.d/netfilter-persistent stop +modprobe -r ixgbe +udevadm control --reload-rules +udevadm trigger +modprobe ixgbe +/etc/init.d/netfilter-persistent start diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index c47aa3b3e6..cfbfeaed78 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -27,6 +27,7 @@ MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service CONF_DIR := conf +UDEV_DIR := udev %: dh $@ --with systemd,python3 --buildsystem=pybuild @@ -70,9 +71,15 @@ binary-indep: dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} usr/local/bin; \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} lib/systemd/system; \ + if [ -d $(MOD_SRC_DIR)/$${mod}/$(UDEV_DIR) ]; then \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} etc/udev/rules.d; \ + fi; \ cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ + if [ -f $(MOD_SRC_DIR)/$${mod}/$(UDEV_DIR)/* ]; then \ + cp $(MOD_SRC_DIR)/$${mod}/$(UDEV_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/etc/udev/rules.d/; \ + fi; \ $(PYTHON3) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ done) # Resuming debhelper scripts