DellEMC: Initial commit for S5224F platform support (#8717)

Why I did it
Added support for the device S5224F

How I did it
Implemented the support for the platform S5224F
Switch Vendor: DellEMC
Switch SKU: S5224F-ON
ASIC Vendor: Broadcom
SONiC Image: sonic-broadcom.bin

How to verify it
Verified the show platform/interface commands
This commit is contained in:
arunlk-dell 2021-09-26 22:04:16 +05:30 committed by GitHub
parent b0b0ba828a
commit c668f2ab5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
52 changed files with 6677 additions and 1 deletions

View File

@ -0,0 +1,2 @@
{%- set default_topo = 't1' %}
{%- include 'buffers_config.j2' %}

View File

@ -0,0 +1,37 @@
{%- set default_cable = '5m' %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "26531072",
"type": "ingress",
"mode": "dynamic",
"xoff": "6291456"
},
"egress_lossless_pool": {
"size": "32822528",
"type": "egress",
"mode": "static"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "static",
"static_th":"32822528"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "dynamic",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,37 @@
{%- set default_cable = '40m' %}
{%- macro generate_buffer_pool_and_profiles() %}
"BUFFER_POOL": {
"ingress_lossless_pool": {
"size": "26531072",
"type": "ingress",
"mode": "dynamic",
"xoff": "6291456"
},
"egress_lossless_pool": {
"size": "32822528",
"type": "egress",
"mode": "static"
}
},
"BUFFER_PROFILE": {
"ingress_lossy_profile": {
"pool":"[BUFFER_POOL|ingress_lossless_pool]",
"size":"0",
"dynamic_th":"3"
},
"egress_lossless_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "static",
"static_th":"32822528"
},
"egress_lossy_profile": {
"pool":"[BUFFER_POOL|egress_lossless_pool]",
"size":"0",
"mode": "dynamic",
"dynamic_th":"3"
}
},
{%- endmacro %}

View File

@ -0,0 +1,17 @@
# PG lossless profiles.
# speed cable size xon xoff threshold xon_offset
10000 5m 1024 2048 46080 -3 2048
25000 5m 1024 2048 65024 -3 2048
40000 5m 1024 2048 77056 -3 2048
50000 5m 1024 2048 93440 -3 2048
100000 5m 1024 2048 162048 -3 2048
10000 40m 1024 2048 47360 -3 2048
25000 40m 1024 2048 67840 -3 2048
40000 40m 1024 2048 81664 -3 2048
50000 40m 1024 2048 99072 -3 2048
100000 40m 1024 2048 173568 -3 2048
10000 300m 1024 2048 57088 -3 2048
25000 300m 1024 2048 92672 -3 2048
40000 300m 1024 2048 121344 -3 2048
50000 300m 1024 2048 148736 -3 2048
100000 300m 1024 2048 272640 -3 2048

View File

@ -0,0 +1,29 @@
# name lanes alias index speed
Ethernet0 21 twentyfiveGigE1/1 1 25000
Ethernet1 22 twentyfiveGigE1/2 2 25000
Ethernet2 23 twentyfiveGigE1/3 3 25000
Ethernet3 24 twentyfiveGigE1/4 4 25000
Ethernet4 25 twentyfiveGigE1/5 5 25000
Ethernet5 26 twentyfiveGigE1/6 6 25000
Ethernet6 27 twentyfiveGigE1/7 7 25000
Ethernet7 28 twentyfiveGigE1/8 8 25000
Ethernet8 29 twentyfiveGigE1/9 9 25000
Ethernet9 30 twentyfiveGigE1/10 10 25000
Ethernet10 31 twentyfiveGigE1/11 11 25000
Ethernet11 32 twentyfiveGigE1/12 12 25000
Ethernet12 49 twentyfiveGigE1/13 13 25000
Ethernet13 50 twentyfiveGigE1/14 14 25000
Ethernet14 51 twentyfiveGigE1/15 15 25000
Ethernet15 52 twentyfiveGigE1/16 16 25000
Ethernet16 53 twentyfiveGigE1/17 17 25000
Ethernet17 54 twentyfiveGigE1/18 18 25000
Ethernet18 55 twentyfiveGigE1/19 19 25000
Ethernet19 56 twentyfiveGigE1/20 20 25000
Ethernet20 57 twentyfiveGigE1/21 21 25000
Ethernet21 58 twentyfiveGigE1/22 22 25000
Ethernet22 59 twentyfiveGigE1/23 23 25000
Ethernet23 60 twentyfiveGigE1/24 24 25000
Ethernet24 33,34,35,36 hundredGigE1/25 25 100000
Ethernet28 37,38,39,40 hundredGigE1/26 26 100000
Ethernet32 41,42,43,44 hundredGigE1/27 27 100000
Ethernet36 45,46,47,48 hundredGigE1/28 28 100000

View File

@ -0,0 +1 @@
{%- include 'qos_config.j2' %}

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-s5224f-25g.config.bcm

View File

@ -0,0 +1,2 @@
m0 load 0 0x0 /usr/share/sonic/hwsku/linkscan_led_fw.bin
m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin

View File

@ -0,0 +1,237 @@
os=unix
portmap_1.0=21:25
portmap_2.0=22:25
portmap_3.0=23:25
portmap_4.0=24:25
portmap_5.0=25:25
portmap_6.0=26:25
portmap_7.0=27:25
portmap_8.0=28:25
portmap_9.0=29:25
portmap_10.0=30:25
portmap_11.0=31:25
portmap_12.0=32:25
portmap_13.0=33:100
portmap_17.0=37:100
portmap_47.0=41:100
portmap_51.0=45:100
portmap_35.0=49:25
portmap_36.0=50:25
portmap_37.0=51:25
portmap_38.0=52:25
portmap_39.0=53:25
portmap_40.0=54:25
portmap_41.0=55:25
portmap_42.0=56:25
portmap_43.0=57:25
portmap_44.0=58:25
portmap_45.0=59:25
portmap_46.0=60:25
phy_chain_tx_lane_map_physical{21.0}=0x0123
phy_chain_rx_lane_map_physical{21.0}=0x1032
phy_chain_tx_lane_map_physical{25.0}=0x0123
phy_chain_rx_lane_map_physical{25.0}=0x1032
phy_chain_tx_lane_map_physical{29.0}=0x0123
phy_chain_rx_lane_map_physical{29.0}=0x1032
phy_chain_tx_lane_map_physical{33.0}=0x0132
phy_chain_rx_lane_map_physical{33.0}=0x1302
phy_chain_tx_lane_map_physical{37.0}=0x2310
phy_chain_rx_lane_map_physical{37.0}=0x3201
phy_chain_tx_lane_map_physical{41.0}=0x3210
phy_chain_rx_lane_map_physical{41.0}=0x1032
phy_chain_tx_lane_map_physical{45.0}=0x2031
phy_chain_rx_lane_map_physical{45.0}=0x1320
phy_chain_tx_lane_map_physical{49.0}=0x3210
phy_chain_rx_lane_map_physical{49.0}=0x2301
phy_chain_tx_lane_map_physical{53.0}=0x3210
phy_chain_rx_lane_map_physical{53.0}=0x2301
phy_chain_tx_lane_map_physical{57.0}=0x3210
phy_chain_rx_lane_map_physical{57.0}=0x2301
phy_chain_tx_polarity_flip_physical{21.0}=0x0
phy_chain_rx_polarity_flip_physical{21.0}=0x1
phy_chain_tx_polarity_flip_physical{22.0}=0x1
phy_chain_rx_polarity_flip_physical{22.0}=0x0
phy_chain_tx_polarity_flip_physical{23.0}=0x0
phy_chain_rx_polarity_flip_physical{23.0}=0x1
phy_chain_tx_polarity_flip_physical{24.0}=0x1
phy_chain_rx_polarity_flip_physical{24.0}=0x0
phy_chain_tx_polarity_flip_physical{25.0}=0x0
phy_chain_rx_polarity_flip_physical{25.0}=0x1
phy_chain_tx_polarity_flip_physical{26.0}=0x1
phy_chain_rx_polarity_flip_physical{26.0}=0x0
phy_chain_tx_polarity_flip_physical{27.0}=0x0
phy_chain_rx_polarity_flip_physical{27.0}=0x1
phy_chain_tx_polarity_flip_physical{28.0}=0x1
phy_chain_rx_polarity_flip_physical{28.0}=0x0
phy_chain_tx_polarity_flip_physical{29.0}=0x0
phy_chain_rx_polarity_flip_physical{29.0}=0x1
phy_chain_tx_polarity_flip_physical{30.0}=0x1
phy_chain_rx_polarity_flip_physical{30.0}=0x0
phy_chain_tx_polarity_flip_physical{31.0}=0x0
phy_chain_rx_polarity_flip_physical{31.0}=0x1
phy_chain_tx_polarity_flip_physical{32.0}=0x1
phy_chain_rx_polarity_flip_physical{32.0}=0x0
phy_chain_tx_polarity_flip_physical{33.0}=0x1
phy_chain_rx_polarity_flip_physical{33.0}=0x0
phy_chain_tx_polarity_flip_physical{34.0}=0x0
phy_chain_rx_polarity_flip_physical{34.0}=0x1
phy_chain_tx_polarity_flip_physical{35.0}=0x1
phy_chain_rx_polarity_flip_physical{35.0}=0x1
phy_chain_tx_polarity_flip_physical{36.0}=0x1
phy_chain_rx_polarity_flip_physical{36.0}=0x1
phy_chain_tx_polarity_flip_physical{37.0}=0x0
phy_chain_rx_polarity_flip_physical{37.0}=0x1
phy_chain_tx_polarity_flip_physical{38.0}=0x1
phy_chain_rx_polarity_flip_physical{38.0}=0x0
phy_chain_tx_polarity_flip_physical{39.0}=0x1
phy_chain_rx_polarity_flip_physical{39.0}=0x0
phy_chain_tx_polarity_flip_physical{40.0}=0x0
phy_chain_rx_polarity_flip_physical{40.0}=0x0
phy_chain_tx_polarity_flip_physical{41.0}=0x0
phy_chain_rx_polarity_flip_physical{41.0}=0x0
phy_chain_tx_polarity_flip_physical{42.0}=0x1
phy_chain_rx_polarity_flip_physical{42.0}=0x1
phy_chain_tx_polarity_flip_physical{43.0}=0x1
phy_chain_rx_polarity_flip_physical{43.0}=0x0
phy_chain_tx_polarity_flip_physical{44.0}=0x1
phy_chain_rx_polarity_flip_physical{44.0}=0x1
phy_chain_tx_polarity_flip_physical{45.0}=0x0
phy_chain_rx_polarity_flip_physical{45.0}=0x0
phy_chain_tx_polarity_flip_physical{46.0}=0x0
phy_chain_rx_polarity_flip_physical{46.0}=0x1
phy_chain_tx_polarity_flip_physical{47.0}=0x0
phy_chain_rx_polarity_flip_physical{47.0}=0x1
phy_chain_tx_polarity_flip_physical{48.0}=0x1
phy_chain_rx_polarity_flip_physical{48.0}=0x1
phy_chain_tx_polarity_flip_physical{49.0}=0x0
phy_chain_rx_polarity_flip_physical{49.0}=0x1
phy_chain_tx_polarity_flip_physical{50.0}=0x1
phy_chain_rx_polarity_flip_physical{50.0}=0x0
phy_chain_tx_polarity_flip_physical{51.0}=0x0
phy_chain_rx_polarity_flip_physical{51.0}=0x1
phy_chain_tx_polarity_flip_physical{52.0}=0x1
phy_chain_rx_polarity_flip_physical{52.0}=0x0
phy_chain_tx_polarity_flip_physical{53.0}=0x0
phy_chain_rx_polarity_flip_physical{53.0}=0x1
phy_chain_tx_polarity_flip_physical{54.0}=0x1
phy_chain_rx_polarity_flip_physical{54.0}=0x0
phy_chain_tx_polarity_flip_physical{55.0}=0x0
phy_chain_rx_polarity_flip_physical{55.0}=0x1
phy_chain_tx_polarity_flip_physical{56.0}=0x1
phy_chain_rx_polarity_flip_physical{56.0}=0x0
phy_chain_tx_polarity_flip_physical{57.0}=0x0
phy_chain_rx_polarity_flip_physical{57.0}=0x1
phy_chain_tx_polarity_flip_physical{58.0}=0x1
phy_chain_rx_polarity_flip_physical{58.0}=0x0
phy_chain_tx_polarity_flip_physical{59.0}=0x0
phy_chain_rx_polarity_flip_physical{59.0}=0x1
phy_chain_tx_polarity_flip_physical{60.0}=0x1
phy_chain_rx_polarity_flip_physical{60.0}=0x0
dport_map_port_1=1
dport_map_port_2=2
dport_map_port_3=3
dport_map_port_4=4
dport_map_port_5=5
dport_map_port_6=6
dport_map_port_7=7
dport_map_port_8=8
dport_map_port_9=9
dport_map_port_10=10
dport_map_port_11=11
dport_map_port_12=12
dport_map_port_35=13
dport_map_port_36=14
dport_map_port_37=15
dport_map_port_38=16
dport_map_port_39=17
dport_map_port_40=18
dport_map_port_41=19
dport_map_port_42=20
dport_map_port_43=21
dport_map_port_44=22
dport_map_port_45=23
dport_map_port_46=24
dport_map_port_13=25
dport_map_port_14=26
dport_map_port_15=27
dport_map_port_16=28
dport_map_port_17=29
dport_map_port_18=30
dport_map_port_19=31
dport_map_port_20=32
dport_map_port_47=33
dport_map_port_48=34
dport_map_port_49=35
dport_map_port_50=36
dport_map_port_51=37
dport_map_port_52=38
dport_map_port_53=39
dport_map_port_54=40
dpp_clock_ratio=2:3
oversubscribe_mode=1
core_clock_frequency=1525
pbmp_oversubscribe=0x7fff9fffffffffffffffe
pbmp_xport_xe=0x7fff9fffffffffffffffe
port_flex_enable=1
phy_an_c73=3
l2xmsg_mode=1
#Need for mac learn scale
l2xmsg_hostbuf_size=16384
module_64ports=0
#Interrupts and Parity
max_vp_lags=0
schan_intr_enable=0
tdma_timeout_usec=5000000
# Following added by BRCM
stable_size=0x5500000
#Default L3 profile
l2_mem_entries=32768
l3_alpm_enable=2
l3_alpm_ipv6_128b_bkt_rsvd=1
#check correct value
l2_mem_entries=40960
l3_mem_entries=40960
#Tunnels
use_all_splithorizon_groups=1
sai_tunnel_support=1
bcm_tunnel_term_compatible_mode=1
ptp_ts_pll_fref=50000000
ptp_bs_fref_0=50000000
ptp_bs_fref_1=50000000
#RIOT Enable
riot_enable=1
riot_overlay_l3_intf_mem_size=8192
riot_overlay_l3_egress_mem_size=32768
l3_ecmp_levels=2
riot_overlay_ecmp_resilient_hash_size=16384
sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc
#New Additions
pfc_deadlock_seq_control=1
#Common configs from broadcom/x86_64-broadcom_common/x86_64-broadcom_b77/broadcom-sonic-td3.config.bcm (Lower version of Td3 (0xb771))
mem_cache_enable=0
ifp_inports_support_enable=1
ipv6_lpm_128b_enable=0x1
l3_max_ecmp_mode=1
lpm_scaling_enable=0
bcm_num_cos=10
default_cpu_tx_queue=9
mmu_lossless=0
host_as_route_disable=1
sai_eapp_config_file=/etc/broadcom/eapps_cfg.json
sai_fast_convergence_support=1
flow_init_mode=1
sai_load_hw_config=/usr/lib/cancun/

View File

@ -0,0 +1 @@
DellEMC-S5224f-P-25G t1

View File

@ -0,0 +1,2 @@
CONSOLE_PORT=0x3f8
CONSOLE_DEV=0

View File

@ -0,0 +1,6 @@
# LED microprocessor initialization for Dell S5224
#
#
#Led0
led auto on
led start

View File

@ -0,0 +1,446 @@
{
"GLOBAL_MEDIA_SETTINGS": {
"1-24": {
"(.*-C6Y7M)|(.*-V250M)|(.*-05CWK6)|(.*-53HVN)|(.*-358VV)|(.*-MV799)|(.*-59970000.)|(.*-P4YPY)|(.*-TCPM2)|(.*-JNPF8)|(.*-27GG5)|(.*-P8T4W)|(.*-JR54Y)|(.*-L56[SQ]F0..-SD-R)|(.*-61676000.)|(.*-74752.*)|(SFP\\+-CR-.*)": {
"preemphasis": {
"lane0": "0x19410a"
}
},
"(.*-58KM3)|(.*-2JVDD)|(.*-26FN3)|(SFP28-CR-((0\\.5)|(1\\.0)|(0\\.0)|(N/A)))": {
"preemphasis": {
"lane0": "0x19410a"
}
},
"(.*-D0R73)|(.*-YFNDD)|(SFP28-CR-2\\.0)": {
"preemphasis": {
"lane0": "0x19410a"
}
},
"(.*-VXFJY)|(.*-9X8JP)|(.*-7R9N9)|(SFP28-CR-.*)": {
"preemphasis": {
"lane0": "0x19410a"
}
}
},
"25-28": {
"QSFP\\+-CR-.*": {
"preemphasis": {
"lane0": "0x18420a",
"lane1": "0x18420a",
"lane2": "0x18420a",
"lane3": "0x18420a"
}
},
"(.*-035KG)|(.*-P7C7N)|(QSFP28-CR-((0\\.5)|(1\\.0)|(0\\.0)|(N/A)))": {
"preemphasis": {
"lane0": "0x18420a",
"lane1": "0x18420a",
"lane2": "0x18420a",
"lane3": "0x18420a"
}
},
"(.*-76V43)|(QSFP28-CR-2\\.0)": {
"preemphasis": {
"lane0": "0x18420a",
"lane1": "0x18420a",
"lane2": "0x18420a",
"lane3": "0x18420a"
}
},
"(.*-3CC35)|(.*-FN4FC)|(QSFP28-CR-.*)": {
"preemphasis": {
"lane0": "0x18420a",
"lane1": "0x18420a",
"lane2": "0x18420a",
"lane3": "0x18420a"
}
}
}
},
"PORT_MEDIA_SETTINGS": {
"1": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x0b3c02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x14460a"
}
}
},
"2": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x0b3c02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x14460a"
}
}
},
"3": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x0a3b02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x14460a"
}
}
},
"4": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x0a3b02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x14460a"
}
}
},
"5": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x0a3b02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x14460a"
}
}
},
"6": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x093a02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"7": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"8": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"9": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"10": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"11": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073702"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x124909"
}
}
},
"12": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073702"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x124909"
}
}
},
"13": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x093a02"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"14": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"15": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"16": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"17": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"18": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"19": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x083902"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"20": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"21": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"22": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"23": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"24": {
"(.*-WTRD1)|(.*-RN84N)|(.*-DT87G)|(.*-HMTNW)|(.*-1F80G)|(.*-6K3Y6)|(.*-YJF03)|(.*-P9GND)|(.*-T1KCN)|(.*-1DXKP)|(.*-MT7R2)|(.*-C4DD6)|(.*-8JHPY)|(.*-PGYJT)|(.*-FCBG110SD1C)|(.*-FCCG125SD1C)|(SFP\\+-.*)": {
"preemphasis": {
"lane0": "0x073802"
}
},
"(.*-P7D7R)|(.*-W4GPP)|(.*-07RN7)|(.*-3YWG7)|(.*-5CMT2)|(.*-FTLF8540P4BCL)|(SFP28-.*)": {
"preemphasis": {
"lane0": "0x13470a"
}
}
},
"25": {
"(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": {
"preemphasis": {
"lane0": "0x114b08",
"lane1": "0x114b08",
"lane2": "0x114b08",
"lane3": "0x114b08"
}
},
"QSFP\\+-.*": {
"preemphasis": {
"lane0": "0x114b08",
"lane1": "0x114b08",
"lane2": "0x114b08",
"lane3": "0x114b08"
}
}
},
"26": {
"(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": {
"preemphasis": {
"lane0": "0x0f4d08",
"lane1": "0x0f4d08",
"lane2": "0x0f4d08",
"lane3": "0x0f4d08"
}
},
"QSFP\\+-.*": {
"preemphasis": {
"lane0": "0x0f4d08",
"lane1": "0x0f4d08",
"lane2": "0x0f4d08",
"lane3": "0x0f4d08"
}
}
},
"27": {
"(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": {
"preemphasis": {
"lane0": "0x0e4f07",
"lane1": "0x0e4f07",
"lane2": "0x0e4f07",
"lane3": "0x0e4f07"
}
},
"QSFP\\+-.*": {
"preemphasis": {
"lane0": "0x0e4f07",
"lane1": "0x0e4f07",
"lane2": "0x0e4f07",
"lane3": "0x0e4f07"
}
}
},
"28": {
"(.*-14NV5)|(.*-D7P80)|(.*-THPF3)|(.*-X7CCC)|(.*-YKMH7)|(.*-0X9CT)|(.*-05J8P)|(.*-5WGKD)|(.*-XFDRT)|(.*-1002971101)|(QSFP28-.*)": {
"preemphasis": {
"lane0": "0x0f4d08",
"lane1": "0x0f4d08",
"lane2": "0x0f4d08",
"lane3": "0x0f4d08"
}
},
"QSFP\\+-.*": {
"preemphasis": {
"lane0": "0x0f4d08",
"lane1": "0x0f4d08",
"lane2": "0x0f4d08",
"lane3": "0x0f4d08"
}
}
}
}
}

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python
#############################################################################
# DellEMC S5224f
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
import os.path
try:
from sonic_eeprom import eeprom_tlvinfo
except ImportError as e:
raise ImportError (str(e) + "- required module not found")
class board(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self, name, path, cpld_root, ro):
self.eeprom_path = None
for b in (0, 1):
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
if os.path.exists(f):
self.eeprom_path = f
break
if self.eeprom_path is None:
return
super(board, self).__init__(self.eeprom_path, 0, '', True)

View File

@ -0,0 +1,21 @@
- bus: '03'
dev: '00'
fn: '0'
id: '1533'
name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev
03)'
- bus: '02'
dev: '00'
fn: '0'
id: b771
name: 'Ethernet controller: Broadcom Limited Device b771 (rev 01)'
- bus: '04'
dev: '00'
fn: '0'
id: '7021'
name: 'Non-VGA unclassified device: Xilinx Corporation Device 7021'
- bus: '00'
dev: '14'
fn: '0'
id: 19c2
name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)'

View File

@ -0,0 +1,97 @@
#
# psuutil.py
# Platform-specific PSU status interface for SONiC
#
import logging
import sys
import subprocess
S5224F_MAX_PSUS = 2
IPMI_PSU_DATA = "docker exec -it pmon ipmitool sdr list"
IPMI_PSU_DATA_DOCKER = "ipmitool sdr list"
PSU_PRESENCE = "PSU{0}_stat"
# Use this for older firmware
# PSU_PRESENCE="PSU{0}_prsnt"
ipmi_sdr_list = ""
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)
def isDockerEnv(self):
num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker")
if num_docker > 0:
return True
else:
return False
# Fetch a BMC register
def get_pmc_register(self, reg_name):
global ipmi_sdr_list
ipmi_cmd = IPMI_PSU_DATA
dockerenv = self.isDockerEnv()
if dockerenv == True:
ipmi_cmd = IPMI_PSU_DATA_DOCKER
status, ipmi_sdr_list = subprocess.getstatusoutput(ipmi_cmd)
if status:
logging.error('Failed to execute:' + ipmi_sdr_list)
sys.exit(0)
for item in ipmi_sdr_list.split("\n"):
if reg_name in item:
output = item.strip()
if not output:
print('\nFailed to fetch: ' + reg_name + ' sensor ')
sys.exit(0)
output = output.split('|')[1]
logging.basicConfig(level=logging.DEBUG)
return output
def get_num_psus(self):
"""
Retrieves the number of PSUs available on the device
:return: An integer, the number of PSUs available on the device
"""
S5224F_MAX_PSUS = 2
return S5224F_MAX_PSUS
def get_psu_status(self, index):
"""
Retrieves the oprational status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is operating properly, False if PSU is\
faulty
"""
# Until psu_status is implemented this is hardcoded temporarily
status = 1
return status
def get_psu_presence(self, index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
cmd_status, psu_status = subprocess.getstatusoutput('ipmitool raw 0x04 0x2d ' + hex(0x30 + index) + " | awk '{print substr($0,9,1)}'")
return 1 if psu_status == '1' else 0

View File

@ -0,0 +1,550 @@
# sfputil.py
#
# Platform-specific SFP transceiver interface for SONiC
#
# For S5224F-ON, hardware version X01
try:
import struct
import time
from sonic_sfp.sfputilbase import SfpUtilBase
from os import *
from mmap import *
import io
from sonic_sfp.sff8436 import sff8436InterfaceId
from sonic_sfp.sff8436 import sff8436Dom
from sonic_sfp.sff8472 import sff8472Dom
except ImportError as e:
raise ImportError("%s - required module not found" % str(e))
#definitions of the offset and width for values in DOM info eeprom
QSFP_DOM_REV_OFFSET = 1
QSFP_DOM_REV_WIDTH = 1
QSFP_TEMPE_OFFSET = 22
QSFP_TEMPE_WIDTH = 2
QSFP_VOLT_OFFSET = 26
QSFP_VOLT_WIDTH = 2
QSFP_CHANNL_MON_OFFSET = 34
QSFP_CHANNL_MON_WIDTH = 16
QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24
QSFP_MODULE_THRESHOLD_OFFSET = 128
QSFP_MODULE_THRESHOLD_WIDTH = 24
QSFP_CHANNL_THRESHOLD_OFFSET = 176
QSFP_CHANNL_THRESHOLD_WIDTH = 16
QSFP_CHANNL_MON_MASK_OFFSET = 242
QSFP_CHANNL_MON_MASK_WIDTH = 4
SFP_TEMPE_OFFSET = 96
SFP_TEMPE_WIDTH = 2
SFP_VOLT_OFFSET = 98
SFP_VOLT_WIDTH = 2
SFP_MODULE_THRESHOLD_OFFSET = 0
SFP_MODULE_THRESHOLD_WIDTH = 56
XCVR_DOM_CAPABILITY_OFFSET = 92
XCVR_DOM_CAPABILITY_WIDTH = 1
class SfpUtil(SfpUtilBase):
"""Platform-specific SfpUtil class"""
PORT_START = 1
PORT_END = 28
PORTS_IN_BLOCK = 28
BASE_RES_PATH = "/sys/bus/pci/devices/0000:04:00.0/resource0"
_port_to_eeprom_mapping = {}
_global_port_pres_dict = {}
@property
def port_start(self):
return self.PORT_START
@property
def port_end(self):
return self.PORT_END
@property
def qsfp_ports(self):
return range(25, self.PORTS_IN_BLOCK + 1)
@property
def port_to_eeprom_mapping(self):
return self._port_to_eeprom_mapping
def pci_mem_read(self, mm, offset):
mm.seek(offset)
read_data_stream=mm.read(4)
reg_val=struct.unpack('I',read_data_stream)
mem_val = str(reg_val)[1:-2]
# print "reg_val read:%x"%reg_val
return mem_val
def pci_mem_write(self, mm, offset, data):
mm.seek(offset)
# print "data to write:%x"%data
mm.write(struct.pack('I',data))
def pci_set_value(self, resource, val, offset):
fd = open(resource, O_RDWR)
mm = mmap(fd, 0)
val = self.pci_mem_write(mm, offset, val)
mm.close()
close(fd)
return val
def pci_get_value(self, resource, offset):
fd = open(resource, O_RDWR)
mm = mmap(fd, 0)
val = self.pci_mem_read(mm, offset)
mm.close()
close(fd)
return val
def init_global_port_presence(self):
for port_num in range(self.port_start, (self.port_end + 1)):
presence = self.get_presence(port_num)
if(presence):
self._global_port_pres_dict[port_num] = '1'
else:
self._global_port_pres_dict[port_num] = '0'
def __init__(self):
eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for x in range(self.port_start, self.port_end + 1):
self.port_to_eeprom_mapping[x] = eeprom_path.format(x + 1)
self.init_global_port_presence()
SfpUtilBase.__init__(self)
def get_presence(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4004
port_offset = 16388 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off bit for presence
mask = (1 << 0)
if (port_num > 24):
mask = (1 << 4)
# ModPrsL is active low
if reg_value & mask == 0:
return True
return False
def get_low_power_mode(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off 4th bit for presence
mask = (1 << 6)
# LPMode is active high
if reg_value & mask == 0:
return False
return True
def set_low_power_mode(self, port_num, lpmode):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off 4th bit for presence
mask = (1 << 6)
# LPMode is active high; set or clear the bit accordingly
if lpmode is True:
reg_value = reg_value | mask
else:
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
if status != reg_value:
print ("Error: Set LP mode status %d", status)
return True
def reset(self, port_num):
# Check for invalid port_num
if port_num < self.port_start or port_num > self.port_end:
return False
# Port offset starts with 0x4000
port_offset = 16384 + ((port_num-1) * 16)
status = self.pci_get_value(self.BASE_RES_PATH, port_offset)
reg_value = int(status)
# Absence of status throws error
if (reg_value == "" ):
return False
# Mask off 4th bit for presence
mask = (1 << 6)
# ResetL is active low
reg_value = reg_value & ~mask
# Convert our register value back to a hex string and write back
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
if status != reg_value:
print ("Error: pci_set_value reset status %d", status)
# Sleep 1 second to allow it to settle
time.sleep(1)
reg_value = reg_value | mask
# Convert our register value back to a hex string and write back
status = self.pci_set_value(self.BASE_RES_PATH, reg_value, port_offset)
if status != reg_value:
print ("Error: pci_set_value reset status %d", status)
return True
def get_transceiver_change_event(self, timeout=0):
port_dict = {}
while True:
for port_num in range(self.port_start, (self.port_end + 1)):
presence = self.get_presence(port_num)
if(presence and self._global_port_pres_dict[port_num] == '0'):
self._global_port_pres_dict[port_num] = '1'
port_dict[port_num] = '1'
elif(not presence and
self._global_port_pres_dict[port_num] == '1'):
self._global_port_pres_dict[port_num] = '0'
port_dict[port_num] = '0'
if(len(port_dict) > 0):
return True, port_dict
time.sleep(0.5)
def get_transceiver_dom_info_dict(self, port_num):
transceiver_dom_info_dict = {}
dom_info_dict_keys = ['temperature', 'voltage', 'rx1power',
'rx2power', 'rx3power', 'rx4power',
'tx1bias', 'tx2bias', 'tx3bias',
'tx4bias', 'tx1power', 'tx2power',
'tx3power', 'tx4power',
]
transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
if port_num in self.qsfp_ports:
offset = 0
offset_xcvr = 128
file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return transceiver_dom_info_dict
sfpi_obj = sff8436InterfaceId()
if sfpi_obj is None:
return transceiver_dom_info_dict
# QSFP capability byte parse, through this byte can know whether it support tx_power or not.
# TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436,
# need to add more code for determining the capability and version compliance
# in SFF-8636 dom capability definitions evolving with the versions.
qsfp_dom_capability_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH)
if qsfp_dom_capability_raw is not None:
qspf_dom_capability_data = sfpi_obj.parse_qsfp_dom_capability(qsfp_dom_capability_raw, 0)
else:
return transceiver_dom_info_dict
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH)
if dom_temperature_raw is not None:
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
else:
return transceiver_dom_info_dict
dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
else:
return transceiver_dom_info_dict
qsfp_dom_rev_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH)
if qsfp_dom_rev_raw is not None:
qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0)
else:
return transceiver_dom_info_dict
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
# The tx_power monitoring is only available on QSFP which compliant with SFF-8636
# and claimed that it support tx_power with one indicator bit.
dom_channel_monitor_data = {}
qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value']
qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value']
if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')):
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0)
else:
return transceiver_dom_info_dict
transceiver_dom_info_dict['tx1power'] = 'N/A'
transceiver_dom_info_dict['tx2power'] = 'N/A'
transceiver_dom_info_dict['tx3power'] = 'N/A'
transceiver_dom_info_dict['tx4power'] = 'N/A'
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value']
transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value']
transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value']
transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value']
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value']
transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value']
transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value']
transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value']
else:
offset = 256
file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path,"rb",0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8472Dom(None,1)
if sfpd_obj is None:
return None
dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET),
SFP_TEMPE_WIDTH)
if dom_temperature_raw is not None:
dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0)
else:
return transceiver_dom_info_dict
dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_VOLT_OFFSET),
SFP_VOLT_WIDTH)
if dom_voltage_raw is not None:
dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0)
else:
return transceiver_dom_info_dict
dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_MODULE_THRESHOLD_OFFSET),
SFP_MODULE_THRESHOLD_WIDTH)
if dom_channel_monitor_raw is not None:
dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0)
else:
return transceiver_dom_info_dict
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value']
transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value']
transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value']
transceiver_dom_info_dict['rx2power'] = 'N/A'
transceiver_dom_info_dict['rx3power'] = 'N/A'
transceiver_dom_info_dict['rx4power'] = 'N/A'
transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value']
transceiver_dom_info_dict['tx2bias'] = 'N/A'
transceiver_dom_info_dict['tx3bias'] = 'N/A'
transceiver_dom_info_dict['tx4bias'] = 'N/A'
transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value']
transceiver_dom_info_dict['tx2power'] = 'N/A'
transceiver_dom_info_dict['tx3power'] = 'N/A'
transceiver_dom_info_dict['tx4power'] = 'N/A'
return transceiver_dom_info_dict
def get_transceiver_dom_threshold_info_dict(self, port_num):
transceiver_dom_threshold_info_dict = {}
dom_info_dict_keys = ['temphighalarm', 'temphighwarning',
'templowalarm', 'templowwarning',
'vcchighalarm', 'vcchighwarning',
'vcclowalarm', 'vcclowwarning',
'rxpowerhighalarm', 'rxpowerhighwarning',
'rxpowerlowalarm', 'rxpowerlowwarning',
'txpowerhighalarm', 'txpowerhighwarning',
'txpowerlowalarm', 'txpowerlowwarning',
'txbiashighalarm', 'txbiashighwarning',
'txbiaslowalarm', 'txbiaslowwarning'
]
transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A')
if port_num in self.qsfp_ports:
file_path = self._get_port_eeprom_path(port_num, self.IDENTITY_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path, mode="rb", buffering=0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8436Dom()
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
# Dom Threshold data starts from offset 384
# Revert offset back to 0 once data is retrieved
offset = 384
dom_module_threshold_raw = self._read_eeprom_specific_bytes(
sysfsfile_eeprom,
(offset + QSFP_MODULE_THRESHOLD_OFFSET),
QSFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
dom_channel_threshold_raw = self._read_eeprom_specific_bytes(
sysfsfile_eeprom,
(offset + QSFP_CHANNL_THRESHOLD_OFFSET),
QSFP_CHANNL_THRESHOLD_WIDTH)
if dom_channel_threshold_raw is not None:
dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
# Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value']
else:
offset = 256
file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR)
if not self._sfp_eeprom_present(file_path, 0):
return None
try:
sysfsfile_eeprom = io.open(file_path,"rb",0)
except IOError:
print("Error: reading sysfs file %s" % file_path)
return None
sfpd_obj = sff8472Dom(None,1)
if sfpd_obj is None:
return transceiver_dom_threshold_info_dict
dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom,
(offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH)
if dom_module_threshold_raw is not None:
dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0)
else:
return transceiver_dom_threshold_info_dict
try:
sysfsfile_eeprom.close()
except IOError:
print("Error: closing sysfs file %s" % file_path)
return None
#Threshold Data
transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value']
transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value']
transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value']
transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value']
transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value']
transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value']
transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value']
transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value']
transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value']
transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value']
transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value']
transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value']
transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value']
transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value']
transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value']
return transceiver_dom_threshold_info_dict

View File

@ -0,0 +1,4 @@
{
"skip_ledd": true,
"start_ipmievd": true
}

View File

@ -9,6 +9,7 @@ $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR)
$(SONIC_ONE_IMAGE)_INSTALLS += $(FLASHROM)
$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
$(DELL_Z9264F_PLATFORM_MODULE) \
$(DELL_S5224F_PLATFORM_MODULE) \
$(DELL_S5232F_PLATFORM_MODULE) \
$(DELL_S5248F_PLATFORM_MODULE) \
$(DELL_Z9332F_PLATFORM_MODULE) \

View File

@ -4,6 +4,7 @@ DELL_S6000_PLATFORM_MODULE_VERSION = 1.1
DELL_Z9100_PLATFORM_MODULE_VERSION = 1.1
DELL_S6100_PLATFORM_MODULE_VERSION = 1.1
DELL_Z9264F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5224F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1
DELL_Z9332F_PLATFORM_MODULE_VERSION = 1.1
DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1
@ -15,6 +16,7 @@ export DELL_S6000_PLATFORM_MODULE_VERSION
export DELL_Z9100_PLATFORM_MODULE_VERSION
export DELL_S6100_PLATFORM_MODULE_VERSION
export DELL_Z9264F_PLATFORM_MODULE_VERSION
export DELL_S5224F_PLATFORM_MODULE_VERSION
export DELL_S5232F_PLATFORM_MODULE_VERSION
export DELL_Z9332F_PLATFORM_MODULE_VERSION
export DELL_S5248F_PLATFORM_MODULE_VERSION
@ -41,6 +43,10 @@ DELL_S6000_PLATFORM_MODULE = platform-modules-s6000_$(DELL_S6000_PLATFORM_MODULE
$(DELL_S6000_PLATFORM_MODULE)_PLATFORM = x86_64-dell_s6000_s1220-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S6000_PLATFORM_MODULE)))
DELL_S5224F_PLATFORM_MODULE = platform-modules-s5224f_$(DELL_S5224F_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_S5224F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5224f_c3538-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5224F_PLATFORM_MODULE)))
DELL_S5232F_PLATFORM_MODULE = platform-modules-s5232f_$(DELL_S5232F_PLATFORM_MODULE_VERSION)_amd64.deb
$(DELL_S5232F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5232f_c3538-r0
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5232F_PLATFORM_MODULE)))

View File

@ -25,6 +25,11 @@ Architecture: amd64
Depends: linux-image-4.19.0-12-2-amd64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-s5224f
Architecture: amd64
Depends: linux-image-4.19.0-12-2-amd64-unsigned
Description: kernel modules for platform devices such as fan, led, sfp
Package: platform-modules-s5232f
Architecture: amd64
Depends: linux-image-4.19.0-12-2-amd64-unsigned

View File

@ -0,0 +1,40 @@
#!/bin/bash
### BEGIN INIT INFO
# Provides: setup-board
# Required-Start:
# Required-Stop:
# Should-Start:
# Should-Stop:
# Default-Start: S
# Default-Stop: 0 6
# Short-Description: Setup S5224f board.
### END INIT INFO
case "$1" in
start)
echo -n "Setting up board... "
# /usr/local/bin/iom_power_on.sh
/usr/local/bin/s5224f_platform.sh init
echo "done."
;;
stop)
/usr/local/bin/s5224f_platform.sh deinit
echo "done."
;;
force-reload|restart)
echo "Not supported"
;;
*)
echo "Usage: /etc/init.d/platform-modules-s5224f.init {start|stop}"
exit 1
;;
esac
exit 0

View File

@ -0,0 +1,13 @@
s5224f/scripts/s5224f_platform.sh usr/local/bin
s5224f/scripts/check_qsfp.sh usr/local/bin
s5224f/scripts/platform_sensors.py usr/local/bin
s5224f/scripts/sensors usr/bin
s5224f/scripts/pcisysfs.py usr/bin
s5224f/scripts/qsfp_irq_enable.py usr/bin
s5224f/cfg/s5224f-modules.conf etc/modules-load.d
s5224f/cfg/s5224f-params.conf etc/modprobe.d
s5224f/systemd/platform-modules-s5224f.service etc/systemd/system
s5224f/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_s5224f_c3538-r0
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_s5224f_c3538-r0
common/fw-updater usr/local/bin
common/onie_mode_set usr/local/bin

View File

@ -0,0 +1,10 @@
# postinst script for S5224f
# Enable Dell-S5224f-platform-service
depmod -a
systemctl enable platform-modules-s5224f.service
systemctl start platform-modules-s5224f.service
#DEBHELPER#

View File

@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f z9332f s5296f n3248pxe n3248te
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5224f s5232f s5248f z9332f s5296f n3248pxe n3248te
COMMON_DIR := common
%:
@ -39,6 +39,11 @@ override_dh_auto_build:
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
elif [ $$mod = "s5224f" ]; then \
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
cd $(MOD_SRC_DIR)/$${mod}; \
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
cd $(MOD_SRC_DIR); \
elif [ $$mod = "s5232f" ]; then \
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
cd $(MOD_SRC_DIR)/$${mod}; \
@ -114,6 +119,11 @@ override_dh_clean:
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
elif [ $$mod = "s5224f" ]; then \
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build; \
rm -rf $(MOD_SRC_DIR)/$${mod}/build/*.egg-info; \
elif [ $$mod = "s5232f" ]; then \
rm -f $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
rm -f $(MOD_SRC_DIR)/$${mod}/modules/*.whl; \

View File

@ -0,0 +1,19 @@
# /etc/modules: kernel modules to load at boot time.
#
# This file contains the names of kernel modules that should be loaded
# at boot time, one per line. Lines beginning with "#" are ignored.
i2c-i801
i2c-isch
i2c-ismt
i2c-dev
i2c-mux
i2c-smbus
i2c-mux-gpio
i2c-mux-pca954x
ipmi_devintf
ipmi_si
dell_s5224f_fpga_ocores
i2c_ocores

View File

@ -0,0 +1 @@
options ipmi_si kipmid_max_busy_us=1000

View File

@ -0,0 +1,2 @@
obj-m := dell_s5224f_fpga_ocores.o

View File

@ -0,0 +1,3 @@
# Temporary dummy file for s5224f.
# Will be updated soon.

View File

@ -0,0 +1,102 @@
#!/usr/bin/python
# Copyright (c) 2015 Dell Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR
# CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT
# LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS
# FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT.
#
# See the Apache Version 2.0 License for specific language governing
# permissions and limitations under the License.
import struct
import sys
import getopt
from os import *
from mmap import *
def usage():
''' This is the Usage Method '''
print '\t\t pcisysfs.py --get --offset <offset> --res <resource>'
print '\t\t pcisysfs.py --set --val <val> --offset <offset> --res <resource>'
sys.exit(1)
def pci_mem_read(mm,offset):
mm.seek(offset)
read_data_stream=mm.read(4)
print ""
reg_val=struct.unpack('I',read_data_stream)
print "reg_val read:%x"%reg_val
return reg_val
def pci_mem_write(mm,offset,data):
mm.seek(offset)
print "data to write:%x"%data
mm.write(struct.pack('I',data))
def pci_set_value(resource,val,offset):
fd=open(resource,O_RDWR)
mm=mmap(fd,0)
pci_mem_write(mm,offset,val)
def pci_get_value(resource,offset):
fd=open(resource,O_RDWR)
mm=mmap(fd,0)
pci_mem_read(mm,offset)
def main(argv):
''' The main function will read the user input from the
command line argument and process the request '''
opts = ''
val = ''
choice = ''
resource = ''
offset = ''
try:
opts, args = getopt.getopt(argv, "hgsv:" , \
["val=","res=","offset=","help", "get", "set"])
except getopt.GetoptError:
usage()
for opt,arg in opts:
if opt in ('-h','--help'):
choice = 'help'
elif opt in ('-g', '--get'):
choice = 'get'
elif opt in ('-s', '--set'):
choice = 'set'
elif opt == '--res':
resource = arg
elif opt == '--val':
val = int(arg,16)
elif opt == '--offset':
offset = int(arg,16)
if choice == 'set' and val != '' and offset !='' and resource !='':
pci_set_value(resource,val,offset)
elif choice == 'get' and offset != '' and resource !='':
pci_get_value(resource,offset)
else:
usage()
#Calling the main method
if __name__ == "__main__":
main(sys.argv[1:])

View File

@ -0,0 +1,321 @@
#!/usr/bin/python
# On S5224F, the BaseBoard Management Controller is an
# autonomous subsystem provides monitoring and management
# facility independent of the host CPU. IPMI standard
# protocol is used with ipmitool to fetch sensor details.
# Current script support X00 board only. X01 support will
# be added soon. This provies support for the
# following objects:
# * Onboard temperature sensors
# * FAN trays
# * PSU
import sys
import logging
import subprocess
S5224F_MAX_FAN_TRAYS = 4
S5224F_MAX_PSUS = 2
IPMI_SENSOR_DATA = "ipmitool sdr list"
IPMI_SENSOR_DUMP = "/tmp/sdr"
PSU_PRESENCE = "PSU{0}_stat"
# Use this for older firmware
# PSU_PRESENCE="PSU{0}_prsnt"
IPMI_FAN_PRESENCE = "ipmitool sensor get FAN{0}_prsnt"
IPMI_PSU1_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x31 | awk '{print substr($0,9,1)}'"
IPMI_PSU2_DATA_DOCKER = "ipmitool raw 0x04 0x2d 0x32 | awk '{print substr($0,9,1)}'"
IPMI_RAW_STORAGE_READ = "ipmitool raw 0x0a 0x11 {0} 0 0 0xa0"
IPMI_FRU = "ipmitool fru"
ipmi_sdr_list = ""
# Dump sensor registers
def ipmi_sensor_dump():
global ipmi_sdr_list
ipmi_cmd = IPMI_SENSOR_DATA
status, ipmi_sdr_list = subprocess.getstatusoutput(ipmi_cmd)
if status:
logging.error('Failed to execute:' + ipmi_sdr_list)
sys.exit(0)
# Fetch a Fan Status
def get_fan_status(fan_id):
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_FAN_PRESENCE.format(fan_id))
if ret_status:
logging.error('Failed to execute : %s'%IPMI_FAN_PRESENCE.format(fan_id))
sys.exit(0)
return(' ' + ipmi_cmd_ret.splitlines()[5].strip(' ').strip('[]'))
# Fetch a BMC register
def get_pmc_register(reg_name):
output = None
for item in ipmi_sdr_list.split("\n"):
if reg_name in item:
output = item.strip()
if output is None:
print('\nFailed to fetch: ' + reg_name + ' sensor ')
sys.exit(0)
output = output.split('|')[1]
logging.basicConfig(level=logging.DEBUG)
return output
#Fetch FRU Data for given fruid
def get_psu_airflow(psu_id):
fru_id = 'PSU' + str(psu_id) + '_fru'
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_FRU)
if ret_status:
logging.error('Failed to execute ipmitool: '+ IPMI_FRU)
sys.exit(0)
found_fru = False
for line in ipmi_cmd_ret.splitlines():
if line.startswith('FRU Device Description') and fru_id in line.split(':')[1] :
found_fru = True
if found_fru and line.startswith(' Board Product '):
return 'Intake' if 'PS/IO' in line else 'Exhaust'
return ''
# Fetch FRU on given offset
def fetch_raw_fru(dev_id, offset):
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_RAW_STORAGE_READ.format(dev_id))
if ret_status:
logging.error('Failed to execute ipmitool :' + IPMI_RAW_STORAGE_READ.format(dev_id))
sys.exit(0)
return int((ipmi_cmd_ret.splitlines()[int(offset/16)]).split(' ')[(int(offset%16)+1)])
def get_fan_airflow(fan_id):
Airflow_Direction = ['Exhaust', 'Intake']
return Airflow_Direction[fetch_raw_fru(fan_id+2, 0x46)]
# Print the information for temperature sensors
def print_temperature_sensors():
print("\nOnboard Temperature Sensors:")
print (' PT_Left_temp: ',\
(get_pmc_register('PT_Left_temp')))
print (' PT_Mid_temp: ',\
(get_pmc_register('PT_Mid_temp')))
print (' PT_Right_temp: ',\
(get_pmc_register('PT_Right_temp')))
print (' Broadcom Temp: ',\
(get_pmc_register('NPU_Near_temp')))
print (' Inlet Airflow Temp: ',\
(get_pmc_register('ILET_AF_temp')))
print (' CPU Temp: ',\
(get_pmc_register('CPU_temp')))
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput('echo 0 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us')
if ret_status:
logging.error("platform_sensors: Failed to set kipmid_max_busy_us to 0")
ipmi_sensor_dump()
print_temperature_sensors()
# Print the information for 1 Fan Tray
def print_fan_tray(tray):
Fan_Status = [' Normal', ' Abnormal']
print (' Fan Tray ' + str(tray) + ':')
if (tray == 1):
fan1_status = int(get_pmc_register('FAN1_Front_stat'), 16)
fan2_status = int(get_pmc_register('FAN1_Rear_stat'), 16)
print (' Fan1 Speed: ',\
get_pmc_register('FAN1_Front_rpm'))
print (' Fan2 Speed: ',\
get_pmc_register('FAN1_Rear_rpm'))
print (' Fan1 State: ',\
Fan_Status[fan1_status])
print (' Fan2 State: ',\
Fan_Status[fan2_status])
elif (tray == 2):
fan1_status = int(get_pmc_register('FAN2_Front_stat'), 16)
fan2_status = int(get_pmc_register('FAN2_Rear_stat'), 16)
print (' Fan1 Speed: ',\
get_pmc_register('FAN2_Front_rpm'))
print (' Fan2 Speed: ',\
get_pmc_register('FAN2_Rear_rpm'))
print (' Fan1 State: ',\
Fan_Status[fan1_status])
print (' Fan2 State: ',\
Fan_Status[fan2_status])
elif (tray == 3):
fan1_status = int(get_pmc_register('FAN3_Front_stat'), 16)
fan2_status = int(get_pmc_register('FAN3_Rear_stat'), 16)
print (' Fan1 Speed: ',\
get_pmc_register('FAN3_Front_rpm'))
print (' Fan2 Speed: ',\
get_pmc_register('FAN3_Rear_rpm'))
print (' Fan1 State: ',\
Fan_Status[fan1_status])
print (' Fan2 State: ',\
Fan_Status[fan2_status])
elif (tray == 4):
fan1_status = int(get_pmc_register('FAN4_Front_stat'), 16)
fan2_status = int(get_pmc_register('FAN4_Rear_stat'), 16)
print (' Fan1 Speed: ',\
get_pmc_register('FAN4_Front_rpm'))
print (' Fan2 Speed: ',\
get_pmc_register('FAN4_Rear_rpm'))
print (' Fan1 State: ',\
Fan_Status[fan1_status])
print (' Fan2 State: ',\
Fan_Status[fan2_status])
print (' Airflow: ',\
get_fan_airflow(tray))
print('\nFan Trays:')
for tray in range(1, S5224F_MAX_FAN_TRAYS + 1):
if (get_fan_status(tray) == ' Present'):
print_fan_tray(tray)
else:
print (' Fan Tray %d:' % (tray))
print (' Fan State: Not present')
def get_psu_presence(index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
ret_status = 1
if index == 1:
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU1_DATA_DOCKER)
elif index == 2:
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU2_DATA_DOCKER)
if ret_status:
logging.error('Failed to execute ipmitool :' + IPMI_PSU1_DATA_DOCKER)
sys.exit(0)
psu_status = ipmi_cmd_ret
return (int(psu_status, 16) & 1)
def get_psu_status(index):
"""
Retrieves the presence status of power supply unit (PSU) defined
by index <index>
:param index: An integer, index of the PSU of which to query status
:return: Boolean, True if PSU is plugged, False if not
"""
ret_status = 1
ipmi_cmd_ret = 'f'
if index == 1:
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU1_DATA_DOCKER)
elif index == 2:
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput(IPMI_PSU2_DATA_DOCKER)
if ret_status:
logging.error('Failed to execute ipmitool : ' + IPMI_PSU2_DATA_DOCKER)
sys.exit(0)
psu_status = ipmi_cmd_ret
return (not int(psu_status, 16) > 1)
# Print the information for PSU1, PSU2
def print_psu(psu):
# PSU FAN details
if (psu == 1):
print (' PSU1:')
print (' FAN Normal Temperature: ',\
get_pmc_register('PSU1_temp'))
print (' FAN AirFlow Temperature: ',\
get_pmc_register('PSU1_AF_temp'))
print (' FAN RPM: ',\
get_pmc_register('PSU1_rpm'))
# PSU input & output monitors
print (' Input Voltage: ',\
get_pmc_register('PSU1_In_volt'))
print (' Output Voltage: ',\
get_pmc_register('PSU1_Out_volt'))
print (' Input Power: ',\
get_pmc_register('PSU1_In_watt'))
print (' Output Power: ',\
get_pmc_register('PSU1_Out_watt'))
print (' Input Current: ',\
get_pmc_register('PSU1_In_amp'))
print (' Output Current: ',\
get_pmc_register('PSU1_Out_amp'))
else:
print (' PSU2:')
print (' FAN Normal Temperature: ',\
get_pmc_register('PSU2_temp'))
print (' FAN AirFlow Temperature: ',\
get_pmc_register('PSU2_AF_temp'))
print (' FAN RPM: ',\
get_pmc_register('PSU2_rpm'))
# PSU input & output monitors
print (' Input Voltage: ',\
get_pmc_register('PSU2_In_volt'))
print (' Output Voltage: ',\
get_pmc_register('PSU2_Out_volt'))
print (' Input Power: ',\
get_pmc_register('PSU2_In_watt'))
print (' Output Power: ',\
get_pmc_register('PSU2_Out_watt'))
print (' Input Current: ',\
get_pmc_register('PSU2_In_amp'))
print (' Output Current: ',\
get_pmc_register('PSU2_Out_amp'))
print (' Airflow: ',\
get_psu_airflow(psu))
print('\nPSUs:')
for psu in range(1, S5224F_MAX_PSUS + 1):
if not get_psu_presence(psu):
print (' PSU%d:' % (psu))
print (' Status: Not present')
elif not get_psu_status(psu) :
print (' PSU%d:' % (psu))
print (' Status: Not OK')
else:
print_psu(psu)
print ('\n Total Power: ',\
get_pmc_register('PSU_Total_watt'))
ret_status, ipmi_cmd_ret = subprocess.getstatusoutput('echo 1000 > /sys/module/ipmi_si/parameters/kipmid_max_busy_us')
if ret_status:
logging.error("platform_sensors: Failed to set kipmid_max_busy_us to 1000")

View File

@ -0,0 +1,3 @@
#!/usr/bin/python
# No IRQ support for S5224F

View File

@ -0,0 +1,202 @@
#!/bin/bash
init_devnum() {
found=0
for devnum in 0 1; do
devname=`cat /sys/bus/i2c/devices/i2c-${devnum}/name`
# iSMT adapter can be at either dffd0000 or dfff0000
if [[ $devname == 'SMBus iSMT adapter at '* ]]; then
found=1
break
fi
done
[ $found -eq 0 ] && echo "cannot find iSMT" && exit 1
}
# Attach/Detach syseeprom on CPU board
sys_eeprom() {
b=''
for bb in 0 1; do
if [ "$(cat /sys/bus/i2c/devices/i2c-${bb}/name)" = 'SMBus iSMT adapter at dff9f000' ]; then
b=$bb
break
fi
done
if [ "$b" = '' ]; then
echo "s5224f_platform: sys_eeprom : cannot find I2C bus!"
return
fi
case $1 in
"new_device") echo 24c16 0x50 > /sys/bus/i2c/devices/i2c-${b}/$1
;;
"delete_device") echo 0x50 > /sys/bus/i2c/devices/i2c-${b}/$1
;;
*) echo "s5224f_platform: sys_eeprom : invalid command !"
;;
esac
}
#Attach/Detach the MUX connecting all SFP28s/QSFP28s
switch_board_qsfp_mux() {
case $1 in
"new_device")
for ((i=603;i<=606;i++));
do
echo "Attaching PCA9548 @ 0x74"
echo pca9548 0x74 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
"delete_device")
for ((i=603;i<=606;i++));
do
echo "Detaching PCA9548 @ 0x74"
echo 0x74 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
*) echo "s5224f_platform: switch_board_qsfp_mux: invalid command !"
;;
esac
sleep 2
}
#Attach/Detach 24 instances of EEPROM driver SFP28 ports. Use optoe2 (for dual address devices)
#Attach/Detach 4 instances of EEPROM driver QSFP28 ports. Use optoe1 (for single address devices)
#eeprom can dump data using below command
switch_board_qsfp() {
case $1 in
"new_device")
for ((i=2;i<=25;i++));
do
echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
for ((i=26;i<=29;i++));
do
echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
"delete_device")
for ((i=2;i<=29;i++));
do
echo 0x50 > /sys/bus/i2c/devices/i2c-$i/$1
done
;;
*) echo "s5224f_platform: switch_board_qsfp: invalid command !"
;;
esac
}
#Modsel 4 ports to applicable QSFP28 type modules
#This enables the adapter to respond for i2c commands
switch_board_modsel() {
resource="/sys/bus/pci/devices/0000:04:00.0/resource0"
for ((i=1;i<=28;i++));
do
port_addr=$(( 16384 + ((i - 1) * 16)))
hex=$( printf "0x%x" $port_addr )
python /usr/bin/pcisysfs.py --set --offset $hex --val 0x10 --res $resource > /dev/null 2>&1
done
}
platform_firmware_versions() {
FIRMWARE_VERSION_FILE=/var/log/firmware_versions
rm -rf ${FIRMWARE_VERSION_FILE}
echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE
## Get FPGA version
r=`/usr/bin/pcisysfs.py --get --offset 0x00 --res /sys/bus/pci/devices/0000\:04\:00.0/resource0 | sed '1d; s/.*\(....\)$/\1/; s/\(..\{1\}\)/\1./'`
r_min=$(echo $r | sed 's/.*\(..\)$/0x\1/')
r_maj=$(echo $r | sed 's/^\(..\).*/0x\1/')
echo "FPGA: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
## Get BMC Firmware Revision
r=`cat /sys/class/ipmi/ipmi0/device/bmc/firmware_revision`
echo "BMC: $r" >> $FIRMWARE_VERSION_FILE
#System CPLD 0x31 on i2c bus 601 ( physical FPGA I2C-2)
r_min=`/usr/sbin/i2cget -y 601 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'`
r_maj=`/usr/sbin/i2cget -y 601 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'`
echo "System CPLD: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
#Slave CPLD 1 0x30 on i2c bus 600 ( physical FPGA I2C-1)
r_min=`/usr/sbin/i2cget -y 600 0x30 0x0 | sed ' s/.*\(0x..\)$/\1/'`
r_maj=`/usr/sbin/i2cget -y 600 0x30 0x1 | sed ' s/.*\(0x..\)$/\1/'`
echo "Slave CPLD 1: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
#Slave CPLD 2 0x31 on i2c bus 600 ( physical FPGA I2C-1)
r_min=`/usr/sbin/i2cget -y 600 0x31 0x0 | sed ' s/.*\(0x..\)$/\1/'`
r_maj=`/usr/sbin/i2cget -y 600 0x31 0x1 | sed ' s/.*\(0x..\)$/\1/'`
echo "Slave CPLD 2: $((r_maj)).$((r_min))" >> $FIRMWARE_VERSION_FILE
}
install_python_api_package() {
device="/usr/share/sonic/device"
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
}
remove_python_api_package() {
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
if [ $? -eq 0 ]; then
rv=$(pip3 uninstall -y sonic-platform > /dev/null 2>/dev/null)
fi
}
get_reboot_cause() {
REBOOT_REASON_FILE="/host/reboot-cause/platform/reboot_reason"
resource="/sys/bus/pci/devices/0000:04:00.0/resource0"
mkdir -p $(dirname $REBOOT_REASON_FILE)
# Handle First Boot into software version with reboot cause determination support
if [[ ! -e $REBOOT_REASON_FILE ]]; then
echo "0" > $REBOOT_REASON_FILE
else
/usr/bin/pcisysfs.py --get --offset 0x18 --res $resource | sed '1d; s/.*:\(.*\)$/\1/;' > $REBOOT_REASON_FILE
fi
/usr/bin/pcisysfs.py --set --val 0x0 --offset 0x18 --res $resource
}
#This enables the led control for CPU and default states
switch_board_led_default() {
resource="/sys/bus/pci/devices/0000:04:00.0/resource0"
python /usr/bin/pcisysfs.py --set --offset 0x24 --val 0x194 --res $resource > /dev/null 2>&1
}
init_devnum
if [ "$1" == "init" ]; then
modprobe i2c-dev
modprobe i2c-mux-pca954x force_deselect_on_exit=1
modprobe ipmi_devintf
modprobe ipmi_si kipmid_max_busy_us=1000
modprobe i2c_ocores
modprobe dell_s5224f_fpga_ocores
sys_eeprom "new_device"
get_reboot_cause
switch_board_qsfp_mux "new_device"
switch_board_qsfp "new_device"
switch_board_modsel
switch_board_led_default
install_python_api_package
#python /usr/bin/qsfp_irq_enable.py
platform_firmware_versions
elif [ "$1" == "deinit" ]; then
sys_eeprom "delete_device"
switch_board_qsfp "delete_device"
switch_board_qsfp_mux "delete_device"
modprobe -r i2c-mux-pca954x
modprobe -r i2c-dev
remove_python_api_package
modprobe -r ipmi_devintf
modprobe -r ipmi_si
else
echo "s5224f_platform : Invalid option !"
fi

View File

@ -0,0 +1,8 @@
#!/bin/bash
docker exec -i pmon sensors "$@"
docker exec -i pmon /usr/bin/platform_sensors.py "$@"
#To probe sensors not part of lm-sensors
#if [ -r /usr/local/bin/platform_sensors.py ]; then
# python /usr/local/bin/platform_sensors.py
#fi

View File

@ -0,0 +1 @@
../s6100/setup.py

View File

@ -0,0 +1,3 @@
__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"]
from sonic_platform import *

View File

@ -0,0 +1,340 @@
#!/usr/bin/env python
#############################################################################
# DELLEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
import time
import sys
from sonic_platform_base.chassis_base import ChassisBase
from sonic_platform.sfp import Sfp
from sonic_platform.eeprom import Eeprom
from sonic_platform.component import Component
from sonic_platform.psu import Psu
from sonic_platform.thermal import Thermal
from sonic_platform.watchdog import Watchdog
from sonic_platform.fan import Fan
from sonic_platform.fan_drawer import FanDrawer
from sonic_platform.hwaccess import pci_get_value, pci_set_value
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
MAX_S5224F_COMPONENT = 5
MAX_S5224F_FANTRAY =4
MAX_S5224F_FAN = 2
MAX_S5224F_PSU = 2
MAX_S5224F_THERMAL = 8
SYSTEM_LED_REG = 0x24
SYSTEM_BEACON_LED_SET = 0x8
SYSTEM_BEACON_LED_CLEAR = 0xFFFFFFF7
media_part_num_list = set([ \
"8T47V","XTY28","MHVPK","GF76J","J6FGD","F1KMV","9DN5J","H4DHD","6MCNV","0WRX0","X7F70","5R2PT","WTRD1","WTRD1","WTRD1","WTRD1","5250G","WTRD1","C5RNH","C5RNH","FTLX8571D3BCL-FC",
"C5RNH","5250G","N8TDR","7D64H","7D64H","RN84N","RN84N","HMTNW","6K3Y6","6K3Y6","TY5FM","50M0R","PGYJT","WP2PP","85Y13","1HCGH","FP9R1","FYD0M","C6Y7M","C6Y7M","V250M","V250M",
"5CWK6","5CWK6","53HVN","53HVN","358VV","358VV","MV799","MV799","YJF03","P9GND","T1KCN","1DXKP","MT7R2","K0T7R","W5G04","7TCDN","7TCDN","7TCDN","7TCDN","7TCDN","V3XJK","0MV31",
"5FVP7","N6KM9","C41MF","77KC3","XW7J0","V4NJV","2XJHY","H93DH","H93DH","F8CG0","F8CG0","F8CG0","119N6","WFMF5","794RX","288F6","1M31V","1M31V","5NP8R","5NP8R","4TC09","4TC09",
"FC6KV","FC6KV","J90VN","J90VN","05RH0","05RH0","YDN52","0C2YV","YDN52","0C2YV","9JT65","D7M6H","6GW14","FYVFW","0VF5H","P4YPY","P4YPY","TCPM2","TCPM2","JNPF8","JNPF8","27GG5",
"27GG5","P8T4W","P8T4W","JR54Y","M6N0J","XJYD0","K44H9","035KG","P7C7N","76V43","3CC35","FN4FC","26FN3","YFNDD","YFNDD","7R9N9","035KG","P7C7N","76V43","3CC35","PLRXPLSCS43811",
"FN4FC","26FN3","YFNDD","YFNDD","7R9N9","G86YJ","V407F","V407F","9KH6T","G86YJ","V407F","9KH6T","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY","9X8JP","2JVDD","D0R73","VXFJY",
"9X8JP","GMFC5","GMFC5","GMFC5","D7P80","3MFXG","3MFXG","0GWXJ","THPF3","THPF3","THPF3","THPF3","THPF3","PJ62G","3XCX1","JJYKG","RRRTK","16K56","86JM2","K5R6C","7MG2C","WTPPN","9HTT2",
"NKM4F","VXGGG","JC9W6","6MR8M","RP3GV","M5PPJ","XKY55","TKCXT","05J8P","5WGKD","XFDRT","NW8DM","YPKH3","5WGKD","XFDRT","NW8DM","YPKH3","71XXK","MVCX6","0XYP6","HPPVW","3GHRT","71XXK",
"MVCX6","0XYP6","HPPVW","3GHRT","2X5T6","135V2","KD5MV","2X5T6","KD5MV","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","HHFK0","3YWG7","5CMT2","RCVP5","X5DH4","3YWG7","5CMT2","RCVP5","X5DH4",
"4WJ41","4WJ41","14NV5","14NV5","14NV5","4WGYD","YKMH7","X7CCC","X7CCC","0X9CT","0CY8V","P7D7R","W4GPP","W4GPP","W4GPP","HHHCHC","07RN7","07RN7","0YR96","0YR96","JCYM9","FTLX8571D3BCL",
"DDW0X","VPFDJ","229KM","9FC7D","DDW0X","VPFDJ","6FMR5","J7K20","N3K9W","6FMR5","8R4VM","7VN5T","D9YM8","8R4VM","VYXPW","87TPX","WY6FK","VYXPW","87TPX","WY6FK","WG8C4","N8K82","2DV6Y",
"77C3C","RC0HM","77C3C","RC0HM","JHXTN","3P3PG","92YVM","4VX5M","4VX5M","6RRGD","W4JWV","22V6R","XR11M","9GMDY","JMCWK","TP2F0","6MGDY","78RHK", "C0TP5","0WDNV","FCLF8522P2BTL"\
])
class Chassis(ChassisBase):
"""
DELLEMC Platform-specific Chassis class
"""
REBOOT_CAUSE_PATH = "/host/reboot-cause/platform/reboot_reason"
OIR_FD_PATH = "/sys/bus/pci/devices/0000:04:00.0/port_msi"
_global_port_pres_dict = {}
def __init__(self):
ChassisBase.__init__(self)
# sfp.py will read eeprom contents and retrive the eeprom data.
# We pass the eeprom path from chassis.py
self.PORT_START = 1
self.PORT_END = 28
self.SFP28_PORT_END = 24
PORTS_IN_BLOCK = (self.PORT_END + 1)
_sfp_port = range(1, self.SFP28_PORT_END + 1)
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
for index in range(self.PORT_START, PORTS_IN_BLOCK):
port_num = index + 1
eeprom_path = eeprom_base.format(port_num)
if index not in _sfp_port:
sfp_node = Sfp(index, 'QSFP', eeprom_path)
else:
sfp_node = Sfp(index, 'SFP', eeprom_path)
self._sfp_list.append(sfp_node)
self._eeprom = Eeprom()
self._watchdog = Watchdog()
self._num_sfps = self.PORT_END
self._num_fans = MAX_S5224F_FAN * MAX_S5224F_FANTRAY
for i in range(MAX_S5224F_THERMAL):
thermal = Thermal(i)
self._thermal_list.append(thermal)
for i in range(MAX_S5224F_COMPONENT):
component = Component(i)
self._component_list.append(component)
for i in range(MAX_S5224F_PSU):
psu = Psu(i)
self._psu_list.append(psu)
for i in range(MAX_S5224F_FANTRAY):
for j in range(MAX_S5224F_FAN):
fan = Fan(i,j)
self._fan_list.append(fan)
for i in range(MAX_S5224F_FANTRAY):
fandrawer = FanDrawer(i)
self._fan_drawer_list.append(fandrawer)
self._fan_list.extend(fandrawer._fan_list)
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
# sfp get uses zero-indexing, but port numbers start from 1
presence = self.get_sfp(port_num-1).get_presence()
if presence:
self._global_port_pres_dict[port_num] = '1'
else:
self._global_port_pres_dict[port_num] = '0'
# check for this event change for sfp / do we need to handle timeout/sleep
def get_change_event(self, timeout=0):
"""
Returns a nested dictionary containing all devices which have
experienced a change at chassis level
"""
start_ms = time.time() * 1000
port_dict = {}
change_dict = {}
change_dict['sfp'] = port_dict
while True:
time.sleep(0.5)
for port_num in range(self.PORT_START, (self.PORT_END + 1)):
presence = self.get_sfp(port_num-1).get_presence()
if(presence and self._global_port_pres_dict[port_num] == '0'):
self._global_port_pres_dict[port_num] = '1'
port_dict[port_num] = '1'
elif(not presence and
self._global_port_pres_dict[port_num] == '1'):
self._global_port_pres_dict[port_num] = '0'
port_dict[port_num] = '0'
if(len(port_dict) > 0):
return True, change_dict
if timeout:
now_ms = time.time() * 1000
if (now_ms - start_ms >= timeout):
return True, change_dict
def get_sfp(self, index):
"""
Retrieves sfp represented by (0-based) index <index>
Args:
index: An integer, the index (0-based) of the sfp to retrieve.
The index should be the sequence of a physical port in a chassis,
starting from 0.
For example, 0 for Ethernet0, 1 for Ethernet4 and so on.
Returns:
An object dervied from SfpBase representing the specified sfp
"""
sfp = None
try:
# The index will start from 0
sfp = self._sfp_list[index-1]
except IndexError:
sys.stderr.write("SFP index {} out of range (1-{})\n".format(
index, len(self._sfp_list)))
return sfp
def get_name(self):
"""
Retrieves the name of the chassis
Returns:
string: The name of the chassis
"""
return self._eeprom.modelstr()
def get_presence(self):
"""
Retrieves the presence of the chassis
Returns:
bool: True if chassis is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the chassis
Returns:
string: Model/part number of chassis
"""
return self._eeprom.part_number_str()
def get_serial(self):
"""
Retrieves the serial number of the chassis (Service tag)
Returns:
string: Serial number of chassis
"""
return self._eeprom.serial_str()
def get_status(self):
"""
Retrieves the operational status of the chassis
Returns:
bool: A boolean value, True if chassis is operating properly
False if not
"""
return True
def get_base_mac(self):
"""
Retrieves the base MAC address for the chassis
Returns:
A string containing the MAC address in the format
'XX:XX:XX:XX:XX:XX'
"""
return self._eeprom.base_mac_addr('')
def get_serial_number(self):
"""
Retrieves the hardware serial number for the chassis
Returns:
A string containing the hardware serial number for this chassis.
"""
return self._eeprom.serial_number_str()
def get_system_eeprom_info(self):
"""
Retrieves the full content of system EEPROM information for the chassis
Returns:
A dictionary where keys are the type code defined in
OCP ONIE TlvInfo EEPROM format and values are their corresponding
values.
"""
return self._eeprom.system_eeprom_info()
def get_eeprom(self):
"""
Retrieves the Sys Eeprom instance for the chassis.
Returns :
The instance of the Sys Eeprom
"""
return self._eeprom
def get_num_fans(self):
"""
Retrives the number of Fans on the chassis.
Returns :
An integer represents the number of Fans on the chassis.
"""
return self._num_fans
def get_num_sfps(self):
"""
Retrives the numnber of Media on the chassis.
Returns:
An integer represences the number of SFPs on the chassis.
"""
return self._num_sfps
def get_reboot_cause(self):
"""
Retrieves the cause of the previous reboot
Returns:
A tuple (string, string) where the first element is a string
containing the cause of the previous reboot. This string must be
one of the predefined strings in this class. If the first string
is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used
to pass a description of the reboot cause.
"""
try:
with open(self.REBOOT_CAUSE_PATH) as fd:
reboot_cause = int(fd.read(), 16)
except EnvironmentError:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
if reboot_cause & 0x1:
return (self.REBOOT_CAUSE_POWER_LOSS, None)
elif reboot_cause & 0x2:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
elif reboot_cause & 0x4:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "PSU Shutdown")
elif reboot_cause & 0x8:
return (self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU, None)
elif reboot_cause & 0x10:
return (self.REBOOT_CAUSE_WATCHDOG, None)
elif reboot_cause & 0x20:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "BMC Shutdown")
elif reboot_cause & 0x40:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Hot-Swap Shutdown")
elif reboot_cause & 0x80:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Shutdown")
elif reboot_cause & 0x100:
return (self.REBOOT_CAUSE_HARDWARE_OTHER, "Reset Button Cold Reboot")
else:
return (self.REBOOT_CAUSE_NON_HARDWARE, None)
def get_qualified_media_list(self):
return media_part_num_list
def set_locator_led(self, color):
"""
Sets the state of the Chassis Locator LED
Args:
color: A string representing the color with which to set the Chassis Locator LED
Returns:
bool: True if the Chassis Locator LED state is set successfully, False if not
"""
resource = "/sys/bus/pci/devices/0000:04:00.0/resource0"
val = pci_get_value(resource, SYSTEM_LED_REG)
if self.LOCATOR_LED_ON == color:
val = int(val) | SYSTEM_BEACON_LED_SET
elif self.LOCATOR_LED_OFF == color:
val = int(val) & SYSTEM_BEACON_LED_CLEAR
else:
return False
pci_set_value(resource, val, SYSTEM_LED_REG)
return True
def get_locator_led(self):
"""
Gets the state of the Chassis Locator LED
Returns:
LOCATOR_LED_ON or LOCATOR_LED_OFF
"""
resource = "/sys/bus/pci/devices/0000:04:00.0/resource0"
val = pci_get_value(resource, SYSTEM_LED_REG)
val = int(val) & SYSTEM_BEACON_LED_SET
if not val:
return self.LOCATOR_LED_OFF
else:
return self.LOCATOR_LED_ON

View File

@ -0,0 +1,113 @@
#!/usr/bin/env python
########################################################################
# DELLEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Components' (e.g., BIOS, CPLD, FPGA, BMC etc.) available in
# the platform
#
########################################################################
try:
import subprocess
from sonic_platform_base.component_base import ComponentBase
import sonic_platform.hwaccess as hwaccess
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
def get_bios_version():
return subprocess.check_output(['dmidecode', '-s', 'system-version']).strip()
def get_fpga_version():
val = hwaccess.pci_get_value('/sys/bus/pci/devices/0000:03:00.0/resource0', 0)
return '{}.{}'.format((val >> 8) & 0xff, val & 0xff)
def get_bmc_version():
return subprocess.check_output(
['cat', '/sys/class/ipmi/ipmi0/device/bmc/firmware_revision']
).strip()
def get_cpld_version(bus, i2caddr):
return '{}.{}'.format(hwaccess.i2c_get(bus, i2caddr, 1),
hwaccess.i2c_get(bus, i2caddr, 0)
)
def get_cpld0_version():
return get_cpld_version(601, 0x31)
def get_cpld1_version():
return get_cpld_version(600, 0x30)
class Component(ComponentBase):
"""DellEMC Platform-specific Component class"""
CHASSIS_COMPONENTS = [
['BIOS',
'Performs initialization of hardware components during booting',
get_bios_version
],
['FPGA',
'Used for managing the system LEDs',
get_fpga_version
],
['BMC',
'Platform management controller for on-board temperature monitoring, in-chassis power, Fan and LED control',
get_bmc_version
],
['System CPLD',
'Used for managing the CPU power sequence and CPU states',
get_cpld0_version
],
['Slave CPLD 1',
'Used for managing SFP28/QSFP28 port transceivers (SFP28 1-24, QSFP28 1-4)',
get_cpld1_version
]
]
def __init__(self, component_index = 0):
self.index = component_index
self.name = self.CHASSIS_COMPONENTS[self.index][0]
self.description = self.CHASSIS_COMPONENTS[self.index][1]
self.version = self.CHASSIS_COMPONENTS[self.index][2]()
def get_name(self):
"""
Retrieves the name of the component
Returns:
A string containing the name of the component
"""
return self.name
def get_description(self):
"""
Retrieves the description of the component
Returns:
A string containing the description of the component
"""
return self.description
def get_firmware_version(self):
"""
Retrieves the firmware version of the component
Returns:
A string containing the firmware version of the component
"""
return self.version
def install_firmware(self, image_path):
"""
Installs firmware to the component
Args:
image_path: A string, path to firmware image
Returns:
A boolean, True if install was successful, False if not
"""
return False

View File

@ -0,0 +1,133 @@
#!/usr/bin/env python
#############################################################################
# DellEmc S5224F
#
# Platform and model specific eeprom subclass, inherits from the base class,
# and provides the followings:
# - the eeprom format definition
# - specific encoder/decoder if there is special need
#############################################################################
try:
import os.path
from sonic_eeprom import eeprom_tlvinfo
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
def __init__(self):
self.eeprom_path = None
for b in (0, 1):
f = '/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom'.format(b)
if os.path.exists(f):
self.eeprom_path = f
break
if self.eeprom_path is None:
return
super(Eeprom, self).__init__(self.eeprom_path, 0, '', True)
self.eeprom_tlv_dict = dict()
try:
self.eeprom_data = self.read_eeprom()
except Exception:
self.eeprom_data = "N/A"
raise RuntimeError("Eeprom is not Programmed")
eeprom = self.eeprom_data
if not self.is_valid_tlvinfo_header(eeprom):
return
total_length = (eeprom[9] << 8) | eeprom[10]
tlv_index = self._TLV_INFO_HDR_LEN
tlv_end = self._TLV_INFO_HDR_LEN + total_length
while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end:
if not self.is_valid_tlv(eeprom[tlv_index:]):
break
tlv = eeprom[tlv_index:tlv_index + 2
+ eeprom[tlv_index + 1]]
code = "0x%02X" % tlv[0]
name, value = self.decoder(None, tlv)
self.eeprom_tlv_dict[code] = value
if eeprom[tlv_index] == self._TLV_CODE_CRC_32:
break
tlv_index += eeprom[tlv_index+1] + 2
def serial_number_str(self):
"""
Returns the serial number
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_SERIAL_NUMBER)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def base_mac_addr(self, e):
"""
Returns the base mac address found in the system EEPROM
"""
(is_valid, t) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_MAC_BASE)
if not is_valid or t[1] != 6:
return super(eeprom_tlvinfo.TlvInfoDecoder, self).switchaddrstr(t)
return ":".join(["{:02x}".format(T) for T in t[2]]).upper()
def modelstr(self):
"""
Returns the Model name
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_PRODUCT_NAME)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def part_number_str(self):
"""
Returns the part number
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_PART_NUMBER)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def serial_str(self):
"""
Returns the servicetag number
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_SERVICE_TAG)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def revision_str(self):
"""
Returns the device revision
"""
(is_valid, results) = self.get_tlv_field(
self.eeprom_data, self._TLV_CODE_DEVICE_VERSION)
if not is_valid:
return "N/A"
return results[2].decode('ascii')
def system_eeprom_info(self):
"""
Returns a dictionary, where keys are the type code defined in
ONIE EEPROM format and values are their corresponding values
found in the system EEPROM.
"""
return self.eeprom_tlv_dict

View File

@ -0,0 +1,185 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fans' information which are available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_base import FanBase
from sonic_platform.ipmihelper import IpmiSensor, IpmiFru
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
FAN1_MAX_SPEED_OFFSET = 71
FAN2_MAX_SPEED_OFFSET = 73
PSU_FAN_MAX_SPEED_OFFSET = 50
FAN_DIRECTION_OFFSET = 69
PSU_FAN_DIRECTION_OFFSET = 47
class Fan(FanBase):
"""DellEMC Platform-specific Fan class"""
# { FAN-ID: { Sensor-Name: Sensor-ID } }
# System rev X01, BMC firmware rev 1.02
FAN_SENSOR_MAPPING = { 1: {"Prsnt": 0x53, "State": 0x57, "Speed": 0x24},
2: {"Prsnt": 0x53, "State": 0x5b, "Speed": 0x20},
3: {"Prsnt": 0x54, "State": 0x58, "Speed": 0x25},
4: {"Prsnt": 0x54, "State": 0x5c, "Speed": 0x21},
5: {"Prsnt": 0x55, "State": 0x59, "Speed": 0x26},
6: {"Prsnt": 0x55, "State": 0x5d, "Speed": 0x22},
7: {"Prsnt": 0x56, "State": 0x5a, "Speed": 0x27},
8: {"Prsnt": 0x56, "State": 0x5e, "Speed": 0x23}
}
PSU_FAN_SENSOR_MAPPING = { 1: {"State": 0x31, "Speed": 0x28},
2: {"State": 0x32, "Speed": 0x29} }
# { FANTRAY-ID: FRU-ID }
FAN_FRU_MAPPING = { 1: 3, 2: 4, 3: 5, 4: 6 }
PSU_FRU_MAPPING = { 1: 1, 2: 2 }
def __init__(self, fantray_index=1, fan_index=1, psu_fan=False,
dependency=None):
FanBase.__init__(self)
self.is_psu_fan = psu_fan
if not self.is_psu_fan:
# API index is starting from 0, DellEMC platform index is
# starting from 1
self.fantrayindex = fantray_index + 1
self.fanindex = fan_index + 1
if (self.fanindex == 1):
self.max_speed_offset = FAN1_MAX_SPEED_OFFSET
else:
self.max_speed_offset = FAN2_MAX_SPEED_OFFSET
self.fan_direction_offset = FAN_DIRECTION_OFFSET
self.index = (self.fantrayindex - 1) * 2 + self.fanindex
self.prsnt_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Prsnt"],
is_discrete=True)
self.state_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["State"],
is_discrete=True)
self.speed_sensor = IpmiSensor(self.FAN_SENSOR_MAPPING[self.index]["Speed"])
self.fru = IpmiFru(self.FAN_FRU_MAPPING[self.fantrayindex])
else:
self.dependency = dependency
self.fanindex = fan_index
self.state_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["State"],
is_discrete=True)
self.speed_sensor = IpmiSensor(self.PSU_FAN_SENSOR_MAPPING[self.fanindex]["Speed"])
self.fru = IpmiFru(self.PSU_FRU_MAPPING[self.fanindex])
self.max_speed_offset = PSU_FAN_MAX_SPEED_OFFSET
self.fan_direction_offset = PSU_FAN_DIRECTION_OFFSET
self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1]
self.max_speed = self.max_speed[1] << 8 | self.max_speed[0]
def get_name(self):
"""
Retrieves the name of the device
Returns:
String: The name of the device
"""
if self.is_psu_fan:
return "PSU{} Fan".format(self.fanindex)
else:
return "FanTray{}-Fan{}".format(self.fantrayindex, self.fanindex)
def get_model(self):
"""
Retrieves the part number of the FAN
Returns:
String: Part number of FAN
"""
if self.is_psu_fan:
return None
else:
return self.fru.get_board_part_number()
def get_serial(self):
"""
Retrieves the serial number of the FAN
Returns:
String: Serial number of FAN
"""
if self.is_psu_fan:
return None
else:
return self.fru.get_board_serial()
def get_presence(self):
"""
Retrieves the presence of the FAN
Returns:
bool: True if fan is present, False if not
"""
presence = False
if self.is_psu_fan:
return self.dependency.get_presence()
else:
is_valid, state = self.prsnt_sensor.get_reading()
if is_valid:
if (state & 0b1):
presence = True
return presence
def get_status(self):
"""
Retrieves the operational status of the FAN
Returns:
bool: True if FAN is operating properly, False if not
"""
status = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if not state > 1:
status = True
return status
def get_direction(self):
"""
Retrieves the fan airfow direction
Returns:
A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST
depending on fan direction
Notes:
In DellEMC platforms,
- Forward/Exhaust : Air flows from Port side to Fan side.
- Reverse/Intake : Air flows from Fan side to Port side.
"""
direction = [self.FAN_DIRECTION_EXHAUST, self.FAN_DIRECTION_INTAKE]
fan_status = self.get_presence()
if not fan_status:
return None
is_valid, fan_direction = self.fru.get_fru_data(self.fan_direction_offset)
if is_valid and fan_direction[0] < len(direction):
return direction[fan_direction[0]]
else:
return None
def get_speed(self):
"""
Retrieves the speed of the fan
Returns:
int: percentage of the max fan speed
"""
if self.max_speed == 0:
self.max_speed = self.fru.get_fru_data(self.max_speed_offset,2)[1]
self.max_speed = self.max_speed[1] << 8 | self.max_speed[0]
is_valid, fan_speed = self.speed_sensor.get_reading()
if not is_valid or self.max_speed == 0:
return None
else:
speed = (100 * fan_speed)//self.max_speed
return speed
def get_speed_rpm(self):
"""
Retrieves the speed of the fan
Returns:
int: percentage of the max fan speed
"""
fan_speed = 0
is_valid, fan_speed = self.speed_sensor.get_reading()
return fan_speed if is_valid else None

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Fan-Drawers' information available in the platform.
#
########################################################################
try:
from sonic_platform_base.fan_drawer_base import FanDrawerBase
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
S5224F_FANS_PER_FANTRAY = 2
class FanDrawer(FanDrawerBase):
"""DellEMC Platform-specific Fan class"""
def __init__(self, fantray_index):
FanDrawerBase.__init__(self)
# FanTray is 1-based in DellEMC platforms
self.fantrayindex = fantray_index + 1
for i in range(S5224F_FANS_PER_FANTRAY):
self._fan_list.append(Fan(fantray_index, i))
def get_name(self):
"""
Retrieves the fan drawer name
Returns:
string: The name of the device
"""
return "FanTray{}".format(self.fantrayindex)

View File

@ -0,0 +1 @@
../../common/sonic_platform/hwaccess.py

View File

@ -0,0 +1,269 @@
#!/usr/bin/python3
########################################################################
# DellEMC
#
# Module contains implementation of IpmiSensor and IpmiFru classes that
# provide Sensor's and FRU's information respectively.
#
########################################################################
import subprocess
import re
# IPMI Request Network Function Codes
NetFn_SensorEvent = 0x04
NetFn_Storage = 0x0A
# IPMI Sensor Device Commands
Cmd_GetSensorReadingFactors = 0x23
Cmd_GetSensorThreshold = 0x27
Cmd_GetSensorReading = 0x2D
# IPMI FRU Device Commands
Cmd_ReadFRUData = 0x11
def get_ipmitool_raw_output(args):
"""
Returns a list the elements of which are the individual bytes of
ipmitool raw <cmd> command output.
"""
result_bytes = list()
result = ""
command = "ipmitool raw {}".format(args)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
universal_newlines=True, stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except EnvironmentError:
pass
for i in result.split():
result_bytes.append(int(i, 16))
return result_bytes
class IpmiSensor(object):
# Sensor Threshold types and their respective bit masks
THRESHOLD_BIT_MASK = {
"LowerNonCritical" : 0,
"LowerCritical" : 1,
"LowerNonRecoverable" : 2,
"UpperNonCritical" : 3,
"UpperCritical" : 4,
"UpperNonRecoverable" : 5
}
def __init__(self, sensor_id, is_discrete=False):
self.id = sensor_id
self.is_discrete = is_discrete
def _get_converted_sensor_reading(self, raw_value):
"""
Returns a 2 element tuple(bool, int) in which first element
provides the validity of the reading and the second element is
the converted sensor reading
"""
# Get Sensor Reading Factors
cmd_args = "{} {} {} {}".format(NetFn_SensorEvent,
Cmd_GetSensorReadingFactors,
self.id, raw_value)
factors = get_ipmitool_raw_output(cmd_args)
if len(factors) != 7:
return False, 0
# Compute Twos complement
def get_twos_complement(val, bits):
if val & (1 << (bits - 1)):
val = val - (1 << bits)
return val
# Calculate actual sensor value from the raw sensor value
# using the sensor reading factors.
M = get_twos_complement(((factors[2] & 0xC0) << 8) | factors[1], 10)
B = get_twos_complement(((factors[4] & 0xC0) << 8) | factors[3], 10)
R_exp = get_twos_complement((factors[6] & 0xF0) >> 4, 4)
B_exp = get_twos_complement(factors[6] & 0x0F, 4)
converted_reading = ((M * raw_value) + (B * 10**B_exp)) * 10**R_exp
return True, converted_reading
def get_reading(self):
"""
For Threshold sensors, returns the sensor reading.
For Discrete sensors, returns the state value.
Returns:
A tuple (bool, int) where the first element provides the
validity of the reading and the second element provides the
sensor reading/state value.
"""
# Get Sensor Reading
cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorReading,
self.id)
output = get_ipmitool_raw_output(cmd_args)
if len(output) != 4:
return False, 0
# Check reading/state unavailable
if output[1] & 0x20:
return False, 0
if self.is_discrete:
state = ((output[3] & 0x7F) << 8) | output[2]
return True, state
else:
return self._get_converted_sensor_reading(output[0])
def get_threshold(self, threshold_type):
"""
Returns the sensor's threshold value for a given threshold type.
Args:
threshold_type (str) - one of the below mentioned
threshold type strings
"LowerNonCritical"
"LowerCritical"
"LowerNonRecoverable"
"UpperNonCritical"
"UpperCritical"
"UpperNonRecoverable"
Returns:
A tuple (bool, int) where the first element provides the
validity of that threshold and second element provides the
threshold value.
"""
# Thresholds are not valid for discrete sensors
if self.is_discrete:
raise TypeError("Threshold is not applicable for Discrete Sensor")
if threshold_type not in list(self.THRESHOLD_BIT_MASK.keys()):
raise ValueError("Invalid threshold type {} provided. Valid types "
"are {}".format(threshold_type,
list(self.THRESHOLD_BIT_MASK.keys())))
bit_mask = self.THRESHOLD_BIT_MASK[threshold_type]
# Get Sensor Threshold
cmd_args = "{} {} {}".format(NetFn_SensorEvent, Cmd_GetSensorThreshold,
self.id)
thresholds = get_ipmitool_raw_output(cmd_args)
if len(thresholds) != 7:
return False, 0
valid_thresholds = thresholds.pop(0)
# Check whether particular threshold is readable
if valid_thresholds & (1 << bit_mask):
return self._get_converted_sensor_reading(thresholds[bit_mask])
else:
return False, 0
class IpmiFru(object):
def __init__(self, fru_id):
self.id = fru_id
def _get_ipmitool_fru_print(self):
result = ""
command = "ipmitool fru print {}".format(self.id)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
universal_newlines=True, stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except EnvironmentError:
pass
return result
def _get_from_fru(self, info):
"""
Returns a string containing the info from FRU
"""
fru_output = self._get_ipmitool_fru_print()
if not fru_output:
return "NA"
info_req = re.search(r"%s\s*:(.*)" % info, fru_output)
if not info_req:
return "NA"
return info_req.group(1).strip()
def get_board_serial(self):
"""
Returns a string containing the Serial Number of the device.
"""
return self._get_from_fru('Board Serial')
def get_board_part_number(self):
"""
Returns a string containing the Part Number of the device.
"""
return self._get_from_fru('Board Part Number')
def get_board_mfr_id(self):
"""
Returns a string containing the manufacturer id of the FRU.
"""
return self._get_from_fru('Board Mfg')
def get_board_product(self):
"""
Returns a string containing the manufacturer id of the FRU.
"""
return self._get_from_fru('Board Product')
def get_fru_data(self, offset, count=1):
"""
Reads and returns the FRU data at the provided offset.
Args:
offset (int) - FRU offset to read
count (int) - Number of bytes to read [optional, default = 1]
Returns:
A tuple (bool, list(int)) where the first element provides
the validity of the data read and the second element is a
list, the elements of which are the individual bytes of the
FRU data read.
"""
result_bytes = list()
is_valid = True
result = ""
offset_LSB = offset & 0xFF
offset_MSB = offset & 0xFF00
command = "ipmitool raw {} {} {} {} {} {}".format(NetFn_Storage,
Cmd_ReadFRUData,
self.id, offset_LSB,
offset_MSB, count)
try:
proc = subprocess.Popen(command.split(), stdout=subprocess.PIPE,
universal_newlines=True, stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
if not proc.returncode:
result = stdout.rstrip('\n')
except EnvironmentError:
is_valid = False
if (not result) or (not is_valid):
return False, result_bytes
for i in result.split():
result_bytes.append(int(i, 16))
read_count = result_bytes.pop(0)
if read_count != count:
return False, result_bytes
else:
return True, result_bytes

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python
#############################################################################
# DellEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the platform information
#
#############################################################################
try:
from sonic_platform_base.platform_base import PlatformBase
from sonic_platform.chassis import Chassis
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Platform(PlatformBase):
"""
DELLEMC Platform-specific class
"""
def __init__(self):
PlatformBase.__init__(self)
self._chassis = Chassis()

View File

@ -0,0 +1,230 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the PSUs' information which are available in the platform
#
########################################################################
try:
from sonic_platform_base.psu_base import PsuBase
from sonic_platform.ipmihelper import IpmiSensor, IpmiFru
from sonic_platform.fan import Fan
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Psu(PsuBase):
"""DellEMC Platform-specific PSU class"""
# { PSU-ID: { Sensor-Name: Sensor-ID } }
SENSOR_MAPPING = { 1: { "State": 0x31, "Current": 0x39,
"Power": 0x37, "Voltage": 0x38,
"InCurrent": 0x36, "InPower": 0x34,
"InVoltage": 0x35 },
2: { "State": 0x32, "Current": 0x3F,
"Power": 0x3D, "Voltage": 0x3E,
"InCurrent": 0x3C, "InPower": 0x3A,
"InVoltage": 0x3B } }
# ( PSU-ID: FRU-ID }
FRU_MAPPING = { 1: 1, 2: 2 }
def __init__(self, psu_index):
PsuBase.__init__(self)
# PSU is 1-based in DellEMC platforms
self.index = psu_index + 1
self.state_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["State"],
is_discrete=True)
self.voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Voltage"])
self.current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Current"])
self.power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["Power"])
self.input_voltage_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InVoltage"])
self.input_current_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InCurrent"])
self.input_power_sensor = IpmiSensor(self.SENSOR_MAPPING[self.index]["InPower"])
self.fru = IpmiFru(self.FRU_MAPPING[self.index])
self._fan_list.append(Fan(fan_index=self.index, psu_fan=True,
dependency=self))
def get_name(self):
"""
Retrieves the name of the device
Returns:
string: The name of the device
"""
return "PSU{}".format(self.index)
def get_presence(self):
"""
Retrieves the presence of the Power Supply Unit (PSU)
Returns:
bool: True if PSU is present, False if not
"""
presence = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state & 0b1):
presence = True
return presence
def get_model(self):
"""
Retrieves the part number of the PSU
Returns:
string: Part number of PSU
"""
return self.fru.get_board_part_number()
def get_serial(self):
"""
Retrieves the serial number of the PSU
Returns:
string: Serial number of PSU
"""
return self.fru.get_board_serial()
def get_status(self):
"""
Retrieves the operational status of the PSU
Returns:
bool: True if PSU is operating properly, False if not
"""
status = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state == 0x01):
status = True
return status
def get_voltage(self):
"""
Retrieves current PSU voltage output
Returns:
A float number, the output voltage in volts,
e.g. 12.1
"""
is_valid, voltage = self.voltage_sensor.get_reading()
if not is_valid:
return None
return "{:.1f}".format(voltage)
def get_current(self):
"""
Retrieves present electric current supplied by PSU
Returns:
A float number, electric current in amperes,
e.g. 15.4
"""
is_valid, current = self.current_sensor.get_reading()
if not is_valid:
return None
return "{:.1f}".format(current)
def get_power(self):
"""
Retrieves current energy supplied by PSU
Returns:
A float number, the power in watts,
e.g. 302.6
"""
is_valid, power = self.power_sensor.get_reading()
if not is_valid:
return None
return "{:.1f}".format(power)
def get_input_voltage(self):
"""
Retrieves current PSU voltage input
Returns:
A float number, the input voltage in volts,
e.g. 12.1
"""
is_valid, input_voltage = self.input_voltage_sensor.get_reading()
if not is_valid:
return None
return "{:.1f}".format(input_voltage)
def get_input_current(self):
"""
Retrieves present electric current supplied to PSU
Returns:
A float number, electric current in amperes,
e.g. 15.4
"""
is_valid, input_current = self.input_current_sensor.get_reading()
if not is_valid:
return None
return "{:.1f}".format(input_current)
def get_input_power(self):
"""
Retrieves current energy supplied to PSU
Returns:
A float number, the power in watts,
e.g. 302.6
"""
is_valid, input_power = self.input_power_sensor.get_reading()
if not is_valid:
return None
return "{:.1f}".format(input_power)
def get_powergood_status(self):
"""
Retrieves the powergood status of PSU
Returns:
A boolean, True if PSU has stablized its output voltages and
passed all its internal self-tests, False if not.
"""
status = False
is_valid, state = self.state_sensor.get_reading()
if is_valid:
if (state == 0x01):
status = True
return status
def get_mfr_id(self):
"""
Retrives the Manufacturer Id of PSU
Returns:
A string, the manunfacturer id.
"""
return self.fru.get_board_mfr_id()
def get_type(self):
"""
Retrives the Power Type of PSU
Returns :
A string, PSU power type
"""
board_product = self.fru.get_board_product()
if board_product is not None :
info = board_product.split(',')
if 'AC' in info : return 'AC'
if 'DC' in info : return 'DC'
return None

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,170 @@
#!/usr/bin/env python
########################################################################
# DellEMC S5224F
#
# Module contains an implementation of SONiC Platform Base API and
# provides the Thermals' information which are available in the platform
#
########################################################################
try:
from sonic_platform_base.thermal_base import ThermalBase
from sonic_platform.ipmihelper import IpmiSensor
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class Thermal(ThermalBase):
"""DellEMC Platform-specific Thermal class"""
# [ Sensor-Name, Sensor-ID ]
SENSOR_MAPPING = [
['CPU On-board', 0xe],
['ASIC On-board', 0x2],
['System Front Left', 0x3],
['System Front Middle', 0x1],
['System Front Right', 0x4],
['Inlet Airflow Sensor', 0x5],
['PSU1 Airflow Sensor', 0x7],
['PSU2 Airflow Sensor', 0x8]
]
def __init__(self, thermal_index):
ThermalBase.__init__(self)
self.index = thermal_index + 1
self.sensor = IpmiSensor(self.SENSOR_MAPPING[self.index - 1][1])
def get_name(self):
"""
Retrieves the name of the thermal
Returns:
string: The name of the thermal
"""
return self.SENSOR_MAPPING[self.index - 1][0]
def get_presence(self):
"""
Retrieves the presence of the thermal
Returns:
bool: True if thermal is present, False if not
"""
return True
def get_model(self):
"""
Retrieves the model number (or part number) of the Thermal
Returns:
string: Model/part number of Thermal
"""
return 'NA'
def get_serial(self):
"""
Retrieves the serial number of the Thermal
Returns:
string: Serial number of Thermal
"""
return 'NA'
def get_status(self):
"""
Retrieves the operational status of the thermal
Returns:
A boolean value, True if thermal is operating properly,
False if not
"""
return True
def get_temperature(self):
"""
Retrieves current temperature reading from thermal
Returns:
A float number of current temperature in Celsius up to
nearest thousandth of one degree Celsius, e.g. 30.125
"""
is_valid, temperature = self.sensor.get_reading()
if not is_valid:
temperature = 0
return float(temperature)
def get_high_threshold(self):
"""
Retrieves the high threshold temperature of thermal
Returns:
A float number, the high threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
is_valid, high_threshold = self.sensor.get_threshold("UpperNonCritical")
if not is_valid:
return super(Thermal, self).get_high_threshold()
return float(high_threshold)
def get_high_critical_threshold(self):
"""
Retrieves the high critical threshold temperature of thermal
Returns:
A float number, the high critical threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
is_valid, high_crit_threshold = self.sensor.get_threshold("UpperCritical")
if not is_valid:
return super(Thermal, self).get_high_critical_threshold()
return float(high_crit_threshold)
def get_low_threshold(self):
"""
Retrieves the low threshold temperature of thermal
Returns:
A float number, the low threshold temperature of thermal in
Celsius up to nearest thousandth of one degree Celsius,
e.g. 30.125
"""
is_valid, low_threshold = self.sensor.get_threshold("LowerNonRecoverable")
if not is_valid:
low_threshold = 0
return float(low_threshold)
def set_high_threshold(self, temperature):
"""
Sets the high threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one
degree Celsius, e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if
not
"""
# Thermal threshold values are pre-defined based on HW.
return False
def set_low_threshold(self, temperature):
"""
Sets the low threshold temperature of thermal
Args :
temperature: A float number up to nearest thousandth of one
degree Celsius, e.g. 30.125
Returns:
A boolean, True if threshold is set successfully, False if
not
"""
# Thermal threshold values are pre-defined based on HW.
return False

View File

@ -0,0 +1,212 @@
#!/usr/bin/env python
########################################################################
#
# DELLEMC S5248f
#
# Abstract base class for implementing a platform-specific class with
# which to interact with a hardware watchdog module in SONiC
#
########################################################################
try:
import ctypes
import subprocess
import syslog
import sonic_platform.component as Component
from sonic_platform_base.watchdog_base import WatchdogBase
except ImportError as e:
raise ImportError(str(e) + "- required module not found")
class _timespec(ctypes.Structure):
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
class Watchdog(WatchdogBase):
"""
Abstract base class for interfacing with a hardware watchdog module
"""
TIMERS = [15,20,30,40,50,60,65,70,80,100,120,140,160,180,210,240]
armed_time = 0
timeout = 0
CLOCK_MONOTONIC = 1
def __init__(self):
self._librt = ctypes.CDLL('librt.so.1', use_errno=True)
self._clock_gettime = self._librt.clock_gettime
self._clock_gettime.argtypes=[ctypes.c_int, ctypes.POINTER(_timespec)]
def _get_command_result(self, cmdline):
try:
proc = subprocess.Popen(cmdline.split(), stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
stdout = proc.communicate()[0]
proc.wait()
result = stdout.rstrip('\n'.encode())
except OSError:
result = None
return result
def _get_reg_val(self):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cget -y 601 0x31 0x07")
if not value:
return None
else:
return int(value, 16)
def _set_reg_val(self,val):
# 0x31 = CPLD I2C Base Address
# 0x07 = Watchdog Function Register
value = self._get_command_result("/usr/sbin/i2cset -y 601 0x31 0x07 %s"
% (val))
return value
def _get_time(self):
"""
To get clock monotonic time
"""
ts = _timespec()
if self._clock_gettime(self.CLOCK_MONOTONIC, ctypes.pointer(ts)) != 0:
self._errno = ctypes.get_errno()
return 0
return ts.tv_sec + ts.tv_nsec * 1e-9
def arm(self, seconds):
"""
Arm the hardware watchdog with a timeout of <seconds> seconds.
If the watchdog is currently armed, calling this function will
simply reset the timer to the provided value. If the underlying
hardware does not support the value provided in <seconds>, this
method should arm the watchdog with the *next greater*
available value.
Returns:
An integer specifying the *actual* number of seconds the
watchdog was armed with. On failure returns -1.
"""
timer_offset = -1
for key,timer_seconds in enumerate(self.TIMERS):
if seconds <= timer_seconds:
timer_offset = key
seconds = timer_seconds
break
if timer_offset == -1:
return -1
cpld_version = Component.get_cpld0_version()
wd_enabled_version = "0.8"
if cpld_version < wd_enabled_version:
syslog.syslog(syslog.LOG_ERR,
'Older System CPLD ver, Update to 0.8 to support watchdog ')
return -1
# Extracting 5th to 8th bits for WD timer values
reg_val = self._get_reg_val()
wd_timer_offset = (reg_val >> 4) & 0xf
if wd_timer_offset != timer_offset:
# Setting 5th to 7th bits
# value from timer_offset
self.disarm()
self._set_reg_val((reg_val & 0x07) | (timer_offset << 4))
if self.is_armed():
# Setting last bit to WD Timer punch
# Last bit = WD Timer punch
self._set_reg_val(reg_val & 0xFE)
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
else:
# Setting 4th bit to enable WD
# 4th bit = Enable WD
reg_val = self._get_reg_val()
self._set_reg_val(reg_val | 0x8)
self.armed_time = self._get_time()
self.timeout = seconds
return seconds
def disarm(self):
"""
Disarm the hardware watchdog
Returns:
A boolean, True if watchdog is disarmed successfully, False
if not
"""
if self.is_armed():
# Setting 4th bit to disable WD
# 4th bit = Disable WD
reg_val = self._get_reg_val()
self._set_reg_val(reg_val & 0xF7)
self.armed_time = 0
self.timeout = 0
return True
return False
def is_armed(self):
"""
Retrieves the armed state of the hardware watchdog.
Returns:
A boolean, True if watchdog is armed, False if not
"""
# Extracting 4th bit to get WD Enable/Disable status
# 0 - Disabled WD
# 1 - Enabled WD
reg_val = self._get_reg_val()
wd_offset = (reg_val >> 3) & 1
return bool(wd_offset)
def get_remaining_time(self):
"""
If the watchdog is armed, retrieve the number of seconds
remaining on the watchdog timer
Returns:
An integer specifying the number of seconds remaining on
their watchdog timer. If the watchdog is not armed, returns
-1.
S5224f doesnot have hardware support to show remaining time.
Due to this limitation, this API is implemented in software.
This API would return correct software time difference if it
is called from the process which armed the watchdog timer.
If this API called from any other process, it would return
0. If the watchdog is not armed, this API would return -1.
"""
if not self.is_armed():
return -1
if self.armed_time > 0 and self.timeout != 0:
cur_time = self._get_time()
if cur_time <= 0:
return 0
diff_time = int(cur_time - self.armed_time)
if diff_time > self.timeout:
return self.timeout
else:
return self.timeout - diff_time
return 0

View File

@ -0,0 +1,13 @@
[Unit]
Description=Dell S5224f Platform modules
Before=pmon.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/usr/local/bin/s5224f_platform.sh init
ExecStop=/usr/local/bin/s5224f_platform.sh deinit
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target