diff --git a/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini new file mode 100644 index 000000000000..2e128a4fde65 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/port_config.ini @@ -0,0 +1,55 @@ +# name lanes alias index speed +Ethernet0 2 tenGigE1 1 10000 +Ethernet1 1 tenGigE2 2 10000 +Ethernet2 4 tenGigE3 3 10000 +Ethernet3 3 tenGigE4 4 10000 +Ethernet4 6 tenGigE5 5 10000 +Ethernet5 5 tenGigE6 6 10000 +Ethernet6 8 tenGigE7 7 10000 +Ethernet7 7 tenGigE8 8 10000 +Ethernet8 10 tenGigE9 9 10000 +Ethernet9 9 tenGigE10 10 10000 +Ethernet10 12 tenGigE11 11 10000 +Ethernet11 11 tenGigE12 12 10000 +Ethernet12 14 tenGigE13 13 10000 +Ethernet13 13 tenGigE14 14 10000 +Ethernet14 16 tenGigE15 15 10000 +Ethernet15 15 tenGigE16 16 10000 +Ethernet16 18 tenGigE17 17 10000 +Ethernet17 17 tenGigE18 18 10000 +Ethernet18 20 tenGigE19 19 10000 +Ethernet19 19 tenGigE20 20 10000 +Ethernet20 22 tenGigE21 21 10000 +Ethernet21 21 tenGigE22 22 10000 +Ethernet22 24 tenGigE23 23 10000 +Ethernet23 23 tenGigE24 24 10000 +Ethernet24 54 tenGigE25 25 10000 +Ethernet25 53 tenGigE26 26 10000 +Ethernet26 56 tenGigE27 27 10000 +Ethernet27 55 tenGigE28 28 10000 +Ethernet28 58 tenGigE29 29 10000 +Ethernet29 57 tenGigE30 30 10000 +Ethernet30 60 tenGigE31 31 10000 +Ethernet31 59 tenGigE32 32 10000 +Ethernet32 62 tenGigE33 33 10000 +Ethernet33 61 tenGigE34 34 10000 +Ethernet34 64 tenGigE35 35 10000 +Ethernet35 63 tenGigE36 36 10000 +Ethernet36 66 tenGigE37 37 10000 +Ethernet37 65 tenGigE38 38 10000 +Ethernet38 68 tenGigE39 39 10000 +Ethernet39 67 tenGigE40 40 10000 +Ethernet40 70 tenGigE41 41 10000 +Ethernet41 69 tenGigE42 42 10000 +Ethernet42 72 tenGigE43 43 10000 +Ethernet43 71 tenGigE44 44 10000 +Ethernet44 74 tenGigE45 45 10000 +Ethernet45 73 tenGigE46 46 10000 +Ethernet46 76 tenGigE47 47 10000 +Ethernet47 75 tenGigE48 48 10000 +Ethernet48 29,30,31,32 hundredGigE49 49 100000 +Ethernet52 33,34,35,36 hundredGigE50 53 100000 +Ethernet56 37,38,39,40 hundredGigE51 57 100000 +Ethernet60 41,42,43,44 hundredGigE52 61 100000 +Ethernet64 45,46,47,48 hundredGigE53 65 100000 +Ethernet68 49,50,51,52 hundredGigE54 69 100000 diff --git a/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/sai.profile b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/sai.profile new file mode 100644 index 000000000000..952c87a00eeb --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/etc/bcm/td3-as5835t-48x10G+6x100G.config.bcm diff --git a/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/td3-as5835t-48x10G+6x100G.config.bcm b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/td3-as5835t-48x10G+6x100G.config.bcm new file mode 100644 index 000000000000..4b73e8c29db3 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/Accton-AS5835-54T/td3-as5835t-48x10G+6x100G.config.bcm @@ -0,0 +1,515 @@ +#polarity/lanemap is using TH2 style. +core_clock_frequency=1525 +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=0x1FFFFFFFFFFFFFFFE + +parity_enable=0 +mem_cache_enable=0 + +l2_mem_entries=32768 +#l3_mem_entries=49152 +#fpem_mem_entries=16384 +l2xmsg_mode=1 + +#FC0 +dport_map_port_1=2 +dport_map_port_2=1 +dport_map_port_3=4 +dport_map_port_4=3 +portmap_1=1:10 +portmap_2=2:10 +portmap_3=3:10 +portmap_4=4:10 +#port_phy_addr_1=0x00 +#port_phy_addr_2=0x01 +#port_phy_addr_3=0x02 +#port_phy_addr_4=0x03 +phy_chain_rx_lane_map_physical{1.0}=0x0123 +phy_chain_rx_lane_map_physical{2.0}=0x0123 +phy_chain_rx_lane_map_physical{3.0}=0x0123 +phy_chain_rx_lane_map_physical{4.0}=0x0123 +phy_chain_tx_lane_map_physical{1.0}=0x0123 +phy_chain_tx_lane_map_physical{2.0}=0x0123 +phy_chain_tx_lane_map_physical{3.0}=0x0123 +phy_chain_tx_lane_map_physical{4.0}=0x0123 +phy_chain_rx_polarity_flip_physical{1.0}=0x1 +phy_chain_rx_polarity_flip_physical{2.0}=0x1 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 +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 + +#FC1 +dport_map_port_5=6 +dport_map_port_6=5 +dport_map_port_7=8 +dport_map_port_8=7 +portmap_5=5:10 +portmap_6=6:10 +portmap_7=7:10 +portmap_8=8:10 +#port_phy_addr_5=0x04 +#port_phy_addr_6=0x05 +#port_phy_addr_7=0x06 +#port_phy_addr_8=0x07 +phy_chain_rx_lane_map_physical{5.0}=0x0123 +phy_chain_rx_lane_map_physical{6.0}=0x0123 +phy_chain_rx_lane_map_physical{7.0}=0x0123 +phy_chain_rx_lane_map_physical{8.0}=0x0123 +phy_chain_tx_lane_map_physical{5.0}=0x0123 +phy_chain_tx_lane_map_physical{6.0}=0x0123 +phy_chain_tx_lane_map_physical{7.0}=0x0123 +phy_chain_tx_lane_map_physical{8.0}=0x0123 +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{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 + +#FC2 +dport_map_port_9=10 +dport_map_port_10=9 +dport_map_port_11=12 +dport_map_port_12=11 +portmap_9=9:10 +portmap_10=10:10 +portmap_11=11:10 +portmap_12=12:10 +#port_phy_addr_9=0x20 +#port_phy_addr_10=0x21 +#port_phy_addr_11=0x22 +#port_phy_addr_12=0x23 +phy_chain_rx_lane_map_physical{9.0}=0x0123 +phy_chain_rx_lane_map_physical{10.0}=0x0123 +phy_chain_rx_lane_map_physical{11.0}=0x0123 +phy_chain_rx_lane_map_physical{12.0}=0x0123 +phy_chain_tx_lane_map_physical{9.0}=0x0123 +phy_chain_tx_lane_map_physical{10.0}=0x0123 +phy_chain_tx_lane_map_physical{11.0}=0x0123 +phy_chain_tx_lane_map_physical{12.0}=0x0123 +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_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 + +#FC3 +dport_map_port_13=14 +dport_map_port_14=13 +dport_map_port_15=16 +dport_map_port_16=15 +portmap_13=13:10 +portmap_14=14:10 +portmap_15=15:10 +portmap_16=16:10 +#port_phy_addr_13=0x24 +#port_phy_addr_14=0x25 +#port_phy_addr_15=0x26 +#port_phy_addr_16=0x27 +phy_chain_rx_lane_map_physical{13.0}=0x0123 +phy_chain_rx_lane_map_physical{14.0}=0x0123 +phy_chain_rx_lane_map_physical{15.0}=0x0123 +phy_chain_rx_lane_map_physical{16.0}=0x0123 +phy_chain_tx_lane_map_physical{13.0}=0x0123 +phy_chain_tx_lane_map_physical{14.0}=0x0123 +phy_chain_tx_lane_map_physical{15.0}=0x0123 +phy_chain_tx_lane_map_physical{16.0}=0x0123 +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{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 + +#FC4 +dport_map_port_17=18 +dport_map_port_18=17 +dport_map_port_19=20 +dport_map_port_20=19 +portmap_17=17:10 +portmap_18=18:10 +portmap_19=19:10 +portmap_20=20:10 +#port_phy_addr_17=0x40 +#port_phy_addr_18=0x41 +#port_phy_addr_19=0x42 +#port_phy_addr_20=0x43 +phy_chain_rx_lane_map_physical{17.0}=0x0123 +phy_chain_rx_lane_map_physical{18.0}=0x0123 +phy_chain_rx_lane_map_physical{19.0}=0x0123 +phy_chain_rx_lane_map_physical{20.0}=0x0123 +phy_chain_tx_lane_map_physical{17.0}=0x0123 +phy_chain_tx_lane_map_physical{18.0}=0x0123 +phy_chain_tx_lane_map_physical{19.0}=0x0123 +phy_chain_tx_lane_map_physical{20.0}=0x0123 +phy_chain_rx_polarity_flip_physical{17.0}=0x1 +phy_chain_rx_polarity_flip_physical{18.0}=0x1 +phy_chain_rx_polarity_flip_physical{19.0}=0x1 +phy_chain_rx_polarity_flip_physical{20.0}=0x1 +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 + +#FC5 +dport_map_port_21=22 +dport_map_port_22=21 +dport_map_port_23=24 +dport_map_port_24=23 +portmap_21=21:10 +portmap_22=22:10 +portmap_23=23:10 +portmap_24=24:10 +#port_phy_addr_21=0x44 +#port_phy_addr_22=0x45 +#port_phy_addr_23=0x46 +#port_phy_addr_24=0x47 +phy_chain_rx_lane_map_physical{21.0}=0x0123 +phy_chain_rx_lane_map_physical{22.0}=0x0123 +phy_chain_rx_lane_map_physical{23.0}=0x0123 +phy_chain_rx_lane_map_physical{24.0}=0x0123 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_tx_lane_map_physical{22.0}=0x0123 +phy_chain_tx_lane_map_physical{23.0}=0x0123 +phy_chain_tx_lane_map_physical{24.0}=0x0123 +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{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 + +#FC6 + +#FC7 +dport_map_port_25=50 +portmap_25=29:100:4 +phy_chain_rx_lane_map_physical{29.0}=0x1302 +phy_chain_rx_lane_map_physical{30.0}=0x1302 +phy_chain_rx_lane_map_physical{31.0}=0x1302 +phy_chain_rx_lane_map_physical{32.0}=0x1302 +phy_chain_tx_lane_map_physical{29.0}=0x2031 +phy_chain_tx_lane_map_physical{30.0}=0x2031 +phy_chain_tx_lane_map_physical{31.0}=0x2031 +phy_chain_tx_lane_map_physical{32.0}=0x2031 +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}=0x1 +phy_chain_tx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x1 +phy_chain_tx_polarity_flip_physical{31.0}=0x1 +phy_chain_tx_polarity_flip_physical{32.0}=0x1 + +#FC8 +dport_map_port_26=51 +portmap_26=33:100:4 +phy_chain_rx_lane_map_physical{33.0}=0x0123 +phy_chain_rx_lane_map_physical{34.0}=0x0123 +phy_chain_rx_lane_map_physical{35.0}=0x0123 +phy_chain_rx_lane_map_physical{36.0}=0x0123 +phy_chain_tx_lane_map_physical{33.0}=0x0123 +phy_chain_tx_lane_map_physical{34.0}=0x0123 +phy_chain_tx_lane_map_physical{35.0}=0x0123 +phy_chain_tx_lane_map_physical{36.0}=0x0123 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 +phy_chain_tx_polarity_flip_physical{33.0}=0x0 +phy_chain_tx_polarity_flip_physical{34.0}=0x0 +phy_chain_tx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 + +#FC9 +dport_map_port_27=49 +dport_map_port_28=52 +dport_map_port_29=53 +dport_map_port_30=54 +portmap_27=37:100:4 +phy_chain_rx_lane_map_physical{37.0}=0x1023 +phy_chain_rx_lane_map_physical{38.0}=0x1023 +phy_chain_rx_lane_map_physical{39.0}=0x1023 +phy_chain_rx_lane_map_physical{40.0}=0x1023 +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{37.0}=0x0 +phy_chain_rx_polarity_flip_physical{38.0}=0x1 +phy_chain_rx_polarity_flip_physical{39.0}=0x0 +phy_chain_rx_polarity_flip_physical{40.0}=0x0 +phy_chain_tx_polarity_flip_physical{37.0}=0x0 +phy_chain_tx_polarity_flip_physical{38.0}=0x1 +phy_chain_tx_polarity_flip_physical{39.0}=0x0 +phy_chain_tx_polarity_flip_physical{40.0}=0x0 + +#FC10 +dport_map_port_33=57 +portmap_33=41:100:4 +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_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_rx_polarity_flip_physical{41.0}=0x0 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x0 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 +phy_chain_tx_polarity_flip_physical{41.0}=0x1 +phy_chain_tx_polarity_flip_physical{42.0}=0x0 +phy_chain_tx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 + +#FC11 +dport_map_port_34=56 +portmap_34=45:100:4 +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{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{45.0}=0x0 +phy_chain_rx_polarity_flip_physical{46.0}=0x0 +phy_chain_rx_polarity_flip_physical{47.0}=0x0 +phy_chain_rx_polarity_flip_physical{48.0}=0x0 +phy_chain_tx_polarity_flip_physical{45.0}=0x0 +phy_chain_tx_polarity_flip_physical{46.0}=0x0 +phy_chain_tx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x0 + +#FC12 +dport_map_port_35=55 +dport_map_port_36=58 +dport_map_port_37=59 +dport_map_port_38=60 +portmap_35=49:100:4 +phy_chain_rx_lane_map_physical{49.0}=0x3210 +phy_chain_rx_lane_map_physical{50.0}=0x3210 +phy_chain_rx_lane_map_physical{51.0}=0x3210 +phy_chain_rx_lane_map_physical{52.0}=0x3210 +phy_chain_tx_lane_map_physical{49.0}=0x3210 +phy_chain_tx_lane_map_physical{50.0}=0x3210 +phy_chain_tx_lane_map_physical{51.0}=0x3210 +phy_chain_tx_lane_map_physical{52.0}=0x3210 +phy_chain_rx_polarity_flip_physical{49.0}=0x0 +phy_chain_rx_polarity_flip_physical{50.0}=0x0 +phy_chain_rx_polarity_flip_physical{51.0}=0x0 +phy_chain_rx_polarity_flip_physical{52.0}=0x0 +phy_chain_tx_polarity_flip_physical{49.0}=0x1 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x1 + +#FC13 +dport_map_port_39=26 +dport_map_port_40=25 +dport_map_port_41=28 +dport_map_port_42=27 +portmap_39=53:10 +portmap_40=54:10 +portmap_41=55:10 +portmap_42=56:10 +#port_phy_addr_39=0x60 +#port_phy_addr_40=0x61 +#port_phy_addr_41=0x62 +#port_phy_addr_42=0x63 +phy_chain_rx_lane_map_physical{53.0}=0x3120 +phy_chain_rx_lane_map_physical{54.0}=0x3120 +phy_chain_rx_lane_map_physical{55.0}=0x3120 +phy_chain_rx_lane_map_physical{56.0}=0x3120 +phy_chain_tx_lane_map_physical{53.0}=0x3102 +phy_chain_tx_lane_map_physical{54.0}=0x3102 +phy_chain_tx_lane_map_physical{55.0}=0x3102 +phy_chain_tx_lane_map_physical{56.0}=0x3102 +phy_chain_rx_polarity_flip_physical{53.0}=0x0 +phy_chain_rx_polarity_flip_physical{54.0}=0x1 +phy_chain_rx_polarity_flip_physical{55.0}=0x1 +phy_chain_rx_polarity_flip_physical{56.0}=0x0 +phy_chain_tx_polarity_flip_physical{53.0}=0x0 +phy_chain_tx_polarity_flip_physical{54.0}=0x1 +phy_chain_tx_polarity_flip_physical{55.0}=0x1 +phy_chain_tx_polarity_flip_physical{56.0}=0x0 + +#FC14 +dport_map_port_43=30 +dport_map_port_44=29 +dport_map_port_45=32 +dport_map_port_46=31 +portmap_43=57:10 +portmap_44=58:10 +portmap_45=59:10 +portmap_46=60:10 +#port_phy_addr_43=0x64 +#port_phy_addr_44=0x65 +#port_phy_addr_45=0x66 +#port_phy_addr_46=0x67 +phy_chain_rx_lane_map_physical{57.0}=0x3210 +phy_chain_rx_lane_map_physical{58.0}=0x3210 +phy_chain_rx_lane_map_physical{59.0}=0x3210 +phy_chain_rx_lane_map_physical{60.0}=0x3210 +phy_chain_tx_lane_map_physical{57.0}=0x3210 +phy_chain_tx_lane_map_physical{58.0}=0x3210 +phy_chain_tx_lane_map_physical{59.0}=0x3210 +phy_chain_tx_lane_map_physical{60.0}=0x3210 +phy_chain_rx_polarity_flip_physical{57.0}=0x1 +phy_chain_rx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x1 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 +phy_chain_tx_polarity_flip_physical{57.0}=0x0 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_tx_polarity_flip_physical{59.0}=0x0 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 + +#FC15 +dport_map_port_47=34 +dport_map_port_48=33 +dport_map_port_49=36 +dport_map_port_50=35 +portmap_47=61:10 +portmap_48=62:10 +portmap_49=63:10 +portmap_50=64:10 +#port_phy_addr_47=0x100 +#port_phy_addr_48=0x101 +#port_phy_addr_49=0x102 +#port_phy_addr_50=0x103 +phy_chain_rx_lane_map_physical{61.0}=0x3210 +phy_chain_rx_lane_map_physical{62.0}=0x3210 +phy_chain_rx_lane_map_physical{63.0}=0x3210 +phy_chain_rx_lane_map_physical{64.0}=0x3210 +phy_chain_tx_lane_map_physical{61.0}=0x3210 +phy_chain_tx_lane_map_physical{62.0}=0x3210 +phy_chain_tx_lane_map_physical{63.0}=0x3210 +phy_chain_tx_lane_map_physical{64.0}=0x3210 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_rx_polarity_flip_physical{62.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x1 +phy_chain_rx_polarity_flip_physical{64.0}=0x1 +phy_chain_tx_polarity_flip_physical{61.0}=0x0 +phy_chain_tx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x0 +phy_chain_tx_polarity_flip_physical{64.0}=0x0 + +#FC16 +dport_map_port_51=38 +dport_map_port_52=37 +dport_map_port_53=40 +dport_map_port_54=39 +portmap_51=65:10 +portmap_52=66:10 +portmap_53=67:10 +portmap_54=68:10 +#port_phy_addr_51=0x104 +#port_phy_addr_52=0x105 +#port_phy_addr_53=0x106 +#port_phy_addr_54=0x107 +phy_chain_rx_lane_map_physical{65.0}=0x3210 +phy_chain_rx_lane_map_physical{66.0}=0x3210 +phy_chain_rx_lane_map_physical{67.0}=0x3210 +phy_chain_rx_lane_map_physical{68.0}=0x3210 +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_tx_lane_map_physical{66.0}=0x3210 +phy_chain_tx_lane_map_physical{67.0}=0x3210 +phy_chain_tx_lane_map_physical{68.0}=0x3210 +phy_chain_rx_polarity_flip_physical{65.0}=0x0 +phy_chain_rx_polarity_flip_physical{66.0}=0x0 +phy_chain_rx_polarity_flip_physical{67.0}=0x0 +phy_chain_rx_polarity_flip_physical{68.0}=0x0 +phy_chain_tx_polarity_flip_physical{65.0}=0x0 +phy_chain_tx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x0 +phy_chain_tx_polarity_flip_physical{68.0}=0x0 + +#FC17 +dport_map_port_55=42 +dport_map_port_56=41 +dport_map_port_57=44 +dport_map_port_58=43 +portmap_55=69:10 +portmap_56=70:10 +portmap_57=71:10 +portmap_58=72:10 +#port_phy_addr_55=0x120 +#port_phy_addr_56=0x121 +#port_phy_addr_57=0x122 +#port_phy_addr_58=0x123 +phy_chain_rx_lane_map_physical{69.0}=0x3210 +phy_chain_rx_lane_map_physical{70.0}=0x3210 +phy_chain_rx_lane_map_physical{71.0}=0x3210 +phy_chain_rx_lane_map_physical{72.0}=0x3210 +phy_chain_tx_lane_map_physical{69.0}=0x3210 +phy_chain_tx_lane_map_physical{70.0}=0x3210 +phy_chain_tx_lane_map_physical{71.0}=0x3210 +phy_chain_tx_lane_map_physical{72.0}=0x3210 +phy_chain_rx_polarity_flip_physical{69.0}=0x0 +phy_chain_rx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{71.0}=0x0 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_tx_polarity_flip_physical{71.0}=0x0 +phy_chain_tx_polarity_flip_physical{72.0}=0x0 + +#FC18 +dport_map_port_59=46 +dport_map_port_60=45 +dport_map_port_61=48 +dport_map_port_62=47 +portmap_59=73:10 +portmap_60=74:10 +portmap_61=75:10 +portmap_62=76:10 +#port_phy_addr_59=0x124 +#port_phy_addr_60=0x125 +#port_phy_addr_61=0x126 +#port_phy_addr_62=0x127 +phy_chain_rx_lane_map_physical{73.0}=0x3210 +phy_chain_rx_lane_map_physical{74.0}=0x3210 +phy_chain_rx_lane_map_physical{75.0}=0x3210 +phy_chain_rx_lane_map_physical{76.0}=0x3210 +phy_chain_tx_lane_map_physical{73.0}=0x2031 +phy_chain_tx_lane_map_physical{74.0}=0x2031 +phy_chain_tx_lane_map_physical{75.0}=0x2031 +phy_chain_tx_lane_map_physical{76.0}=0x2031 +phy_chain_rx_polarity_flip_physical{73.0}=0x1 +phy_chain_rx_polarity_flip_physical{74.0}=0x1 +phy_chain_rx_polarity_flip_physical{75.0}=0x1 +phy_chain_rx_polarity_flip_physical{76.0}=0x1 +phy_chain_tx_polarity_flip_physical{73.0}=0x0 +phy_chain_tx_polarity_flip_physical{74.0}=0x1 +phy_chain_tx_polarity_flip_physical{75.0}=0x1 +phy_chain_tx_polarity_flip_physical{76.0}=0x0 + +#FC19 + +dport_map_port_64=64 +portmap_64=81:10:m +phy_chain_rx_polarity_flip_physical{81.0}=0x1 +phy_chain_tx_polarity_flip_physical{81.0}=0x1 + diff --git a/device/accton/x86_64-accton_as5835_54t-r0/default_sku b/device/accton/x86_64-accton_as5835_54t-r0/default_sku new file mode 100644 index 000000000000..d0bfc0f22e8d --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/default_sku @@ -0,0 +1 @@ +Accton-AS5835-54T t1 diff --git a/device/accton/x86_64-accton_as5835_54t-r0/installer.conf b/device/accton/x86_64-accton_as5835_54t-r0/installer.conf new file mode 100644 index 000000000000..925a32fc0c3a --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 diff --git a/device/accton/x86_64-accton_as5835_54t-r0/plugins/eeprom.py b/device/accton/x86_64-accton_as5835_54t-r0/plugins/eeprom.py new file mode 100644 index 000000000000..7681caafeef4 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/plugins/eeprom.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python + +try: + import exceptions + import binascii + import time + import optparse + import warnings + import os + import sys + from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + import subprocess +except ImportError, 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" + #Two i2c buses might get flipped order, check them both. + if not os.path.exists(self.eeprom_path): + self.eeprom_path = "/sys/bus/i2c/devices/0-0057/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/accton/x86_64-accton_as5835_54t-r0/plugins/psuutil.py b/device/accton/x86_64-accton_as5835_54t-r0/plugins/psuutil.py new file mode 100644 index 000000000000..c95bc27897dc --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/plugins/psuutil.py @@ -0,0 +1,61 @@ +#!/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 +# +############################################################################# + +import os.path + +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: "11-0050", + 2: "12-0053", + } + + 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_as5835_54t-r0/plugins/sfputil.py b/device/accton/x86_64-accton_as5835_54t-r0/plugins/sfputil.py new file mode 100644 index 000000000000..58ed8007a477 --- /dev/null +++ b/device/accton/x86_64-accton_as5835_54t-r0/plugins/sfputil.py @@ -0,0 +1,225 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + import string + 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)) + + +class SfpUtil(SfpUtilBase): + """Platform-specific SfpUtil class""" + + PORT_START = 49 + PORT_END = 72 + PORTS_IN_BLOCK = 72 + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 49: 28, #QSFP49 + 50: 28, + 51: 28, + 52: 28, + 53: 29, #QSFP50 + 54: 29, + 55: 29, + 56: 29, + 57: 26, #QSFP51 + 58: 26, + 59: 26, + 60: 26, + 61: 30, #QSFP52 + 62: 30, + 63: 30, + 64: 30, + 65: 31, #QSFP53 + 66: 31, + 67: 31, + 68: 31, + 69: 27, #QSFP54 + 70: 27, + 71: 27, + 72: 27, + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.PORT_START + + @property + def qsfp_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 = '/sys/bus/i2c/devices/{0}-0050/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]) + + SfpUtilBase.__init__(self) + + + # For port 49~54 are QSFP, here presumed they're all split to 4 lanes. + def get_cage_num(self, port_num): + cage_num = port_num + if (port_num >= self.PORT_START): + cage_num = (port_num - self.PORT_START)/4 + cage_num = cage_num + self.PORT_START + + return cage_num + + 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 + + cage_num = self.get_cage_num(port_num) + path = "/sys/bus/i2c/devices/3-0062/module_present_{0}" + port_ps = path.format(cage_num) + + try: + val_file = open(port_ps) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode_cpld(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + cage_num = self.get_cage_num(port_num) + path = "/sys/bus/i2c/devices/3-0062/module_lpmode_{0}" + lp_mode_path = path.format(cage_num) + + try: + val_file = open(lp_mode_path) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + # content is a string, either "0" or "1" + if content == "1": + return True + + return False + + def get_low_power_mode(self, port_num): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + if not self.get_presence(port_num): + return False + + try: + eeprom = None + + eeprom = open(self.port_to_eeprom_mapping[port_num], mode="rb", buffering=0) + eeprom.seek(93) + lpmode = ord(eeprom.read(1)) + + if not (lpmode & 0x1): # 'Power override' bit is 0 + return self.get_low_power_mode_cpld(port_num) + else: + if ((lpmode & 0x2) == 0x2): + return True # Low Power Mode if "Power set" bit is 1 + else: + return False # High Power Mode if "Power set" bit is 0 + 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): + if port_num < self.qsfp_port_start or port_num > self.qsfp_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 + regval = 0x3 if lpmode else 0x1 # 0x3:Low Power Mode, 0x1:High Power Mode + buffer = create_string_buffer(1) + buffer[0] = chr(regval) + + # Write to eeprom + eeprom = open(self.port_to_eeprom_mapping[port_num], mode="r+b", buffering=0) + 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): + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + cage_num = self.get_cage_num(port_num) + path = "/sys/bus/i2c/devices/3-0062/module_reset_{0}" + port_ps = path.format(cage_num) + try: + reg_file = open(port_ps, mode="w", buffering=0) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + #toggle reset + reg_file.seek(0) + reg_file.write('0') + time.sleep(1) + reg_file.seek(0) + reg_file.write('1') + reg_file.close() + + return True + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index 2a36bd3c568d..897845ab82d7 100755 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -28,6 +28,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(ACCTON_AS5812_54X_PLATFORM_MODULE) \ $(ACCTON_AS5835_54X_PLATFORM_MODULE) \ $(ACCTON_AS9716_32D_PLATFORM_MODULE) \ + $(ACCTON_AS5835_54T_PLATFORM_MODULE) \ $(INVENTEC_D7032Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7054Q28B_PLATFORM_MODULE) \ $(INVENTEC_D7264Q28B_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-accton.mk b/platform/broadcom/platform-modules-accton.mk index fa786b51d733..af8cb0fb4701 100755 --- a/platform/broadcom/platform-modules-accton.mk +++ b/platform/broadcom/platform-modules-accton.mk @@ -14,6 +14,7 @@ ACCTON_MINIPACK_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION = 1.1 ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION = 1.1 export ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION export ACCTON_AS5712_54X_PLATFORM_MODULE_VERSION @@ -29,6 +30,7 @@ export ACCTON_MINIPACK_PLATFORM_MODULE_VERSION export ACCTON_AS5812_54X_PLATFORM_MODULE_VERSION export ACCTON_AS5835_54X_PLATFORM_MODULE_VERSION export ACCTON_AS9716_32D_PLATFORM_MODULE_VERSION +export ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION ACCTON_AS7712_32X_PLATFORM_MODULE = sonic-platform-accton-as7712-32x_$(ACCTON_AS7712_32X_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_AS7712_32X_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton @@ -89,5 +91,8 @@ ACCTON_AS9716_32D_PLATFORM_MODULE = sonic-platform-accton-as9716-32d_$(ACCTON_AS $(ACCTON_AS9716_32D_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9716_32d-r0 $(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS9716_32D_PLATFORM_MODULE))) +ACCTON_AS5835_54T_PLATFORM_MODULE = sonic-platform-accton-as5835-54t_$(ACCTON_AS5835_54T_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS5835_54T_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as5835_54t-r0 +$(eval $(call add_extra_package,$(ACCTON_AS7712_32X_PLATFORM_MODULE),$(ACCTON_AS5835_54T_PLATFORM_MODULE))) SONIC_STRETCH_DEBS += $(ACCTON_AS7712_32X_PLATFORM_MODULE) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/__init__.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/fanutil.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/fanutil.py new file mode 100644 index 000000000000..c741ebfd7246 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/fanutil.py @@ -0,0 +1,237 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/27/2019: Brandon_Chuang create +# ------------------------------------------------------------------ + +try: + import time + import logging + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + + +class FanUtil(object): + """Platform-specific FanUtil class""" + + FAN_NUM_ON_MAIN_BROAD = 5 + FAN_NUM_1_IDX = 1 + FAN_NUM_2_IDX = 2 + FAN_NUM_3_IDX = 3 + FAN_NUM_4_IDX = 4 + FAN_NUM_5_IDX = 5 + + FAN_NODE_NUM_OF_MAP = 2 + FAN_NODE_FAULT_IDX_OF_MAP = 1 + FAN_NODE_DIR_IDX_OF_MAP = 2 + + BASE_VAL_PATH = '/sys/bus/i2c/devices/3-0063/{0}' + FAN_DUTY_PATH = '/sys/bus/i2c/devices/3-0063/fan_duty_cycle_percentage' + + #logfile = '' + #loglevel = logging.INFO + + """ Dictionary where + key1 = fan id index (integer) starting from 1 + key2 = fan node index (interger) starting from 1 + value = path to fan device file (string) """ + _fan_to_device_path_mapping = {} + +#fan1_direction +#fan1_fault +#fan1_present + + #(FAN_NUM_2_IDX, FAN_NODE_DUTY_IDX_OF_MAP): 'fan2_duty_cycle_percentage', + _fan_to_device_node_mapping = { + (FAN_NUM_1_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan1_fault', + (FAN_NUM_1_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan1_direction', + + (FAN_NUM_2_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan2_fault', + (FAN_NUM_2_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan2_direction', + + (FAN_NUM_3_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan3_fault', + (FAN_NUM_3_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan3_direction', + + (FAN_NUM_4_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan4_fault', + (FAN_NUM_4_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan4_direction', + + (FAN_NUM_5_IDX, FAN_NODE_FAULT_IDX_OF_MAP): 'fan5_fault', + (FAN_NUM_5_IDX, FAN_NODE_DIR_IDX_OF_MAP): 'fan5_direction', + } + + def _get_fan_to_device_node(self, fan_num, node_num): + return self._fan_to_device_node_mapping[(fan_num, node_num)] + + def _get_fan_node_val(self, fan_num, node_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + + try: + val_file = open(device_path, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + content = val_file.readline().rstrip() + + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return int(content) + + def _set_fan_node_val(self, fan_num, node_num, val): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num:%d', fan_num) + return None + + if node_num < self.FAN_NODE_FAULT_IDX_OF_MAP or node_num > self.FAN_NODE_NUM_OF_MAP: + logging.debug('GET. Parameter error. node_num:%d', node_num) + return None + + content = str(val) + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + + device_path = self.get_fan_to_device_path(fan_num, node_num) + try: + val_file = open(device_path, 'w') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + + val_file.write(content) + + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + + return True + + def __init__(self): + fan_path = self.BASE_VAL_PATH + + for fan_num in range(self.FAN_NUM_1_IDX, self.FAN_NUM_ON_MAIN_BROAD+1): + for node_num in range(self.FAN_NODE_FAULT_IDX_OF_MAP, self.FAN_NODE_NUM_OF_MAP+1): + self._fan_to_device_path_mapping[(fan_num, node_num)] = fan_path.format( + self._fan_to_device_node_mapping[(fan_num, node_num)]) + + def get_num_fans(self): + return self.FAN_NUM_ON_MAIN_BROAD + + def get_idx_fan_start(self): + return self.FAN_NUM_1_IDX + + def get_num_nodes(self): + return self.FAN_NODE_NUM_OF_MAP + + def get_idx_node_start(self): + return self.FAN_NODE_FAULT_IDX_OF_MAP + + def get_size_node_map(self): + return len(self._fan_to_device_node_mapping) + + def get_size_path_map(self): + return len(self._fan_to_device_path_mapping) + + def get_fan_to_device_path(self, fan_num, node_num): + return self._fan_to_device_path_mapping[(fan_num, node_num)] + + def get_fan_fault(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_FAULT_IDX_OF_MAP) + + #def get_fan_speed(self, fan_num): + # return self._get_fan_node_val(fan_num, self.FAN_NODE_SPEED_IDX_OF_MAP) + + def get_fan_dir(self, fan_num): + return self._get_fan_node_val(fan_num, self.FAN_NODE_DIR_IDX_OF_MAP) + + def get_fan_duty_cycle(self): + #duty_path = self.FAN_DUTY_PATH + try: + val_file = open(self.FAN_DUTY_PATH) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + + content = val_file.readline().rstrip() + val_file.close() + + return int(content) + + def set_fan_duty_cycle(self, val): + try: + fan_file = open(self.FAN_DUTY_PATH, 'r+') + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + fan_file.write(str(val)) + fan_file.close() + return True + + #def get_fanr_fault(self, fan_num): + # return self._get_fan_node_val(fan_num, self.FANR_NODE_FAULT_IDX_OF_MAP) + + def get_fanr_speed(self, fan_num): + return self._get_fan_node_val(fan_num, self.FANR_NODE_SPEED_IDX_OF_MAP) + + def get_fan_status(self, fan_num): + if fan_num < self.FAN_NUM_1_IDX or fan_num > self.FAN_NUM_ON_MAIN_BROAD: + logging.debug('GET. Parameter error. fan_num, %d', fan_num) + return None + + if self.get_fan_fault(fan_num) is not None and self.get_fan_fault(fan_num) > 0: + logging.debug('GET. FAN fault. fan_num, %d', fan_num) + return False + + #if self.get_fanr_fault(fan_num) is not None and self.get_fanr_fault(fan_num) > 0: + # logging.debug('GET. FANR fault. fan_num, %d', fan_num) + # return False + + return True + +#def main(): +# fan = FanUtil() +# +# print 'get_size_node_map : %d' % fan.get_size_node_map() +# print 'get_size_path_map : %d' % fan.get_size_path_map() +# for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): +# for y in range(fan.get_idx_node_start(), fan.get_num_nodes()+1): +# print fan.get_fan_to_device_path(x, y) +# +#if __name__ == '__main__': +# main() diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/thermalutil.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/thermalutil.py new file mode 100644 index 000000000000..1dc97cfe276d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/classes/thermalutil.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# Copyright (C) 2017 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 6/11/2019: Brandon_Chuang create +# ------------------------------------------------------------------ + +try: + import os + import time + import logging + import glob + import commands + from collections import namedtuple +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +class ThermalUtil(object): + """Platform-specific ThermalUtil class""" + THERMAL_NUM_MAX = 4 + THERMAL_NUM_1_IDX = 1 # 1_ON_CPU_BROAD. LM75 + THERMAL_NUM_2_IDX = 2 # 2_ON_MAIN_BROAD. LM75 + THERMAL_NUM_3_IDX = 3 # 3_ON_MAIN_BROAD. LM75 + THERMAL_NUM_4_IDX = 4 # 4_ON_MAIN_BROAD. LM75 + + """ Dictionary where + key1 = thermal id index (integer) starting from 1 + value = path to fan device file (string) """ + #_thermal_to_device_path_mapping = {} + + _thermal_to_device_node_mapping = { + THERMAL_NUM_1_IDX: ['18', '4b'], + THERMAL_NUM_2_IDX: ['19', '4c'], + THERMAL_NUM_3_IDX: ['20', '49'], + THERMAL_NUM_4_IDX: ['21', '4a'], + } + thermal_sysfspath ={ + THERMAL_NUM_1_IDX: ["/sys/bus/i2c/devices/18-004b/hwmon/hwmon3/temp1_input"], + THERMAL_NUM_2_IDX: ["/sys/bus/i2c/devices/19-004c/hwmon/hwmon4/temp1_input"], + THERMAL_NUM_3_IDX: ["/sys/bus/i2c/devices/20-0049/hwmon/hwmon5/temp1_input"], + THERMAL_NUM_4_IDX: ["/sys/bus/i2c/devices/21-004a/hwmon/hwmon6/temp1_input"], + } + + #def __init__(self): + def _get_thermal_val(self, thermal_num): + if thermal_num < self.THERMAL_NUM_1_IDX or thermal_num > self.THERMAL_NUM_MAX: + logging.debug('GET. Parameter error. thermal_num, %d', thermal_num) + return None + + device_path = self.get_thermal_to_device_path(thermal_num) + if(os.path.isfile(device_path)): + for filename in glob.glob(device_path): + try: + val_file = open(filename, 'r') + except IOError as e: + logging.error('GET. unable to open file: %s', str(e)) + return None + content = val_file.readline().rstrip() + if content == '': + logging.debug('GET. content is NULL. device_path:%s', device_path) + return None + try: + val_file.close() + except: + logging.debug('GET. unable to close file. device_path:%s', device_path) + return None + return int(content) + + else: + print "No such device_path=%s"%device_path + return 0 + + def get_num_thermals(self): + return self.THERMAL_NUM_MAX + + def get_idx_thermal_start(self): + return self.THERMAL_NUM_1_IDX + + def get_size_node_map(self): + return len(self._thermal_to_device_node_mapping) + + def get_size_path_map(self): + return len(self.thermal_sysfspath) + + def get_thermal_to_device_path(self, thermal_num): + return self.thermal_sysfspath[thermal_num][0] + + def get_thermal_1_val(self): + return self._get_thermal_val(self.THERMAL_NUM_1_IDX) + + def get_thermal_2_val(self): + return self._get_thermal_val(self.THERMAL_NUM_2_IDX) + + def get_thermal_3_val(self): + return self._get_thermal_val(self.THERMAL_NUM_3_IDX) + + def get_thermal_temp(self): + return (self._get_thermal_val(self.THERMAL_NUM_1_IDX) + self._get_thermal_val(self.THERMAL_NUM_2_IDX) +self._get_thermal_val(self.THERMAL_NUM_3_IDX)) + +def main(): + thermal = ThermalUtil() + print "termal1=%d" %thermal._get_thermal_val(1) + print "termal2=%d" %thermal._get_thermal_val(2) + print "termal3=%d" %thermal._get_thermal_val(3) + print "termal4=%d" %thermal._get_thermal_val(4) +# +# print 'get_size_node_map : %d' % thermal.get_size_node_map() +# print 'get_size_path_map : %d' % thermal.get_size_path_map() +# for x in range(thermal.get_idx_thermal_start(), thermal.get_num_thermals()+1): +# print thermal.get_thermal_to_device_path(x) +# +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile new file mode 100644 index 000000000000..887ac3189cec --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/Makefile @@ -0,0 +1,17 @@ +ifneq ($(KERNELRELEASE),) +obj-m:= accton_as5835_54t_cpld.o accton_as5835_54t_psu.o \ + accton_as5835_54t_fan.o accton_as5835_54t_leds.o \ + ym2651y.o + +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_cpld.c b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_cpld.c new file mode 100644 index 000000000000..ae773b4d8209 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_cpld.c @@ -0,0 +1,603 @@ +/* + * Copyright (C) Brandon Chuang + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as5835_54t CPLD1/CPLD2/CPLD3 + * + * Based on: + * pca954t.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954t.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as5835_54t_cpld1, + as5835_54t_cpld2, + as5835_54t_cpld3 +}; + +struct as5835_54t_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; +}; + +static const struct i2c_device_id as5835_54t_cpld_id[] = { + { "as5835_54t_cpld1", as5835_54t_cpld1 }, + { "as5835_54t_cpld2", as5835_54t_cpld2 }, + { "as5835_54t_cpld3", as5835_54t_cpld3 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as5835_54t_cpld_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index + +enum as5835_54t_cpld1_sysfs_attributes { + CPLD_VERSION, + ACCESS, + MODULE_PRESENT_ALL, + MODULE_RXLOS_ALL, + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(49), + TRANSCEIVER_PRESENT_ATTR_ID(50), + TRANSCEIVER_PRESENT_ATTR_ID(51), + TRANSCEIVER_PRESENT_ATTR_ID(52), + TRANSCEIVER_PRESENT_ATTR_ID(53), + TRANSCEIVER_PRESENT_ATTR_ID(54), + TRANSCEIVER_LPMODE_ATTR_ID(49), + TRANSCEIVER_LPMODE_ATTR_ID(50), + TRANSCEIVER_LPMODE_ATTR_ID(51), + TRANSCEIVER_LPMODE_ATTR_ID(52), + TRANSCEIVER_LPMODE_ATTR_ID(53), + TRANSCEIVER_LPMODE_ATTR_ID(54), + TRANSCEIVER_RESET_ATTR_ID(49), + TRANSCEIVER_RESET_ATTR_ID(50), + TRANSCEIVER_RESET_ATTR_ID(51), + TRANSCEIVER_RESET_ATTR_ID(52), + TRANSCEIVER_RESET_ATTR_ID(53), + TRANSCEIVER_RESET_ATTR_ID(54), +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static int as5835_54t_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as5835_54t_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/* transceiver attributes */ +#define DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index) +#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr + +#define DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_LPMODE_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_RESET_##index) +#define DECLARE_QSFP_TRANSCEIVER_ATTR(index) \ + &sensor_dev_attr_module_lpmode_##index.dev_attr.attr, \ + &sensor_dev_attr_module_reset_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); +/* transceiver attributes */ +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(49); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(50); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(51); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(52); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(53); +DECLARE_TRANSCEIVER_PRESENT_SENSOR_DEVICE_ATTR(54); + +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(49); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(50); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(51); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(52); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(53); +DECLARE_QSFP_TRANSCEIVER_SENSOR_DEVICE_ATTR(54); + +static struct attribute *as5835_54t_cpld1_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as5835_54t_cpld1_group = { + .attrs = as5835_54t_cpld1_attributes, +}; + +static struct attribute *as5835_54t_cpld2_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + NULL +}; + +static const struct attribute_group as5835_54t_cpld2_group = { + .attrs = as5835_54t_cpld2_attributes, +}; + +static struct attribute *as5835_54t_cpld3_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(49), + DECLARE_TRANSCEIVER_PRESENT_ATTR(50), + DECLARE_TRANSCEIVER_PRESENT_ATTR(51), + DECLARE_TRANSCEIVER_PRESENT_ATTR(52), + DECLARE_TRANSCEIVER_PRESENT_ATTR(53), + DECLARE_TRANSCEIVER_PRESENT_ATTR(54), + DECLARE_QSFP_TRANSCEIVER_ATTR(49), + DECLARE_QSFP_TRANSCEIVER_ATTR(50), + DECLARE_QSFP_TRANSCEIVER_ATTR(51), + DECLARE_QSFP_TRANSCEIVER_ATTR(52), + DECLARE_QSFP_TRANSCEIVER_ATTR(53), + DECLARE_QSFP_TRANSCEIVER_ATTR(54), + NULL +}; + +static const struct attribute_group as5835_54t_cpld3_group = { + .attrs = as5835_54t_cpld3_attributes, +}; + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[5] = {0}; + u8 regs_cpld3[] = {0x14}; + u8 *regs[] = {NULL, NULL, regs_cpld3}; + u8 size[] = {0, 0, ARRAY_SIZE(regs_cpld3)}; + struct i2c_client *client = to_i2c_client(dev); + struct as5835_54t_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + for (i = 0; i < size[data->type]; i++) { + status = as5835_54t_cpld_read_internal(client, regs[data->type][i]); + if (status < 0) { + goto exit; + } + + values[i] = ~(u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values in order */ + values[0] &= 0x3F; + return sprintf(buf, "%.2x\n", values[0]); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as5835_54t_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, revert = 0; + + switch (attr->index) { + case MODULE_PRESENT_49 ... MODULE_PRESENT_54: + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_PRESENT_49); + break; + case MODULE_LPMODE_49 ... MODULE_LPMODE_54: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_LPMODE_49); + break; + case MODULE_RESET_49 ... MODULE_RESET_54: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + default: + return 0; + } + + if (attr->index >= MODULE_PRESENT_49 && attr->index <= MODULE_PRESENT_54) { + revert = 1; + } + + mutex_lock(&data->update_lock); + status = as5835_54t_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", revert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as5835_54t_cpld_data *data = i2c_get_clientdata(client); + long value; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &value); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_LPMODE_49 ... MODULE_LPMODE_54: + reg = 0x16; + mask = 0x1 << (attr->index - MODULE_LPMODE_49); + break; + case MODULE_RESET_49 ... MODULE_RESET_54: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_RESET_49); + break; + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as5835_54t_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update tx_disable/lpmode/reset status */ + if (value) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as5835_54t_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as5835_54t_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as5835_54t_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as5835_54t_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as5835_54t_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d\n", val); +} + +/* + * I2C init/probing/exit functions + */ +static int as5835_54t_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as5835_54t_cpld_data *data; + int ret = -ENODEV; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as5835_54t_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) { + case as5835_54t_cpld1: + group = &as5835_54t_cpld1_group; + break; + case as5835_54t_cpld2: + group = &as5835_54t_cpld2_group; + break; + case as5835_54t_cpld3: + group = &as5835_54t_cpld3_group; + break; + default: + break; + } + + if (group) { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as5835_54t_cpld_add_client(client); + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as5835_54t_cpld_remove(struct i2c_client *client) +{ + struct as5835_54t_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as5835_54t_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) { + case as5835_54t_cpld1: + group = &as5835_54t_cpld1_group; + break; + case as5835_54t_cpld2: + group = &as5835_54t_cpld2_group; + break; + case as5835_54t_cpld3: + group = &as5835_54t_cpld3_group; + break; + default: + break; + } + + if (group) { + sysfs_remove_group(&client->dev.kobj, group); + } + + kfree(data); + + return 0; +} + +static int as5835_54t_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as5835_54t_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as5835_54t_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5835_54t_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5835_54t_cpld_read); + +int as5835_54t_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as5835_54t_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as5835_54t_cpld_write); + +static struct i2c_driver as5835_54t_cpld_driver = { + .driver = { + .name = "as5835_54t_cpld", + .owner = THIS_MODULE, + }, + .probe = as5835_54t_cpld_probe, + .remove = as5835_54t_cpld_remove, + .id_table = as5835_54t_cpld_id, +}; + +static int __init as5835_54t_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as5835_54t_cpld_driver); +} + +static void __exit as5835_54t_cpld_exit(void) +{ + i2c_del_driver(&as5835_54t_cpld_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton I2C CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as5835_54t_cpld_init); +module_exit(as5835_54t_cpld_exit); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_fan.c b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_fan.c new file mode 100644 index 000000000000..ea6fdb8296c9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_fan.c @@ -0,0 +1,484 @@ +/* + * A hwmon driver for the Accton as5835 54t fan + * + * Copyright (C) 2016 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as5835_54t_fan" +#define MAX_FAN_SPEED_RPM 21500 + +static struct as5835_54t_fan_data *as5835_54t_fan_update_device(struct device *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +extern int as5835_54t_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5835_54t_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x02, /* fan 1-5 present status */ + 0x03, /* fan 1-5 direction(0:F2B 1:B2F) */ + 0x04, /* front fan 1-5 fault status */ + 0x05, /* rear fan 1-5 fault status */ + 0x06, /* fan PWM(for all fan) */ + 0x07, /* front fan 1 speed(rpm) */ + 0x08, /* front fan 2 speed(rpm) */ + 0x09, /* front fan 3 speed(rpm) */ + 0x0A, /* front fan 4 speed(rpm) */ + 0x0B, /* front fan 5 speed(rpm) */ + 0x0C, /* rear fan 1 speed(rpm) */ + 0x0D, /* rear fan 2 speed(rpm) */ + 0x0E, /* rear fan 3 speed(rpm) */ + 0x0F, /* rear fan 4 speed(rpm) */ + 0x10, /* rear fan 5 speed(rpm) */ +}; + +/* fan data */ +struct as5835_54t_fan_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ +}; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID, + FAN5_ID +}; + +enum sysfs_fan_attributes { + FAN_PRESENT_REG, + FAN_DIRECTION_REG, + FAN_FRONT_FAULT_REG, + FAN_REAR_FAULT_REG, + FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ + FAN1_FRONT_SPEED_RPM, + FAN2_FRONT_SPEED_RPM, + FAN3_FRONT_SPEED_RPM, + FAN4_FRONT_SPEED_RPM, + FAN5_FRONT_SPEED_RPM, + FAN1_REAR_SPEED_RPM, + FAN2_REAR_SPEED_RPM, + FAN3_REAR_SPEED_RPM, + FAN4_REAR_SPEED_RPM, + FAN5_REAR_SPEED_RPM, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, + FAN5_PRESENT, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN4_FAULT, + FAN5_FAULT, + FAN_MAX_RPM, + CPLD_VERSION +}; + +/* Define attributes + */ +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT);\ + static SENSOR_DEVICE_ATTR(fan##index2##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index, index2) &sensor_dev_attr_fan##index##_fault.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_fault.dev_attr.attr +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IRUGO, fan_show_value, NULL, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE) +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr + +#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT) +#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr + +#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_front_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_rear_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index2##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM) +#define DECLARE_FAN_SPEED_RPM_ATTR(index, index2) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_input.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(fan_max_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN_MAX_RPM); +#define DECLARE_FAN_MAX_RPM_ATTR(index) &sensor_dev_attr_fan_max_speed_rpm.dev_attr.attr + + +/* 5 fan fault attributes in this platform */ +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1, 11); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2, 12); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3, 13); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4, 14); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5, 15); +/* 5 fan speed(rpm) attributes in this platform */ +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1, 11); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2, 12); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3, 13); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4, 14); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5, 15); +/* 5 fan present attributes in this platform */ +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(5); +/* 5 fan direction attribute in this platform */ +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); +/* 1 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); + +static struct attribute *as5835_54t_fan_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + /* fan related attributes */ + DECLARE_FAN_FAULT_ATTR(1, 11), + DECLARE_FAN_FAULT_ATTR(2, 12), + DECLARE_FAN_FAULT_ATTR(3, 13), + DECLARE_FAN_FAULT_ATTR(4, 14), + DECLARE_FAN_FAULT_ATTR(5, 15), + DECLARE_FAN_SPEED_RPM_ATTR(1, 11), + DECLARE_FAN_SPEED_RPM_ATTR(2, 12), + DECLARE_FAN_SPEED_RPM_ATTR(3, 13), + DECLARE_FAN_SPEED_RPM_ATTR(4, 14), + DECLARE_FAN_SPEED_RPM_ATTR(5, 15), + DECLARE_FAN_PRESENT_ATTR(1), + DECLARE_FAN_PRESENT_ATTR(2), + DECLARE_FAN_PRESENT_ATTR(3), + DECLARE_FAN_PRESENT_ATTR(4), + DECLARE_FAN_PRESENT_ATTR(5), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(5), + DECLARE_FAN_DUTY_CYCLE_ATTR(), + DECLARE_FAN_MAX_RPM_ATTR(), + NULL +}; + +#define FAN_DUTY_CYCLE_REG_MASK 0x1F +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 150 + +static int as5835_54t_fan_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int as5835_54t_fan_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + return (reg_val & FAN_DUTY_CYCLE_REG_MASK) * 5; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + if (duty_cycle > FAN_MAX_DUTY_CYCLE) { + duty_cycle = FAN_MAX_DUTY_CYCLE; + } + + return (duty_cycle / 5); +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) +{ + return !!(reg_val & BIT(id)); /* 0: Front to Back, 1: Back to Front*/ +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + return !(reg_val & BIT(id)); +} + +static u8 is_fan_fault(struct as5835_54t_fan_data *data, enum fan_id id) +{ + if ((data->reg_val[FAN_FRONT_FAULT_REG] & BIT(id)) || + (data->reg_val[FAN_REAR_FAULT_REG] & BIT(id))) { + return 1; + } + + return 0; +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct i2c_client *client = to_i2c_client(dev); + + error = kstrtoint(buf, 10, &value); + if (error) { + return error; + } + + if (value < 0 || value > FAN_MAX_DUTY_CYCLE) { + return -EINVAL; + } + + as5835_54t_fan_write_value(client, fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); + return count; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as5835_54t_fan_data *data = as5835_54t_fan_update_device(dev); + ssize_t ret = 0; + + if (data->valid) { + switch (attr->index) { + case FAN_DUTY_CYCLE_PERCENTAGE: + { + u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[FAN_DUTY_CYCLE_PERCENTAGE]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + } + case FAN1_FRONT_SPEED_RPM: + case FAN2_FRONT_SPEED_RPM: + case FAN3_FRONT_SPEED_RPM: + case FAN4_FRONT_SPEED_RPM: + case FAN5_FRONT_SPEED_RPM: + case FAN1_REAR_SPEED_RPM: + case FAN2_REAR_SPEED_RPM: + case FAN3_REAR_SPEED_RPM: + case FAN4_REAR_SPEED_RPM: + case FAN5_REAR_SPEED_RPM: + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG], + attr->index - FAN1_PRESENT)); + break; + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + case FAN5_FAULT: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); + break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + ret = sprintf(buf, "%d\n", + reg_val_to_direction(data->reg_val[FAN_DIRECTION_REG], + attr->index - FAN1_DIRECTION)); + break; + case FAN_MAX_RPM: + ret = sprintf(buf, "%d\n", MAX_FAN_SPEED_RPM); + default: + break; + } + } + + return ret; +} + +static const struct attribute_group as5835_54t_fan_group = { + .attrs = as5835_54t_fan_attributes, +}; + +static struct as5835_54t_fan_data *as5835_54t_fan_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5835_54t_fan_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting as5835_54t_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + int status = as5835_54t_fan_read_value(client, fan_reg[i]); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "reg %d, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + mutex_unlock(&data->update_lock); + + return data; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d\n", val); +} + +static int as5835_54t_fan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as5835_54t_fan_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as5835_54t_fan_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as5835_54t_fan_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, "as5835_54t_fan", + NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: fan '%s'\n", + dev_name(data->hwmon_dev), client->name); + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as5835_54t_fan_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as5835_54t_fan_remove(struct i2c_client *client) +{ + struct as5835_54t_fan_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as5835_54t_fan_group); + + return 0; +} + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static const struct i2c_device_id as5835_54t_fan_id[] = { + { "as5835_54t_fan", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as5835_54t_fan_id); + +static struct i2c_driver as5835_54t_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as5835_54t_fan_probe, + .remove = as5835_54t_fan_remove, + .id_table = as5835_54t_fan_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(as5835_54t_fan_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as5835_54t_fan driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_leds.c b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_leds.c new file mode 100644 index 000000000000..e02930a2f6e0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_leds.c @@ -0,0 +1,380 @@ +/* + * A LED driver for the accton_as5822_54t_led + * + * Copyright (C) 2016 Accton Technology Corporation. + * Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as5835_54t_led" + +#define DEBUG_MODE 0 + +#if (DEBUG_MODE == 1) + #define DEBUG_PRINT(fmt, args...) \ + printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) +#endif + +extern int as5835_54t_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as5835_54t_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +struct accton_as5835_54t_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[2]; /* Register value, 0 = RELEASE/DIAG LED, + 1 = FAN/PSU LED, + 2 ~ 4 = SYSTEM LED */ +}; + +static struct accton_as5835_54t_led_data *ledctl = NULL; + +#define LED_CNTRLER_I2C_ADDRESS (0x60) + +#define LED_TYPE_DIAG_REG_MASK (0x0C) +#define LED_MODE_DIAG_GREEN_VALUE (0x08) +#define LED_MODE_DIAG_AMBER_VALUE (0x04) +#define LED_MODE_DIAG_OFF_VALUE (0x0C) +#define LED_MODE_DIAG_AMBER_VALUE1 (0x00) + +#define LED_TYPE_LOC_REG_MASK (0x30) +#define LED_MODE_LOC_AMBER_BLINK_VALUE (0x20) +#define LED_MODE_LOC_OFF_VALUE (0x10) +#define LED_MODE_LOC_AMBER_VALUE (0x00) + +static const u8 led_reg[] = { + 0xA, /* LOC/DIAG/FAN LED */ + 0xB, /* PSU LED */ +}; + +enum led_type { + LED_TYPE_DIAG, + LED_TYPE_LOC, + LED_TYPE_FAN, + LED_TYPE_PSU1, + LED_TYPE_PSU2 +}; + +/* FAN/PSU/DIAG/RELEASE led mode */ +enum led_light_mode { + LED_MODE_OFF = 0, + LED_MODE_GREEN, + LED_MODE_GREEN_BLINK, + LED_MODE_AMBER, + LED_MODE_AMBER_BLINK, + LED_MODE_RED, + LED_MODE_RED_BLINK, + LED_MODE_BLUE, + LED_MODE_BLUE_BLINK, + LED_MODE_AUTO, + LED_MODE_UNKNOWN +}; + +struct led_type_mode { + enum led_type type; + enum led_light_mode mode; + int type_mask; + int mode_value; +}; + +static struct led_type_mode led_type_mode_data[] = { +{LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE}, +{LED_TYPE_LOC, LED_MODE_AMBER_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_BLINK_VALUE}, +{LED_TYPE_LOC, LED_MODE_AMBER, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_VALUE}, +{LED_TYPE_DIAG, LED_MODE_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE}, +{LED_TYPE_DIAG, LED_MODE_GREEN, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_VALUE}, +{LED_TYPE_DIAG, LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE}, +{LED_TYPE_DIAG, LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE1}, +}; + +static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + if (type != led_type_mode_data[i].type) { + continue; + } + + if ((led_type_mode_data[i].type_mask & reg_val) == + led_type_mode_data[i].mode_value) { + return led_type_mode_data[i].mode; + } + } + + return LED_MODE_UNKNOWN; +} + +static u8 led_light_mode_to_reg_val(enum led_type type, + enum led_light_mode mode, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + int type_mask, mode_value; + + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + type_mask = led_type_mode_data[i].type_mask; + mode_value = led_type_mode_data[i].mode_value; + reg_val = (reg_val & ~type_mask) | mode_value; + } + + return reg_val; +} + +static int accton_as5835_54t_led_read_value(u8 reg) +{ + return as5835_54t_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); +} + +static int accton_as5835_54t_led_write_value(u8 reg, u8 value) +{ + return as5835_54t_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); +} + +static void accton_as5835_54t_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting accton_as5835_54t_led update\n"); + ledctl->valid = 0; + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = accton_as5835_54t_led_read_value(led_reg[i]); + + if (status < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status); + goto exit; + } + else + ledctl->reg_val[i] = status; + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as5835_54t_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + int reg_val; + + mutex_lock(&ledctl->update_lock); + reg_val = accton_as5835_54t_led_read_value(reg); + + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + accton_as5835_54t_led_write_value(reg, reg_val); + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void accton_as7312_54t_led_auto_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ +} + +static enum led_brightness accton_as7312_54t_led_auto_get(struct led_classdev *cdev) +{ + return LED_MODE_AUTO; +} + +static void accton_as5835_54t_led_diag_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5835_54t_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_DIAG); +} + +static enum led_brightness accton_as5835_54t_led_diag_get(struct led_classdev *cdev) +{ + accton_as5835_54t_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[0]); +} + +static enum led_brightness accton_as5835_54t_led_loc_get(struct led_classdev *cdev) +{ + accton_as5835_54t_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]); +} + +static void accton_as5835_54t_led_loc_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + accton_as5835_54t_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC); +} + +static struct led_classdev accton_as5835_54t_leds[] = { + [LED_TYPE_LOC] = { + .name = "as5835_54t_led::loc", + .default_trigger = "unused", + .brightness_set = accton_as5835_54t_led_loc_set, + .brightness_get = accton_as5835_54t_led_loc_get, + .max_brightness = LED_MODE_AMBER_BLINK, + }, + [LED_TYPE_DIAG] = { + .name = "as5835_54t_led::diag", + .default_trigger = "unused", + .brightness_set = accton_as5835_54t_led_diag_set, + .brightness_get = accton_as5835_54t_led_diag_get, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_PSU1] = { + .name = "as5835_54t_led::psu1", + .default_trigger = "unused", + .brightness_set = accton_as7312_54t_led_auto_set, + .brightness_get = accton_as7312_54t_led_auto_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_PSU2] = { + .name = "as5835_54t_led::psu2", + .default_trigger = "unused", + .brightness_set = accton_as7312_54t_led_auto_set, + .brightness_get = accton_as7312_54t_led_auto_get, + .max_brightness = LED_MODE_AUTO, + }, + [LED_TYPE_FAN] = { + .name = "as5835_54t_led::fan", + .default_trigger = "unused", + .brightness_set = accton_as7312_54t_led_auto_set, + .brightness_get = accton_as7312_54t_led_auto_get, + .max_brightness = LED_MODE_AUTO, + }, +}; + +static int accton_as5835_54t_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(accton_as5835_54t_leds); i++) { + ret = led_classdev_register(&pdev->dev, &accton_as5835_54t_leds[i]); + + if (ret < 0) { + break; + } + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(accton_as5835_54t_leds)){ + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&accton_as5835_54t_leds[i]); + } + } + + return ret; +} + +static int accton_as5835_54t_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(accton_as5835_54t_leds); i++) { + led_classdev_unregister(&accton_as5835_54t_leds[i]); + } + + return 0; +} + +static struct platform_driver accton_as5835_54t_led_driver = { + .probe = accton_as5835_54t_led_probe, + .remove = accton_as5835_54t_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init accton_as5835_54t_led_init(void) +{ + int ret; + + ret = platform_driver_register(&accton_as5835_54t_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct accton_as5835_54t_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + goto exit_driver; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + goto exit_free; + } + + return 0; + +exit_free: + kfree(ledctl); +exit_driver: + platform_driver_unregister(&accton_as5835_54t_led_driver); +exit: + return ret; +} + +static void __exit accton_as5835_54t_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&accton_as5835_54t_led_driver); + kfree(ledctl); +} + +late_initcall(accton_as5835_54t_led_init); +module_exit(accton_as5835_54t_led_exit); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("accton_as5835_54t_led driver"); +MODULE_LICENSE("GPL"); + + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_psu.c b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_psu.c new file mode 100644 index 000000000000..78f0b4298a58 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/accton_as5835_54t_psu.c @@ -0,0 +1,343 @@ +/* + * An hwmon driver for accton as5835_54t Power Module + * + * Copyright (C) 2014 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PSU_STATUS_I2C_ADDR 0x60 +#define PSU_STATUS_I2C_REG_OFFSET 0x2 + +#define MODEL_NAME_LEN 8 +#define MODEL_NAME_REG_OFFSET 0x20 + +#define SERIAL_NUM_LEN 18 +#define SERIAL_NUM_REG_OFFSET 0x35 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id*4 + 1))) +#define IS_PRESENT(id, value) (!(value & BIT(id*4))) + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +extern int as5835_54t_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as5835_54t_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MODEL_NAME_LEN+1]; /* Model name, read from eeprom */ + char serial[SERIAL_NUM_LEN+1]; /* Serial number, read from eeprom*/ +}; + +static struct as5835_54t_psu_data *as5835_54t_psu_update_device(struct device *dev); + +enum as5835_54t_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_numer, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); + +static struct attribute *as5835_54t_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_numer.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as5835_54t_psu_data *data = as5835_54t_psu_update_device(dev); + u8 status = 0; + + if (!data->valid) { + return sprintf(buf, "0\n"); + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct as5835_54t_psu_data *data = as5835_54t_psu_update_device(dev); + char *str = NULL; + + if (!data->valid) { + return 0; + } + + if (attr->index == PSU_MODEL_NAME) { + str = data->model_name; + } + else { /* PSU_SERIAL_NUBMER */ + str = data->serial; + } + + return sprintf(buf, "%s\n", str); +} + +static const struct attribute_group as5835_54t_psu_group = { + .attrs = as5835_54t_psu_attributes, +}; + +static int as5835_54t_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as5835_54t_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as5835_54t_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as5835_54t_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, "as5835_54t_psu", + NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as5835_54t_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as5835_54t_psu_remove(struct i2c_client *client) +{ + struct as5835_54t_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as5835_54t_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as5835_54t_psu1, + as5835_54t_psu2 +}; + +static const struct i2c_device_id as5835_54t_psu_id[] = { + { "as5835_54t_psu1", as5835_54t_psu1 }, + { "as5835_54t_psu2", as5835_54t_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as5835_54t_psu_id); + +static struct i2c_driver as5835_54t_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as5835_54t_psu", + }, + .probe = as5835_54t_psu_probe, + .remove = as5835_54t_psu_remove, + .id_table = as5835_54t_psu_id, + .address_list = normal_i2c, +}; + +static int as5835_54t_psu_read_byte(struct i2c_client *client, u8 command, u8 *data) +{ + int status = 0; + int retry_count = 5; + + while (retry_count) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(10); + retry_count--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + +abort: + return status; +} + +static int as5835_54t_psu_read_bytes(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int ret = 0; + + while (data_len) { + ssize_t status; + + status = as5835_54t_psu_read_byte(client, command, data); + if (status <= 0) { + ret = status; + break; + } + + data += 1; + command += 1; + data_len -= 1; + } + + return ret; +} + +static struct as5835_54t_psu_data *as5835_54t_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as5835_54t_psu_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + + dev_dbg(&client->dev, "Starting as5835_54t update\n"); + data->valid = 0; + + /* Read psu status */ + status = as5835_54t_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial, 0, sizeof(data->serial)); + + if (IS_PRESENT(data->index, data->status)) { + /* Read model name */ + status = as5835_54t_psu_read_bytes(client, MODEL_NAME_REG_OFFSET, data->model_name, + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + goto exit; + } + + /* Read serial number */ + status = as5835_54t_psu_read_bytes(client, SERIAL_NUM_REG_OFFSET, data->serial, + ARRAY_SIZE(data->serial)-1); + if (status < 0) { + data->serial[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial number from (0x%x)\n", client->addr); + goto exit; + } + else { + data->serial[SERIAL_NUM_LEN] = '\0'; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +module_i2c_driver(as5835_54t_psu_driver); + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("as5835_54t_psu driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/ym2651y.c b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/ym2651y.c new file mode 120000 index 000000000000..f4d67640ccc3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/modules/ym2651y.c @@ -0,0 +1 @@ +../../common/modules/ym2651y.c \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor-fan.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor-fan.service new file mode 100644 index 000000000000..19ad3e519471 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor-fan.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS5835-54T Platform Monitoring FAN service +Before=pmon.service +After=as5835-54t-platform-monitor.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as5835_54t_monitor_fan.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor-psu.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor-psu.service new file mode 100644 index 000000000000..f30b13b6bc3b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor-psu.service @@ -0,0 +1,16 @@ +[Unit] +Description=Accton AS5835-54T Platform Monitoring PSU service +Before=pmon.service +After=as5835-54t-platform-monitor.service +DefaultDependencies=no + +[Service] +ExecStart=/usr/local/bin/accton_as5835_54t_monitor_psu.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor.service b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor.service new file mode 100644 index 000000000000..9789201034c0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/service/as5835-54t-platform-monitor.service @@ -0,0 +1,18 @@ +[Unit] +Description=Accton AS5835-54T Platform Monitoring service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +ExecStartPre=/usr/local/bin/accton_as5835_54t_util.py install +ExecStart=/usr/local/bin/accton_as5835_54t_monitor.py +KillSignal=SIGKILL +SuccessExitStatus=SIGKILL +#StandardOutput=tty + +# Resource Limitations +LimitCORE=infinity + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/setup.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/setup.py new file mode 100644 index 000000000000..ac880c41e4e0 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='as5835_54t', + version='1.0', + description='Module to initialize Accton AS5835-54T platforms', + + packages=['as5835_54t'], + package_dir={'as5835_54t': 'as5835-54t/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/README b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/README new file mode 100644 index 000000000000..dc9b838f9f1b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/README @@ -0,0 +1,74 @@ +Copyright (C) 2016 Accton Networks, Inc. + +This program is free software: you can redistribute it and/or modify +It under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . + +Contents of this package: + module - Contains source code of as5835 kernel driver modules. + util - operational scripts. + +Sonic creates a docker container and run building process under it. +If user tries to built new drivers, please get into that docker and +dpkg-buildpackage for them. + +All Linux kernel code is licensed under the GPLv1. All other code is +licensed under the GPLv3. Please see the LICENSE file for copies of +both licenses. + +The code for integacting with Accton AS5835-54T has 2 parts, +kernel drivers and operational script. +The kernel drivers of peripherals are under module/ directory. +1. These drivers can be built to individual ko during dpkg-buildpackage. +2. A operational script, accton_as5835_54t_util.py, for device initializatian. + Run "accton_as5835_54t_util.py install" to install drivers. + +To initialize the system, run "accton_as5835_54t_util.py install". +To clean up the drivers & devices, run "accton_as5835_54t_util.py clean". +To dump information of sensors, run "accton_as5835_54t_util.py show". +To dump SFP EEPROM, run "accton_as5835_54t_util.py sff". +To set fan speed, run "accton_as5835_54t_util.py set fan". +To enable/disable SFP emission, run "accton_as5835_54t_util.py set sfp". +To set system LEDs' color, run "accton_as5835_54t_util.py set led" +For more information, run "accton_as5835_54t_util.py --help". + +==================================================================== +Besides applying accton_as5835_54t_util.py to access peripherals, you can +access peripherals by sysfs nodes directly after the installation is run. + +System LED: + There are 5 system LEDs at the lower-left corner of front panel. + They are loc, diag, fan, ps1, and ps2. + The sysfs interface color mappings are as follows: + Brightness: + 0 => off + 1 => green + 2 => green blinking + 3 => amber + 4 => amber blinking + But not all colors are available for each LED. + +Fan Control: + There are 10 fans inside 5 fan modules. + All fans share 1 duty setting, ranged from 0~100. + +Thermal sensers: + 4 temperature sensors are controlled by the lm75 kernel modules. + +PSUs: + There 2 power supplies slot at the left/right side of the back. + Once if a PSU is not plugged, the status of it is shown failed. + +There are 48 SFP+ and 6 QSFP modules are equipped. +Before operating on PSU and QSFP+, please make sure it is well plugged. +Otherwise, operation is going to fail. + diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor.py new file mode 100755 index 000000000000..ce2e0d18d4ff --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor.py @@ -0,0 +1,206 @@ +#!/usr/bin/env python +# +# Copyright (C) 2019 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 11/13/2017: Polly Hsu, Create +# 05/08/2019: Roy Lee, changed for as5812-54x. +# 05/29/2019: Brandon Chuang, changed for as5835-54x. +# 06/11/2019: Brandon Chuang, changed for as5835-54t. +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import types + import time # this is only being used as part of the example + import traceback + import signal + from tabulate import tabulate + from as5835_54t.fanutil import FanUtil + from as5835_54t.thermalutil import ThermalUtil +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = 'accton_as5835_54t_monitor' +DUTY_MAX = 100 + +global log_file +global log_level + +# Make a class we can use to capture stdout and sterr in the log +class accton_as5835_54t_monitor(object): + # static temp var + _ori_temp = 0 + _new_perc = 0 + + def __init__(self, log_file, log_level): + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fans(self): + FAN_LEV1_UP_TEMP = 57700 # temperature + FAN_LEV1_DOWN_TEMP = 0 # unused + FAN_LEV1_SPEED_PERC = DUTY_MAX # percentage*/ + + FAN_LEV2_UP_TEMP = 53000 + FAN_LEV2_DOWN_TEMP = 52700 + FAN_LEV2_SPEED_PERC = 80 + + FAN_LEV3_UP_TEMP = 49500 + FAN_LEV3_DOWN_TEMP = 47700 + FAN_LEV3_SPEED_PERC = 65 + + FAN_LEV4_UP_TEMP = 0 # unused + FAN_LEV4_DOWN_TEMP = 42700 + FAN_LEV4_SPEED_PERC = 40 + + + thermal = ThermalUtil() + fan = FanUtil() + + temp2 = thermal.get_thermal_2_val() + if temp2 is None: + return False + + temp3 = thermal.get_thermal_3_val() + if temp3 is None: + return False + + new_temp = (temp2 + temp3) / 2 + + for x in range(fan.get_idx_fan_start(), fan.get_num_fans()+1): + fan_stat = fan.get_fan_status(x) + if fan_stat is None: + return False + if fan_stat is False: + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET new_perc to %d (FAN fault. fan_num:%d)', self._new_perc, x) + break + logging.debug('INFO. fan_stat is True (fan_num:%d)', x) + + if fan_stat is not None and fan_stat is not False: + diff = new_temp - self._ori_temp + if diff == 0: + logging.debug('INFO. RETURN. THERMAL temp not changed. %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + return True + else: + if diff >= 0: + is_up = True + logging.debug('INFO. THERMAL temp UP %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + else: + is_up = False + logging.debug('INFO. THERMAL temp DOWN %d / %d (new_temp / ori_temp)', new_temp, self._ori_temp) + + if is_up is True: + if new_temp >= FAN_LEV1_UP_TEMP: + self._new_perc = FAN_LEV1_SPEED_PERC + elif new_temp >= FAN_LEV2_UP_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + elif new_temp >= FAN_LEV3_UP_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + else: + self._new_perc = FAN_LEV4_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + else: + if new_temp <= FAN_LEV4_DOWN_TEMP: + self._new_perc = FAN_LEV4_SPEED_PERC + elif new_temp <= FAN_LEV3_DOWN_TEMP: + self._new_perc = FAN_LEV3_SPEED_PERC + elif new_temp <= FAN_LEV2_DOWN_TEMP: + self._new_perc = FAN_LEV2_SPEED_PERC + else: + self._new_perc = FAN_LEV1_SPEED_PERC + logging.debug('INFO. SET. FAN_SPEED as %d (new THERMAL temp:%d)', self._new_perc, new_temp) + + cur_perc = fan.get_fan_duty_cycle() + if cur_perc == self._new_perc: + logging.debug('INFO. RETURN. FAN speed not changed. %d / %d (new_perc / ori_perc)', self._new_perc, cur_perc) + return True + + set_stat = fan.set_fan_duty_cycle(self._new_perc) + if set_stat is True: + logging.debug('INFO: PASS. set_fan_duty_cycle (%d)', self._new_perc) + else: + logging.debug('INFO: FAIL. set_fan_duty_cycle (%d)', self._new_perc) + + logging.debug('INFO: GET. ori_perc is %d. ori_temp is %d', cur_perc, self._ori_temp) + self._ori_temp = new_temp + logging.debug('INFO: UPDATE. ori_perc to %d. ori_temp to %d', cur_perc, self._ori_temp) + + return True + +def handler(signum, frame): + fan = FanUtil() + logging.debug('INFO:Cause signal %d, set fan speed max.', signum) + fan.set_fan_duty_cycle(DUTY_MAX) + sys.exit(0) + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + + signal.signal(signal.SIGINT, handler) + signal.signal(signal.SIGTERM, handler) + monitor = accton_as5835_54t_monitor(log_file, log_level) + + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_fans() + time.sleep(10) + +if __name__ == '__main__': + main(sys.argv[1:]) \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor_fan.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor_fan.py new file mode 100755 index 000000000000..d1d93d4f8aea --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor_fan.py @@ -0,0 +1,198 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 5/27/2019: Brandon_Chuang create +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import logging.handlers + import types + import time # this is only being used as part of the example + import traceback + from tabulate import tabulate + +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as5835_54t_monitor_fan' + +global log_file +global log_level + + +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +fan_state=[2, 2, 2, 2, 2, 2] #init state=2, insert=1, remove=0 +fan_status_state=[2, 2, 2, 2, 2, 2] #init state=2, fault=1, normal=0 +# Make a class we can use to capture stdout and sterr in the log +class device_monitor(object): + + #/sys/bus/i2c/devices/3-0063 + #fan1_present, fan5_present + + def __init__(self, log_file, log_level): + + self.fan_num = 5 + self.fan_path = "/sys/bus/i2c/devices/3-0063/" + self.present = { + 0: "fan1_present", + 1: "fan2_present", + 2: "fan3_present", + 3: "fan4_present", + 4: "fan5_present", + } + + self.fault = { + 0: "fan1_fault", + 1: "fan2_fault", + 2: "fan3_fault", + 3: "fan4_fault", + 4: "fan5_fault", + } + + + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + + # set up logging to console + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(logging.DEBUG) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address = '/dev/log') + #sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.INFO) + logging.getLogger('').addHandler(sys_handler) + + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_fan(self): + + FAN_STATE_REMOVE = 0 + FAN_STATE_INSERT = 1 + + FAN_STATUS_FAULT = 1 + FAN_STATUS_NORMAL = 0 + + global fan_state + global fan_status_state + + for idx in range (0, self.fan_num): + node = self.fan_path + self.present[idx] + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if fan_state[idx]!=1: + fan_state[idx]=FAN_STATE_INSERT + logging.info("FAN-%d present is detected", idx+1); + else: + if fan_state[idx]!=0: + fan_state[idx]=FAN_STATE_REMOVE + logging.warning("Alarm for FAN-%d absent is detected", idx+1) + + for idx in range (0, self.fan_num): + node = self.fan_path + self.fault[idx] + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if fan_status_state[idx]!=FAN_STATUS_FAULT: + if fan_state[idx] == FAN_STATE_INSERT: + logging.warning("Alarm for FAN-%d failed is detected", idx+1); + fan_status_state[idx]=FAN_STATUS_FAULT + else: + fan_status_state[idx]=FAN_STATUS_NORMAL + + return True + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + monitor = device_monitor(log_file, log_level) + while True: + monitor.manage_fan() + time.sleep(3) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor_psu.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor_psu.py new file mode 100755 index 000000000000..51837c7262ba --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_monitor_psu.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Accton Technology Corporation +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# ------------------------------------------------------------------ +# HISTORY: +# mm/dd/yyyy (A.D.) +# 7/2/2018: Jostar create for as7326-56x +# ------------------------------------------------------------------ + +try: + import os + import sys, getopt + import subprocess + import click + import imp + import logging + import logging.config + import logging.handlers + import types + import time # this is only being used as part of the example + import traceback + from tabulate import tabulate +except ImportError as e: + raise ImportError('%s - required module not found' % str(e)) + +# Deafults +VERSION = '1.0' +FUNCTION_NAME = '/usr/local/bin/accton_as5835_54t_monitor_psu' + +global log_file +global log_level + + +class switch(object): + def __init__(self, value): + self.value = value + self.fall = False + + def __iter__(self): + """Return the match method once, then stop""" + yield self.match + raise StopIteration + + def match(self, *args): + """Indicate whether or not to enter a case suite""" + if self.fall or not args: + return True + elif self.value in args: # changed for v1.5, see below + self.fall = True + return True + else: + return False + + +psu_state=[2, 2] +psu_power_status=[2, 2] +# Make a class we can use to capture stdout and sterr in the log +class device_monitor(object): + + def __init__(self, log_file, log_level): + + self.psu_num = 2 + self.psu_path = "/sys/bus/i2c/devices/" + self.presence = "/psu_present" + self.oper_status = "/psu_power_good" + self.mapping = { + 0: "11-0050", + 1: "12-0053", + } + + """Needs a logger and a logger level.""" + # set up logging to file + logging.basicConfig( + filename=log_file, + filemode='w', + level=log_level, + format= '[%(asctime)s] {%(pathname)s:%(lineno)d} %(levelname)s - %(message)s', + datefmt='%H:%M:%S' + ) + # set up logging to console + + if log_level == logging.DEBUG: + console = logging.StreamHandler() + console.setLevel(log_level) + formatter = logging.Formatter('%(name)-12s: %(levelname)-8s %(message)s') + console.setFormatter(formatter) + logging.getLogger('').addHandler(console) + + sys_handler = logging.handlers.SysLogHandler(address = '/dev/log') + #sys_handler.setLevel(logging.WARNING) + sys_handler.setLevel(logging.INFO) + logging.getLogger('').addHandler(sys_handler) + + #logging.debug('SET. logfile:%s / loglevel:%d', log_file, log_level) + + def manage_psu(self): + + PSU_STATE_REMOVE = 0 + PSU_STATE_INSERT = 1 + + PSU_STATUS_NO_POWER = 0 + PSU_STATUS_POWER_GOOD = 1 + + global psu_state + global psu_power_status + + for idx in range (0, self.psu_num): + node = self.psu_path + self.mapping[idx] + self.presence + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + if content == "1": + if psu_state[idx]!=PSU_STATE_INSERT: + psu_state[idx]=PSU_STATE_INSERT + logging.info("PSU-%d present is detected", idx+1); + #psu_power_status[idx]=PSU_STATUS_POWER_GOOD #when insert, assume power is good. If no_power, next code will find it. + else: + if psu_state[idx]!=PSU_STATE_REMOVE: + psu_state[idx]=PSU_STATE_REMOVE + logging.warning("Alarm for PSU-%d absent is detected", idx+1); + psu_power_status[idx]=PSU_STATUS_NO_POWER + + for idx in range (0, self.psu_num): + node = self.psu_path + self.mapping[idx] + self.oper_status + try: + val_file = open(node) + except IOError as e: + print "Error: unable to open file: %s" % str(e) + return False + content = val_file.readline().rstrip() + val_file.close() + # content is a string, either "0" or "1" + #logging.info("content=%s, psu_power_status[%d]=%d", content, idx, psu_power_status[idx]); + if content == "0": + if psu_power_status[idx]!=PSU_STATUS_NO_POWER: + if psu_state[idx]==PSU_STATE_INSERT: + logging.warning("Alarm for PSU-%d fault is detected", idx+1); + psu_power_status[idx]=PSU_STATUS_NO_POWER + else: + if psu_power_status[idx] !=PSU_STATUS_POWER_GOOD: + logging.info("PSU-%d power_good is detected", idx+1); + psu_power_status[idx]=PSU_STATUS_POWER_GOOD + + + return True + +def main(argv): + log_file = '%s.log' % FUNCTION_NAME + log_level = logging.INFO + if len(sys.argv) != 1: + try: + opts, args = getopt.getopt(argv,'hdl:',['lfile=']) + except getopt.GetoptError: + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + for opt, arg in opts: + if opt == '-h': + print 'Usage: %s [-d] [-l ]' % sys.argv[0] + return 0 + elif opt in ('-d', '--debug'): + log_level = logging.DEBUG + elif opt in ('-l', '--lfile'): + log_file = arg + monitor = device_monitor(log_file, log_level) + # Loop forever, doing something useful hopefully: + while True: + monitor.manage_psu() + time.sleep(3) + +if __name__ == '__main__': + main(sys.argv[1:]) diff --git a/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_util.py b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_util.py new file mode 100755 index 000000000000..a07ab1a1bc7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-accton/as5835-54t/utils/accton_as5835_54t_util.py @@ -0,0 +1,576 @@ +#!/usr/bin/env python +# +# Copyright (C) 2019 Accton Networks, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all systen status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import os +import commands +import sys, getopt +import logging +import re +import time +from collections import namedtuple + + + + +PROJECT_NAME = 'as5835_54t' +version = '0.1.0' +verbose = False +DEBUG = False +args = [] +ALL_DEVICE = {} +DEVICE_NO = {'led':5, 'fan':5,'thermal':4, 'psu':2, 'sfp':6} +FORCE = 0 +#logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +#logging.basicConfig(level=logging.INFO) + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(args)!=2: + show_eeprom_help() + elif int(args[1]) ==0 or int(args[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(args[1]) + return + elif arg == 'set': + if len(args)<3: + show_set_help() + else: + set_device(args[1:]) + return + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_set_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print cmd +" [led|sfp|fan]" + print " use \""+ cmd + " led 0-4 \" to set led color" + print " use \""+ cmd + " fan 0-100\" to set fan duty percetage" + print " use \""+ cmd + " sfp 49-54 {0|1}\" to set sfp# tx_disable" + sys.exit(0) + +def show_eeprom_help(): + cmd = sys.argv[0].split("/")[-1]+ " " + args[0] + print " use \""+ cmd + " 1-54 \" to dump sfp# eeprom" + sys.exit(0) + +def my_log(txt): + if DEBUG == True: + print "[Debug]"+txt + return + +def log_os_system(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + my_log (cmd +"with result:" + str(status)) + my_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +def driver_check(): + ret, lsmod = log_os_system("lsmod| grep accton", 0) + logging.info('mods:'+lsmod) + if len(lsmod) ==0: + return False + return True + + + +kos = [ +'modprobe i2c_dev', +'modprobe i2c_mux_pca954x force_deselect_on_exit=1', +'modprobe accton_as5835_54t_cpld' , +'modprobe ym2651y' , +'modprobe accton_as5835_54t_fan' , +'modprobe optoe' , +'modprobe accton_as5835_54t_leds' , +'modprobe accton_as5835_54t_psu' ] + +def driver_install(): + global FORCE + status, output = log_os_system("depmod", 1) + for i in range(0,len(kos)): + status, output = log_os_system(kos[i], 1) + if status: + if FORCE == 0: + return status + return 0 + +def driver_uninstall(): + global FORCE + for i in range(0,len(kos)): + rm = kos[-(i+1)].replace("modprobe", "modprobe -rq") + rm = rm.replace("insmod", "rmmod") + lst = rm.split(" ") + if len(lst) > 3: + del(lst[3]) + rm = " ".join(lst) + status, output = log_os_system(rm, 1) + if status: + if FORCE == 0: + return status + return 0 + +led_prefix ='/sys/class/leds/accton_'+PROJECT_NAME+'_led::' +hwmon_types = {'led': ['diag','fan','loc','psu1','psu2']} +hwmon_nodes = {'led': ['brightness'] } +hwmon_prefix ={'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = {'fan': ['3-0063'] , + 'thermal': ['18-004b','19-004c', '20-0049', '21-004a'] , + 'psu': ['11-0050','12-0053'], + 'sfp': ['-0050']} +i2c_nodes = {'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'] , + 'thermal': ['hwmon/hwmon*/temp1_input'] , + 'psu': ['psu_present ', 'psu_power_good'] , + 'sfp': ['module_present_', 'module_tx_disable_']} + +sfp_map = [28,29,26,30,31,27] + +qsfp_start = 48 + +mknod =[ +'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-1/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-2/new_device' , +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device' , +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device' , +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-1/new_device', + +'echo as5835_54t_fan 0x63 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-18/new_device', +'echo lm75 0x4c > /sys/bus/i2c/devices/i2c-19/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-20/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-21/new_device', +'echo as5835_54t_psu1 0x50 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo as5835_54t_psu2 0x53 > /sys/bus/i2c/devices/i2c-12/new_device', +'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-12/new_device', +'echo as5835_54t_cpld1 0x60 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo as5835_54t_cpld2 0x61 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo as5835_54t_cpld3 0x62 > /sys/bus/i2c/devices/i2c-3/new_device'] + +mknod2 =[ +'echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-0/new_device', +'echo pca9548 0x70 > /sys/bus/i2c/devices/i2c-2/new_device' , +'echo pca9548 0x71 > /sys/bus/i2c/devices/i2c-2/new_device' , +'echo pca9548 0x72 > /sys/bus/i2c/devices/i2c-2/new_device' , +'echo 24c02 0x57 > /sys/bus/i2c/devices/i2c-0/new_device', + +'echo as5835_54t_fan 0x63 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo lm75 0x4b > /sys/bus/i2c/devices/i2c-18/new_device', +'echo lm75 0x4c > /sys/bus/i2c/devices/i2c-19/new_device', +'echo lm75 0x49 > /sys/bus/i2c/devices/i2c-20/new_device', +'echo lm75 0x4a > /sys/bus/i2c/devices/i2c-21/new_device', +'echo as5835_54t_psu1 0x50 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo ym2401 0x58 > /sys/bus/i2c/devices/i2c-11/new_device', +'echo as5835_54t_psu2 0x53 > /sys/bus/i2c/devices/i2c-12/new_device', +'echo ym2401 0x5b > /sys/bus/i2c/devices/i2c-12/new_device', +'echo as5835_54t_cpld1 0x60 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo as5835_54t_cpld2 0x61 > /sys/bus/i2c/devices/i2c-3/new_device', +'echo as5835_54t_cpld3 0x62 > /sys/bus/i2c/devices/i2c-3/new_device'] + + +def i2c_order_check(): + # i2c bus 0 and 1 might be installed in different order. + # Here check if 0x77 is exist @ i2c-1 + tmp = "echo pca9548 0x77 > /sys/bus/i2c/devices/i2c-1/new_device" + status, output = log_os_system(tmp, 0) + if not device_exist(): + order = 1 + else: + order = 0 + tmp = "echo 0x77 > /sys/bus/i2c/devices/i2c-1/delete_device" + status, output = log_os_system(tmp, 0) + return order + +def device_install(): + global FORCE + + order = i2c_order_check() + + # if 0x77 is not exist @i2c-1, use reversed bus order + if order: + for i in range(0,len(mknod2)): + #for pca954x need times to built new i2c buses + if mknod2[i].find('pca954') != -1: + time.sleep(1) + + status, output = log_os_system(mknod2[i], 1) + time.sleep(0.01) + if status: + print output + if FORCE == 0: + return status + else: + for i in range(0,len(mknod)): + #for pca954x need times to built new i2c buses + if mknod[i].find('pca954') != -1: + time.sleep(1) + + status, output = log_os_system(mknod[i], 1) + if status: + print output + if FORCE == 0: + return status + for i in range(0,len(sfp_map)): + status, output =log_os_system("echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/new_device", 1) + if status: + print output + if FORCE == 0: + return status + path = "/sys/bus/i2c/devices/{0}-0050/port_name" + status, output =log_os_system("echo port{0} > ".format(i+49)+path.format(sfp_map[i]), 1) + if status: + print output + if FORCE == 0: + return status + return + +def device_uninstall(): + global FORCE + + status, output =log_os_system("ls /sys/bus/i2c/devices/0-0077", 0) + if status==0: + I2C_ORDER=1 + else: + I2C_ORDER=0 + + for i in range(0,len(sfp_map)): + target = "/sys/bus/i2c/devices/i2c-"+str(sfp_map[i])+"/delete_device" + status, output =log_os_system("echo 0x50 > "+ target, 1) + if status: + print output + if FORCE == 0: + return status + + if I2C_ORDER==0: + nodelist = mknod + else: + nodelist = mknod2 + + for i in range(len(nodelist)): + target = nodelist[-(i+1)] + temp = target.split() + del temp[1] + temp[-1] = temp[-1].replace('new_device', 'delete_device') + status, output = log_os_system(" ".join(temp), 1) + if status: + print output + if FORCE == 0: + return status + + return + +def system_ready(): + if driver_check() == False: + return False + if not device_exist(): + return False + return True + +def do_install(): + print "Checking system...." + if driver_check() == False: + print "No driver, installing...." + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" drivers detected...." + if not device_exist(): + print "No device, installing...." + status = device_install() + if status: + if FORCE == 0: + return status + else: + print PROJECT_NAME.upper()+" devices detected...." + return + +def do_uninstall(): + print "Checking system...." + if not device_exist(): + print PROJECT_NAME.upper() +" has no device installed...." + else: + print "Removing device...." + status = device_uninstall() + if status: + if FORCE == 0: + return status + + if driver_check()== False : + print PROJECT_NAME.upper() +" has no driver installed...." + else: + print "Removing installed driver...." + status = driver_uninstall() + if status: + if FORCE == 0: + return status + + return + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key]= {} + for i in range(0,DEVICE_NO[key]): + ALL_DEVICE[key][key+str(i+1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0,len(buses)): + for j in range(0,len(nodes)): + if 'fan' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ buses[i]+"/fan"+str(k+1)+"_"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0,DEVICE_NO[key]): + node = key+str(k+1) + path = i2c_prefix+ str(sfp_map[k])+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + else: + node = key+str(i+1) + path = i2c_prefix+ buses[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0,len(itypes)): + for j in range(0,len(nodes)): + node = key+"_"+itypes[i] + path = hwmon_prefix[key]+ itypes[i]+"/"+ nodes[j] + my_log(node+": "+ path) + ALL_DEVICE[key][ key+str(i+1)].append(path) + + #show dict all in the order + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i+": ") + for j in sorted(ALL_DEVICE[i].keys()): + print(" "+j) + for k in (ALL_DEVICE[i][j]): + print(" "+" "+k) + return + +def show_eeprom(index): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + node = ALL_DEVICE['sfp'] ['sfp'+str(index)][0] + node = node.replace(node.split("/")[-1], 'sfp_eeprom') + # check if got hexdump command in current environment + ret, log = log_os_system("which hexdump", 0) + ret, log2 = log_os_system("which busybox hexdump", 0) + if len(log): + hex_cmd = 'hexdump' + elif len(log2): + hex_cmd = ' busybox hexdump' + else: + log = 'Failed : no hexdump cmd!!' + logging.info(log) + print log + return 1 + + print node + ":" + ret, log = log_os_system("cat "+node+"| "+hex_cmd+" -C", 1) + if ret==0: + print log + else: + print "**********device no found**********" + return + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + + if args[0]=='led': + if int(args[1])>4: + show_set_help() + return + #print ALL_DEVICE['led'] + for i in range(0,len(ALL_DEVICE['led'])): + for k in (ALL_DEVICE['led']['led'+str(i+1)]): + ret, log = log_os_system("echo "+args[1]+" >"+k, 1) + if ret: + return ret + elif args[0]=='fan': + if int(args[1])>100: + show_set_help() + return + #print ALL_DEVICE['fan'] + #fan1~5 is all fine, all fan share same setting + node = ALL_DEVICE['fan'] ['fan1'][0] + node = node.replace(node.split("/")[-1], 'fan_duty_cycle_percentage') + ret, log = log_os_system("cat "+ node, 1) + if ret==0: + print ("Previous fan duty: " + log.strip() +"%") + ret, log = log_os_system("echo "+args[1]+" >"+node, 1) + if ret==0: + print ("Current fan duty: " + args[1] +"%") + return ret + elif args[0]=='sfp': + if int(args[1])> DEVICE_NO[args[0]] or int(args[1])==0: + show_set_help() + return + if len(args)<2: + show_set_help() + return + + if int(args[2])>1: + show_set_help() + return + + #print ALL_DEVICE[args[0]] + for i in range(0,len(ALL_DEVICE[args[0]])): + for j in ALL_DEVICE[args[0]][args[0]+str(args[1])]: + if j.find('tx_disable')!= -1: + ret, log = log_os_system("echo "+args[2]+" >"+ j, 1) + if ret: + return ret + + return + +#get digits inside a string. +#Ex: 31 for "sfp31" +def get_value(input): + digit = re.findall('\d+', input) + return int(digit[0]) + +def device_traversal(): + if system_ready()==False: + print("System's not ready.") + print("Please install first!") + return + + if len(ALL_DEVICE)==0: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print("============================================") + print(i.upper()+": ") + print("============================================") + + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print " "+j+":", + for k in (ALL_DEVICE[i][j]): + ret, log = log_os_system("cat "+k, 0) + func = k.split("/")[-1].strip() + func = re.sub(j+'_','',func,1) + func = re.sub(i.lower()+'_','',func,1) + if ret==0: + print func+"="+log+" ", + else: + print func+"="+"X"+" ", + print + print("----------------------------------------------------------------") + + + print + return + +def device_exist(): + ret1, log = log_os_system("ls "+i2c_prefix+"*0077", 0) + ret2, log = log_os_system("ls "+i2c_prefix+"i2c-2", 0) + return not(ret1 or ret2) + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/control b/platform/broadcom/sonic-platform-modules-accton/debian/control index b22828af67c5..8100f6b76e16 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/control +++ b/platform/broadcom/sonic-platform-modules-accton/debian/control @@ -1,7 +1,7 @@ Source: sonic-accton-platform-modules Section: main Priority: extra -Maintainer: Accton network , Accton Network , Accton Network +Maintainer: Accton network , Accton Network , Accton Network , Accton Network Build-Depends: debhelper (>= 9), bzip2 Standards-Version: 3.9.3 @@ -61,3 +61,6 @@ Package: sonic-platform-accton-as9716-32d Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp +Package: sonic-platform-accton-as5835-54t +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-accton/debian/rules b/platform/broadcom/sonic-platform-modules-accton/debian/rules index e570be68be65..ba2f3e394d1d 100755 --- a/platform/broadcom/sonic-platform-modules-accton/debian/rules +++ b/platform/broadcom/sonic-platform-modules-accton/debian/rules @@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-accton KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x as5835-54x as9716-32d +MODULE_DIRS:= as7712-32x as5712-54x as7816-64x as7716-32x as7716-32xb as7312-54x as7326-56x as6712-32x as7726-32x as4630-54pe minipack as5812-54x as5835-54x as9716-32d as5835-54t MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service