DellEMC: N3248TE Initial platform commit (#8809)
Why I did it Added support for the device N3248TE How I did it Implemented the support for the platform N3248TE Switch Vendor: DellEMC Switch SKU: N3248TE ASIC Vendor: Broadcom SONiC Image: sonic-broadcom.bin How to verify it Verified the show platform commands
This commit is contained in:
parent
27aef53054
commit
8325500560
@ -0,0 +1,2 @@
|
||||
{%- set default_topo = 't0' %}
|
||||
{%- include 'buffers_config.j2' %}
|
@ -0,0 +1,41 @@
|
||||
{%- set default_cable = '5m' %}
|
||||
|
||||
{%- macro generate_port_lists(PORT_ALL) %}
|
||||
{# Generate list of ports #}
|
||||
{% for port_idx in range(0,32) %}
|
||||
{% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %}
|
||||
{% endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro generate_buffer_pool_and_profiles() %}
|
||||
"BUFFER_POOL": {
|
||||
"ingress_lossless_pool": {
|
||||
"size": "8192000",
|
||||
"type": "ingress",
|
||||
"mode": "dynamic",
|
||||
"xoff": "196608"
|
||||
},
|
||||
"egress_lossless_pool": {
|
||||
"size": "8388608",
|
||||
"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",
|
||||
"static_th":"8388608"
|
||||
},
|
||||
"egress_lossy_profile": {
|
||||
"pool":"[BUFFER_POOL|egress_lossless_pool]",
|
||||
"size":"1518",
|
||||
"dynamic_th":"3"
|
||||
}
|
||||
},
|
||||
{%- endmacro %}
|
@ -0,0 +1,41 @@
|
||||
{%- set default_cable = '300m' %}
|
||||
|
||||
{%- macro generate_port_lists(PORT_ALL) %}
|
||||
{# Generate list of ports #}
|
||||
{% for port_idx in range(0,32) %}
|
||||
{% if PORT_ALL.append("Ethernet%d" % (port_idx * 4)) %}{% endif %}
|
||||
{% endfor %}
|
||||
{%- endmacro %}
|
||||
|
||||
{%- macro generate_buffer_pool_and_profiles() %}
|
||||
"BUFFER_POOL": {
|
||||
"ingress_lossless_pool": {
|
||||
"size": "8192000",
|
||||
"type": "ingress",
|
||||
"mode": "dynamic",
|
||||
"xoff": "196608"
|
||||
},
|
||||
"egress_lossless_pool": {
|
||||
"size": "8388608",
|
||||
"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",
|
||||
"static_th":"8388608"
|
||||
},
|
||||
"egress_lossy_profile": {
|
||||
"pool":"[BUFFER_POOL|egress_lossless_pool]",
|
||||
"size":"1518",
|
||||
"dynamic_th":"3"
|
||||
}
|
||||
},
|
||||
{%- endmacro %}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"copp_rx_rate":15000
|
||||
}
|
@ -0,0 +1,145 @@
|
||||
{
|
||||
"COPP_GROUP": {
|
||||
"copp-system-lacp": {
|
||||
"cir":"250",
|
||||
"cbs":"250"
|
||||
},
|
||||
"copp-system-udld": {
|
||||
"cir":"250",
|
||||
"cbs":"250"
|
||||
},
|
||||
"copp-system-stp": {
|
||||
"cir":"8000",
|
||||
"cbs":"8000"
|
||||
},
|
||||
"copp-system-bfd": {
|
||||
"cir":"750",
|
||||
"cbs":"750"
|
||||
},
|
||||
"copp-system-lldp": {
|
||||
"cir":"250",
|
||||
"cbs":"250"
|
||||
},
|
||||
"copp-system-vrrp": {
|
||||
"cir":"250",
|
||||
"cbs":"250"
|
||||
},
|
||||
"copp-system-iccp": {
|
||||
"cir":"2500",
|
||||
"cbs":"2500"
|
||||
},
|
||||
"copp-system-ospf": {
|
||||
"cir":"2500",
|
||||
"cbs":"2500"
|
||||
},
|
||||
"copp-system-bgp": {
|
||||
"cir":"5000",
|
||||
"cbs":"5000"
|
||||
},
|
||||
"copp-system-pim": {
|
||||
"cir":"2500",
|
||||
"cbs":"2500"
|
||||
},
|
||||
"copp-system-igmp": {
|
||||
"cir":"1000",
|
||||
"cbs":"1000"
|
||||
},
|
||||
"copp-system-suppress": {
|
||||
"cir":"1500",
|
||||
"cbs":"1500"
|
||||
},
|
||||
"copp-system-arp": {
|
||||
"cir":"1500",
|
||||
"cbs":"1500"
|
||||
},
|
||||
"copp-system-dhcp": {
|
||||
"cir":"150",
|
||||
"cbs":"150"
|
||||
},
|
||||
"copp-system-icmp": {
|
||||
"cir":"500",
|
||||
"cbs":"500"
|
||||
},
|
||||
"copp-system-ip2me": {
|
||||
"cir":"3000",
|
||||
"cbs":"3000"
|
||||
},
|
||||
"copp-system-subnet": {
|
||||
"cir":"1000",
|
||||
"cbs":"1000"
|
||||
},
|
||||
"copp-system-mtu": {
|
||||
"cir":"250",
|
||||
"cbs":"250"
|
||||
},
|
||||
"copp-system-sflow": {
|
||||
"cir":"4000",
|
||||
"cbs":"4000"
|
||||
}
|
||||
},
|
||||
"SCHEDULER": {
|
||||
"copp-scheduler-policy@23": {
|
||||
"pir": "250"
|
||||
},
|
||||
"copp-scheduler-policy@22": {
|
||||
"pir": "250"
|
||||
},
|
||||
"copp-scheduler-policy@21": {
|
||||
"pir": "8000"
|
||||
},
|
||||
"copp-scheduler-policy@20": {
|
||||
"pir": "750"
|
||||
},
|
||||
"copp-scheduler-policy@19": {
|
||||
"pir": "2500"
|
||||
},
|
||||
"copp-scheduler-policy@18": {
|
||||
"pir": "250"
|
||||
},
|
||||
"copp-scheduler-policy@17": {
|
||||
"pir": "250"
|
||||
},
|
||||
"copp-scheduler-policy@16": {
|
||||
"pir": "2500"
|
||||
},
|
||||
"copp-scheduler-policy@15": {
|
||||
"pir": "2500"
|
||||
},
|
||||
"copp-scheduler-policy@14": {
|
||||
"pir": "5000"
|
||||
},
|
||||
"copp-scheduler-policy@13": {
|
||||
"pir": "2500"
|
||||
},
|
||||
"copp-scheduler-policy@12": {
|
||||
"pir": "1000"
|
||||
},
|
||||
"copp-scheduler-policy@11": {
|
||||
"pir": "1500"
|
||||
},
|
||||
"copp-scheduler-policy@10": {
|
||||
"pir": "1500"
|
||||
},
|
||||
"copp-scheduler-policy@9": {
|
||||
"pir": "150"
|
||||
},
|
||||
"copp-scheduler-policy@8": {
|
||||
"pir": "500"
|
||||
},
|
||||
"copp-scheduler-policy@7": {
|
||||
"pir": "3000"
|
||||
},
|
||||
"copp-scheduler-policy@6": {
|
||||
"pir": "1000"
|
||||
},
|
||||
"copp-scheduler-policy@4": {
|
||||
"pir": "250"
|
||||
},
|
||||
"copp-scheduler-policy@3": {
|
||||
"pir": "4000"
|
||||
},
|
||||
"copp-scheduler-policy@1": {
|
||||
"pir": "100"
|
||||
}
|
||||
}
|
||||
}
|
Binary file not shown.
@ -0,0 +1,260 @@
|
||||
bcm_num_cos=8
|
||||
bcm_stat_interval=2000000
|
||||
bcm_tunnel_term_compatible_mode=1
|
||||
cdma_timeout_usec=3000000
|
||||
core_clock_frequency=668
|
||||
flow_init_mode=0
|
||||
ifa_enable=0
|
||||
ifp_inports_support_enable=1
|
||||
ipv6_lpm_128b_enable=0x1
|
||||
l2xmsg_mode=1
|
||||
|
||||
#Default L3 profile
|
||||
|
||||
l2_mem_entries=32768
|
||||
l3_alpm_enable=2
|
||||
l3_alpm_ipv6_128b_bkt_rsvd=1
|
||||
l3_max_ecmp_mode=1
|
||||
l3_mem_entries=16348
|
||||
lpm_scaling_enable=0
|
||||
memlist_enable=1
|
||||
reglist_enable=1
|
||||
scache_filename=/tmp/brcm_bcm_scache
|
||||
schan_intr_enable=0
|
||||
stable_size=0x5500000
|
||||
tdma_timeout_usec=3000000
|
||||
|
||||
pfc_deadlock_seq_control=1
|
||||
|
||||
#Port and PHY configs
|
||||
|
||||
pbmp_xport_xe=0x1FFFFFFFFFFFFFFE
|
||||
port_gmii_mode_33=1
|
||||
port_gmii_mode_17=1
|
||||
port_gmii_mode_1=1
|
||||
portmap_1=1:1
|
||||
portmap_2=2:1
|
||||
portmap_3=3:1
|
||||
portmap_4=4:1
|
||||
portmap_5=5:1
|
||||
portmap_6=6:1
|
||||
portmap_7=7:1
|
||||
portmap_8=8:1
|
||||
portmap_9=9:1
|
||||
portmap_10=10:1
|
||||
portmap_11=11:1
|
||||
portmap_12=12:1
|
||||
portmap_13=13:1
|
||||
portmap_14=14:1
|
||||
portmap_15=15:1
|
||||
portmap_16=16:1
|
||||
portmap_17=17:1
|
||||
portmap_18=18:1
|
||||
portmap_19=19:1
|
||||
portmap_20=20:1
|
||||
portmap_21=21:1
|
||||
portmap_22=22:1
|
||||
portmap_23=23:1
|
||||
portmap_24=24:1
|
||||
portmap_25=25:1
|
||||
portmap_26=26:1
|
||||
portmap_27=27:1
|
||||
portmap_28=28:1
|
||||
portmap_29=29:1
|
||||
portmap_30=30:1
|
||||
portmap_31=31:1
|
||||
portmap_32=32:1
|
||||
portmap_33=33:1
|
||||
portmap_34=34:1
|
||||
portmap_35=35:1
|
||||
portmap_36=36:1
|
||||
portmap_37=37:1
|
||||
portmap_38=38:1
|
||||
portmap_39=39:1
|
||||
portmap_40=40:1
|
||||
portmap_41=41:1
|
||||
portmap_42=42:1
|
||||
portmap_43=43:1
|
||||
portmap_44=44:1
|
||||
portmap_45=45:1
|
||||
portmap_46=46:1
|
||||
portmap_47=47:1
|
||||
portmap_48=48:1
|
||||
portmap_49=64:10
|
||||
portmap_50=63:10
|
||||
portmap_51=62:10
|
||||
portmap_52=61:10
|
||||
portmap_53=69:100
|
||||
portmap_57=73:100
|
||||
phy_chain_tx_lane_map_physical{33.0}=0x2301
|
||||
phy_chain_rx_lane_map_physical{33.0}=0x2301
|
||||
phy_port_primary_and_offset_1=0x0100
|
||||
phy_port_primary_and_offset_2=0x0101
|
||||
phy_port_primary_and_offset_3=0x0102
|
||||
phy_port_primary_and_offset_4=0x0103
|
||||
phy_port_primary_and_offset_5=0x0104
|
||||
phy_port_primary_and_offset_6=0x0105
|
||||
phy_port_primary_and_offset_7=0x0106
|
||||
phy_port_primary_and_offset_8=0x0107
|
||||
phy_port_primary_and_offset_9=0x0900
|
||||
phy_port_primary_and_offset_10=0x0901
|
||||
phy_port_primary_and_offset_11=0x0902
|
||||
phy_port_primary_and_offset_12=0x0903
|
||||
phy_port_primary_and_offset_13=0x0904
|
||||
phy_port_primary_and_offset_14=0x0905
|
||||
phy_port_primary_and_offset_15=0x0906
|
||||
phy_port_primary_and_offset_16=0x0907
|
||||
phy_port_primary_and_offset_17=0x1200
|
||||
phy_port_primary_and_offset_18=0x1201
|
||||
phy_port_primary_and_offset_19=0x1202
|
||||
phy_port_primary_and_offset_20=0x1203
|
||||
phy_port_primary_and_offset_21=0x1204
|
||||
phy_port_primary_and_offset_22=0x1205
|
||||
phy_port_primary_and_offset_23=0x1206
|
||||
phy_port_primary_and_offset_24=0x1207
|
||||
phy_port_primary_and_offset_25=0x2000
|
||||
phy_port_primary_and_offset_26=0x2001
|
||||
phy_port_primary_and_offset_27=0x2002
|
||||
phy_port_primary_and_offset_28=0x2003
|
||||
phy_port_primary_and_offset_29=0x2004
|
||||
phy_port_primary_and_offset_30=0x2005
|
||||
phy_port_primary_and_offset_31=0x2006
|
||||
phy_port_primary_and_offset_32=0x2007
|
||||
phy_port_primary_and_offset_33=0x2900
|
||||
phy_port_primary_and_offset_34=0x2901
|
||||
phy_port_primary_and_offset_35=0x2902
|
||||
phy_port_primary_and_offset_36=0x2903
|
||||
phy_port_primary_and_offset_37=0x2904
|
||||
phy_port_primary_and_offset_38=0x2905
|
||||
phy_port_primary_and_offset_39=0x2906
|
||||
phy_port_primary_and_offset_40=0x2907
|
||||
phy_port_primary_and_offset_41=0x3200
|
||||
phy_port_primary_and_offset_42=0x3201
|
||||
phy_port_primary_and_offset_43=0x3202
|
||||
phy_port_primary_and_offset_44=0x3203
|
||||
phy_port_primary_and_offset_45=0x3204
|
||||
phy_port_primary_and_offset_46=0x3205
|
||||
phy_port_primary_and_offset_47=0x3206
|
||||
phy_port_primary_and_offset_48=0x3207
|
||||
port_phy_addr_1=0x0
|
||||
port_phy_addr_2=0x1
|
||||
port_phy_addr_3=0x2
|
||||
port_phy_addr_4=0x3
|
||||
port_phy_addr_5=0x4
|
||||
port_phy_addr_6=0x5
|
||||
port_phy_addr_7=0x6
|
||||
port_phy_addr_8=0x7
|
||||
port_phy_addr_9=0x9
|
||||
port_phy_addr_10=0xa
|
||||
port_phy_addr_11=0xb
|
||||
port_phy_addr_12=0xc
|
||||
port_phy_addr_13=0xd
|
||||
port_phy_addr_14=0xe
|
||||
port_phy_addr_15=0xf
|
||||
port_phy_addr_16=0x10
|
||||
port_phy_addr_17=0x12
|
||||
port_phy_addr_18=0x13
|
||||
port_phy_addr_19=0x14
|
||||
port_phy_addr_20=0x15
|
||||
port_phy_addr_21=0x16
|
||||
port_phy_addr_22=0x17
|
||||
port_phy_addr_23=0x18
|
||||
port_phy_addr_24=0x19
|
||||
port_phy_addr_25=0x20
|
||||
port_phy_addr_26=0x21
|
||||
port_phy_addr_27=0x22
|
||||
port_phy_addr_28=0x23
|
||||
port_phy_addr_29=0x24
|
||||
port_phy_addr_30=0x25
|
||||
port_phy_addr_31=0x26
|
||||
port_phy_addr_32=0x27
|
||||
port_phy_addr_33=0x29
|
||||
port_phy_addr_34=0x2a
|
||||
port_phy_addr_35=0x2b
|
||||
port_phy_addr_36=0x2c
|
||||
port_phy_addr_37=0x2d
|
||||
port_phy_addr_38=0x2e
|
||||
port_phy_addr_39=0x2f
|
||||
port_phy_addr_40=0x30
|
||||
port_phy_addr_41=0x32
|
||||
port_phy_addr_42=0x33
|
||||
port_phy_addr_43=0x34
|
||||
port_phy_addr_44=0x35
|
||||
port_phy_addr_45=0x36
|
||||
port_phy_addr_46=0x37
|
||||
port_phy_addr_47=0x38
|
||||
port_phy_addr_48=0x39
|
||||
port_phy_addr_49=0x40
|
||||
phy_force_firmware_load_50=0x01
|
||||
port_phy_addr_50=0x41
|
||||
phy_force_firmware_load_51=0x01
|
||||
port_phy_addr_51=0x42
|
||||
phy_force_firmware_load_52=0x01
|
||||
port_phy_addr_52=0x43
|
||||
phy_pcs_repeater_49=0x01
|
||||
phy_pcs_repeater_50=0x01
|
||||
phy_pcs_repeater_51=0x01
|
||||
phy_pcs_repeater_52=0x01
|
||||
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_13=13
|
||||
dport_map_port_14=14
|
||||
dport_map_port_15=15
|
||||
dport_map_port_16=16
|
||||
dport_map_port_17=17
|
||||
dport_map_port_18=18
|
||||
dport_map_port_19=19
|
||||
dport_map_port_20=20
|
||||
dport_map_port_21=21
|
||||
dport_map_port_22=22
|
||||
dport_map_port_23=23
|
||||
dport_map_port_24=24
|
||||
dport_map_port_25=25
|
||||
dport_map_port_26=26
|
||||
dport_map_port_27=27
|
||||
dport_map_port_28=28
|
||||
dport_map_port_29=29
|
||||
dport_map_port_30=30
|
||||
dport_map_port_31=31
|
||||
dport_map_port_32=32
|
||||
dport_map_port_33=33
|
||||
dport_map_port_34=34
|
||||
dport_map_port_35=35
|
||||
dport_map_port_36=36
|
||||
dport_map_port_37=37
|
||||
dport_map_port_38=38
|
||||
dport_map_port_39=39
|
||||
dport_map_port_40=40
|
||||
dport_map_port_41=41
|
||||
dport_map_port_42=42
|
||||
dport_map_port_43=43
|
||||
dport_map_port_44=44
|
||||
dport_map_port_45=45
|
||||
dport_map_port_46=46
|
||||
dport_map_port_47=47
|
||||
dport_map_port_48=48
|
||||
dport_map_port_49=49
|
||||
dport_map_port_50=50
|
||||
dport_map_port_51=51
|
||||
dport_map_port_52=52
|
||||
dport_map_port_53=53
|
||||
dport_map_port_54=54
|
||||
dport_map_port_55=55
|
||||
dport_map_port_56=56
|
||||
dport_map_port_57=57
|
||||
dport_map_port_58=58
|
||||
dport_map_port_59=59
|
||||
dport_map_port_60=60
|
||||
|
||||
sai_preinit_cmd_file=/usr/share/sonic/hwsku/sai_preinit_cmd.soc
|
||||
|
Binary file not shown.
@ -0,0 +1,17 @@
|
||||
# PG lossless profiles.
|
||||
# speed cable size xon xoff threshold xon_offset
|
||||
10000 5m 9427 0 50176 1 3584
|
||||
25000 5m 9427 0 50176 1 3584
|
||||
40000 5m 9427 0 50176 1 3584
|
||||
50000 5m 9427 0 50176 1 3584
|
||||
100000 5m 9427 0 50176 1 3584
|
||||
10000 40m 9427 0 50176 1 3584
|
||||
25000 40m 9427 0 50176 1 3584
|
||||
40000 40m 9427 0 50176 1 3584
|
||||
50000 40m 9427 0 50176 1 3584
|
||||
100000 40m 9427 0 50176 1 3584
|
||||
10000 300m 9427 0 50176 1 3584
|
||||
25000 300m 9427 0 50176 1 3584
|
||||
40000 300m 9427 0 50176 1 3584
|
||||
50000 300m 9427 0 50176 1 3584
|
||||
100000 300m 9427 0 50176 1 3584
|
@ -0,0 +1,55 @@
|
||||
# name lanes alias index speed autoneg
|
||||
Ethernet0 1 oneGigE1/1 1 1000 1
|
||||
Ethernet1 2 oneGigE1/2 2 1000 1
|
||||
Ethernet2 3 oneGigE1/3 3 1000 1
|
||||
Ethernet3 4 oneGigE1/4 4 1000 1
|
||||
Ethernet4 5 oneGigE1/5 5 1000 1
|
||||
Ethernet5 6 oneGigE1/6 6 1000 1
|
||||
Ethernet6 7 oneGigE1/7 7 1000 1
|
||||
Ethernet7 8 oneGigE1/8 8 1000 1
|
||||
Ethernet8 9 oneGigE1/9 9 1000 1
|
||||
Ethernet9 10 oneGigE1/10 10 1000 1
|
||||
Ethernet10 11 oneGigE1/11 11 1000 1
|
||||
Ethernet11 12 oneGigE1/12 12 1000 1
|
||||
Ethernet12 13 oneGigE1/13 13 1000 1
|
||||
Ethernet13 14 oneGigE1/14 14 1000 1
|
||||
Ethernet14 15 oneGigE1/15 15 1000 1
|
||||
Ethernet15 16 oneGigE1/16 16 1000 1
|
||||
Ethernet16 17 oneGigE1/17 17 1000 1
|
||||
Ethernet17 18 oneGigE1/18 18 1000 1
|
||||
Ethernet18 19 oneGigE1/19 19 1000 1
|
||||
Ethernet19 20 oneGigE1/20 20 1000 1
|
||||
Ethernet20 21 oneGigE1/21 21 1000 1
|
||||
Ethernet21 22 oneGigE1/22 22 1000 1
|
||||
Ethernet22 23 oneGigE1/23 23 1000 1
|
||||
Ethernet23 24 oneGigE1/24 24 1000 1
|
||||
Ethernet24 25 oneGigE1/25 25 1000 1
|
||||
Ethernet25 26 oneGigE1/26 26 1000 1
|
||||
Ethernet26 27 oneGigE1/27 27 1000 1
|
||||
Ethernet27 28 oneGigE1/28 28 1000 1
|
||||
Ethernet28 29 oneGigE1/29 29 1000 1
|
||||
Ethernet29 30 oneGigE1/30 30 1000 1
|
||||
Ethernet30 31 oneGigE1/31 31 1000 1
|
||||
Ethernet31 32 oneGigE1/32 32 1000 1
|
||||
Ethernet32 33 oneGigE1/33 33 1000 1
|
||||
Ethernet33 34 oneGigE1/34 34 1000 1
|
||||
Ethernet34 35 oneGigE1/35 35 1000 1
|
||||
Ethernet35 36 oneGigE1/36 36 1000 1
|
||||
Ethernet36 37 oneGigE1/37 37 1000 1
|
||||
Ethernet37 38 oneGigE1/38 38 1000 1
|
||||
Ethernet38 39 oneGigE1/39 39 1000 1
|
||||
Ethernet39 40 oneGigE1/40 40 1000 1
|
||||
Ethernet40 41 oneGigE1/41 41 1000 1
|
||||
Ethernet41 42 oneGigE1/42 42 1000 1
|
||||
Ethernet42 43 oneGigE1/43 43 1000 1
|
||||
Ethernet43 44 oneGigE1/44 44 1000 1
|
||||
Ethernet44 45 oneGigE1/45 45 1000 1
|
||||
Ethernet45 46 oneGigE1/46 46 1000 1
|
||||
Ethernet46 47 oneGigE1/47 47 1000 1
|
||||
Ethernet47 48 oneGigE1/48 48 1000 1
|
||||
Ethernet48 64 tenGigE1/49 49 10000 0
|
||||
Ethernet49 63 tenGigE1/50 50 10000 0
|
||||
Ethernet50 62 tenGigE1/51 51 10000 0
|
||||
Ethernet51 61 tenGigE1/52 52 10000 0
|
||||
Ethernet52 69,70,71,72 hundredGigE1/53 53 100000 0
|
||||
Ethernet56 73,74,75,76 hundredGigE1/54 54 100000 0
|
@ -0,0 +1 @@
|
||||
{%- include 'qos_config_t1.j2' %}
|
@ -0,0 +1,175 @@
|
||||
{%- set PORT_ALL = [] %}
|
||||
{%- for port in PORT %}
|
||||
{%- if PORT_ALL.append(port) %}{% endif %}
|
||||
{%- endfor %}
|
||||
{%- if PORT_ALL | sort_by_port_index %}{% endif %}
|
||||
|
||||
{%- set port_names_list_all = [] %}
|
||||
{%- for port in PORT_ALL %}
|
||||
{%- if port_names_list_all.append(port) %}{% endif %}
|
||||
{%- endfor %}
|
||||
{%- set port_names_all = port_names_list_all | join(',') -%}
|
||||
|
||||
|
||||
{%- set PORT_ACTIVE = [] %}
|
||||
{%- if DEVICE_NEIGHBOR is not defined %}
|
||||
{%- set PORT_ACTIVE = PORT_ALL %}
|
||||
{%- else %}
|
||||
{%- for port in DEVICE_NEIGHBOR.keys() %}
|
||||
{%- if PORT_ACTIVE.append(port) %}{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- endif %}
|
||||
{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %}
|
||||
|
||||
{%- set port_names_list_active = [] %}
|
||||
{%- for port in PORT_ACTIVE %}
|
||||
{%- if port_names_list_active.append(port) %}{%- endif %}
|
||||
{%- endfor %}
|
||||
{%- set port_names_active = port_names_list_active | join(',') -%}
|
||||
|
||||
|
||||
{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%}
|
||||
|
||||
|
||||
{
|
||||
{% if generate_tc_to_pg_map is defined %}
|
||||
{{- generate_tc_to_pg_map() }}
|
||||
{% else %}
|
||||
"TC_TO_PRIORITY_GROUP_MAP": {
|
||||
"AZURE": {
|
||||
"0": "0",
|
||||
"1": "0",
|
||||
"2": "0",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "0",
|
||||
"6": "0",
|
||||
"7": "7"
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
"MAP_PFC_PRIORITY_TO_QUEUE": {
|
||||
"AZURE": {
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5",
|
||||
"6": "6",
|
||||
"7": "7"
|
||||
}
|
||||
},
|
||||
"TC_TO_QUEUE_MAP": {
|
||||
"AZURE": {
|
||||
"0": "0",
|
||||
"1": "1",
|
||||
"2": "2",
|
||||
"3": "3",
|
||||
"4": "4",
|
||||
"5": "5",
|
||||
"6": "6",
|
||||
"7": "7"
|
||||
}
|
||||
},
|
||||
"DSCP_TO_TC_MAP": {
|
||||
"AZURE": {
|
||||
"0" : "1",
|
||||
"1" : "1",
|
||||
"2" : "1",
|
||||
"3" : "3",
|
||||
"4" : "4",
|
||||
"5" : "2",
|
||||
"6" : "1",
|
||||
"7" : "1",
|
||||
"8" : "0",
|
||||
"9" : "1",
|
||||
"10": "1",
|
||||
"11": "1",
|
||||
"12": "1",
|
||||
"13": "1",
|
||||
"14": "1",
|
||||
"15": "1",
|
||||
"16": "1",
|
||||
"17": "1",
|
||||
"18": "1",
|
||||
"19": "1",
|
||||
"20": "1",
|
||||
"21": "1",
|
||||
"22": "1",
|
||||
"23": "1",
|
||||
"24": "1",
|
||||
"25": "1",
|
||||
"26": "1",
|
||||
"27": "1",
|
||||
"28": "1",
|
||||
"29": "1",
|
||||
"30": "1",
|
||||
"31": "1",
|
||||
"32": "1",
|
||||
"33": "1",
|
||||
"34": "1",
|
||||
"35": "1",
|
||||
"36": "1",
|
||||
"37": "1",
|
||||
"38": "1",
|
||||
"39": "1",
|
||||
"40": "1",
|
||||
"41": "1",
|
||||
"42": "1",
|
||||
"43": "1",
|
||||
"44": "1",
|
||||
"45": "1",
|
||||
"46": "5",
|
||||
"47": "1",
|
||||
"48": "6",
|
||||
"49": "1",
|
||||
"50": "1",
|
||||
"51": "1",
|
||||
"52": "1",
|
||||
"53": "1",
|
||||
"54": "1",
|
||||
"55": "1",
|
||||
"56": "1",
|
||||
"57": "1",
|
||||
"58": "1",
|
||||
"59": "1",
|
||||
"60": "1",
|
||||
"61": "1",
|
||||
"62": "1",
|
||||
"63": "1"
|
||||
}
|
||||
},
|
||||
"SCHEDULER": {
|
||||
"scheduler.0": {
|
||||
"type" : "DWRR",
|
||||
"weight": "14"
|
||||
},
|
||||
"scheduler.1": {
|
||||
"type" : "DWRR",
|
||||
"weight": "15"
|
||||
}
|
||||
},
|
||||
{% if asic_type in pfc_to_pg_map_supported_asics %}
|
||||
"PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": {
|
||||
"AZURE": {
|
||||
"3": "3",
|
||||
"4": "4"
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
"PORT_QOS_MAP": {
|
||||
{% for port in PORT_ACTIVE %}
|
||||
"{{ port }}": {
|
||||
"dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]",
|
||||
"tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]",
|
||||
"tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]",
|
||||
"pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]",
|
||||
{% if asic_type in pfc_to_pg_map_supported_asics %}
|
||||
"pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]",
|
||||
{% endif %}
|
||||
"pfc_enable" : "3,4"
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/hx5-n3248te-48x1G+4x10G.config.bcm
|
@ -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
|
1
device/dell/x86_64-dellemc_n3248te_c3338-r0/default_sku
Normal file
1
device/dell/x86_64-dellemc_n3248te_c3338-r0/default_sku
Normal file
@ -0,0 +1 @@
|
||||
DellEMC-N3248TE t1
|
13
device/dell/x86_64-dellemc_n3248te_c3338-r0/init_cfg.json
Normal file
13
device/dell/x86_64-dellemc_n3248te_c3338-r0/init_cfg.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"FEATURE": {
|
||||
"tam": {
|
||||
"state": "disabled"
|
||||
},
|
||||
"telemetry": {
|
||||
"state": "disabled"
|
||||
},
|
||||
"nat": {
|
||||
"state": "disabled"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
CONSOLE_PORT=0x3f8
|
||||
CONSOLE_DEV=0
|
||||
VAR_LOG_SIZE=512
|
@ -0,0 +1,7 @@
|
||||
# LED microprocessor initialization for Dell N3248TE
|
||||
#
|
||||
#
|
||||
#Led0
|
||||
#led auto on
|
||||
m0 load 0 0x3800 /usr/share/sonic/hwsku/custom_led.bin
|
||||
led start
|
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
#############################################################################
|
||||
# Dell S3000
|
||||
#
|
||||
# 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:
|
||||
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 = "/sys/class/i2c-adapter/i2c-2/2-0050/eeprom"
|
||||
super(board, self).__init__(self.eeprom_path, 0, '', True)
|
@ -0,0 +1,72 @@
|
||||
#
|
||||
# fanutil.py
|
||||
# Platform-specific FAN status interface for SONiC
|
||||
#
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
SENSORS_CMD = "docker exec -i pmon /usr/bin/sensors"
|
||||
DOCKER_SENSORS_CMD = "/usr/bin/sensors"
|
||||
|
||||
|
||||
try:
|
||||
from sonic_fan.fan_base import FanBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class FanUtil(FanBase):
|
||||
"""Platform-specific FanUtil class"""
|
||||
_fan_mapping = {
|
||||
1 : '0',
|
||||
2 : '1',
|
||||
3 : '2'
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
FanBase.__init__(self)
|
||||
|
||||
def isDockerEnv(self):
|
||||
num_docker = open('/proc/self/cgroup', 'r').read().count(":/docker")
|
||||
if num_docker > 0:
|
||||
return True
|
||||
|
||||
def get_num_fans(self):
|
||||
N3248TE_MAX_FANTRAYS = 3
|
||||
return N3248TE_MAX_FANTRAYS
|
||||
|
||||
def get_presence(self, idx):
|
||||
sysfs_path = "/sys/devices/platform/dell-n3248te-cpld.0/fan" + self._fan_mapping[idx] + "_prs"
|
||||
return int(open(sysfs_path).read(), 16)
|
||||
|
||||
def get_direction(self, idx):
|
||||
sysfs_path = "/sys/devices/platform/dell-n3248te-cpld.0/fan" + self._fan_mapping[idx] + "_dir"
|
||||
return open(sysfs_path).read()
|
||||
|
||||
def get_speed(self, idx):
|
||||
dockerenv = self.isDockerEnv()
|
||||
if not dockerenv:
|
||||
status, cmd_output = subprocess.getstatusoutput(SENSORS_CMD)
|
||||
else :
|
||||
status, cmd_output = subprocess.getstatusoutput(DOCKER_SENSORS_CMD)
|
||||
|
||||
if status:
|
||||
print('Failed to execute sensors command')
|
||||
sys.exit(0)
|
||||
fan_id = 'Fan ' + str(idx)
|
||||
found = False
|
||||
for line in cmd_output.splitlines():
|
||||
if line.startswith('emc2305-i2c-7-2c'):
|
||||
found = True
|
||||
if found and line.startswith(fan_id):
|
||||
return line.split()[3]
|
||||
return 0.0
|
||||
|
||||
def get_status(self, idx):
|
||||
sysfs_path = "/sys/devices/platform/dell-n3248te-cpld.0/fan" + self._fan_mapping[idx] + "_prs"
|
||||
return int(open(sysfs_path).read(), 16)
|
||||
|
||||
|
||||
def set_speed(self, idx):
|
||||
return False
|
@ -0,0 +1,16 @@
|
||||
- bus: '02'
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: '1533'
|
||||
name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev
|
||||
03)'
|
||||
- bus: '01'
|
||||
dev: '00'
|
||||
fn: '0'
|
||||
id: b371
|
||||
name: 'Ethernet controller: Broadcom Limited BCM56371 Switch ASIC (rev 02)'
|
||||
- bus: '00'
|
||||
dev: '14'
|
||||
fn: '0'
|
||||
id: 19c2
|
||||
name: 'SATA controller: Intel Corporation DNV SATA Controller 1 (rev 11)'
|
191
device/dell/x86_64-dellemc_n3248te_c3338-r0/plugins/psuutil.py
Normal file
191
device/dell/x86_64-dellemc_n3248te_c3338-r0/plugins/psuutil.py
Normal file
@ -0,0 +1,191 @@
|
||||
#
|
||||
# psuutil.py
|
||||
# Platform-specific PSU status interface for SONiC
|
||||
#
|
||||
|
||||
import commands
|
||||
import os
|
||||
import sys
|
||||
|
||||
SENSORS_CMD = "docker exec -i pmon /usr/bin/sensors"
|
||||
DOCKER_SENSORS_CMD = "/usr/bin/sensors"
|
||||
|
||||
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"""
|
||||
_psu_mapping = {
|
||||
1 : '0',
|
||||
2 : '1'
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
def remove_nonnumeric(self, text):
|
||||
digits='0123456789.'
|
||||
return ''.join(c for c in text if c in digits)
|
||||
|
||||
def get_cpld_register(self, reg_name):
|
||||
cpld_dir = "/sys/devices/platform/dell-n3248te-cpld.0/"
|
||||
retval = 'ERR'
|
||||
reg_file = cpld_dir +'/' + reg_name
|
||||
if (not os.path.isfile(reg_file)):
|
||||
return retval
|
||||
|
||||
try:
|
||||
with open(reg_file, 'r') as fd:
|
||||
retval = fd.read()
|
||||
except Exception as error:
|
||||
print("Unable to open ", reg_file, "file !")
|
||||
|
||||
retval = retval.rstrip('\r\n')
|
||||
return retval
|
||||
|
||||
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
|
||||
"""
|
||||
N3248TE_MAX_PSUS = 2
|
||||
return N3248TE_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
|
||||
"""
|
||||
status = 0
|
||||
psu_status = self.get_cpld_register('psu'+self._psu_mapping[index]+'_status')
|
||||
if (psu_status != 'ERR'):
|
||||
status = int(psu_status, 10)
|
||||
|
||||
presence = self.get_psu_presence(index)
|
||||
|
||||
return (status & presence)
|
||||
|
||||
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
|
||||
"""
|
||||
status = 0
|
||||
psu_presence = self.get_cpld_register('psu'+self._psu_mapping[index]+'_prs')
|
||||
if (psu_presence != 'ERR'):
|
||||
status = int(psu_presence, 10)
|
||||
|
||||
return status
|
||||
|
||||
def get_sensor(self):
|
||||
dockerenv = self.isDockerEnv()
|
||||
if not dockerenv:
|
||||
status, cmd_output = commands.getstatusoutput(SENSORS_CMD)
|
||||
else :
|
||||
status, cmd_output = commands.getstatusoutput(DOCKER_SENSORS_CMD)
|
||||
|
||||
if status:
|
||||
print('Failed to execute sensors command')
|
||||
sys.exit(0)
|
||||
return cmd_output
|
||||
|
||||
def get_output_current(self, index):
|
||||
cmd_output= self.get_sensor()
|
||||
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
|
||||
found = False
|
||||
for line in cmd_output.splitlines():
|
||||
if line.startswith(sensor_name):
|
||||
found = True
|
||||
if found:
|
||||
if 'Output Current' in line :
|
||||
return float(self.remove_nonnumeric(line.split()[2]))
|
||||
return 0.0
|
||||
|
||||
def get_output_voltage(self, index):
|
||||
cmd_output= self.get_sensor()
|
||||
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
|
||||
found = False
|
||||
for line in cmd_output.splitlines():
|
||||
if line.startswith(sensor_name):
|
||||
found = True
|
||||
if found:
|
||||
if 'Output Voltage' in line :
|
||||
return float(self.remove_nonnumeric(line.split()[2]))
|
||||
return 0.0
|
||||
|
||||
def get_fan_rpm(self, index, fan_index):
|
||||
if fan_index > 1 : return 0.0
|
||||
cmd_output= self.get_sensor()
|
||||
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
|
||||
found = False
|
||||
for line in cmd_output.splitlines():
|
||||
if line.startswith(sensor_name):
|
||||
found = True
|
||||
if found:
|
||||
if 'Fan RPM' in line :
|
||||
return self.remove_nonnumeric(line.split()[2])
|
||||
return 0.0
|
||||
|
||||
def get_output_power(self, index):
|
||||
cmd_output= self.get_sensor()
|
||||
sensor_name = 'dps460-i2c-10' if index == 1 else 'dps460-i2c-11'
|
||||
found = False
|
||||
for line in cmd_output.splitlines():
|
||||
if line.startswith(sensor_name):
|
||||
found = True
|
||||
if found:
|
||||
if 'Output Power' in line :
|
||||
return float(self.remove_nonnumeric(line.split()[2]))
|
||||
return 0.0
|
||||
|
||||
def get_direction(self, index):
|
||||
psuid = '0' if index == 1 else '1'
|
||||
sysfs_path = '/sys/devices/platform/dell-n3248te-cpld.0/psu' + psuid + '_prs'
|
||||
found_psu = int(open(sysfs_path).read())
|
||||
if not found_psu : return ''
|
||||
bus_no = '10' if index == 1 else '11'
|
||||
sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom"
|
||||
val = (open(sysfs_path, "rb").read())[0xe1:0xe8]
|
||||
dir = 'F2B' if 'FORWARD' == val else 'B2F'
|
||||
return dir
|
||||
|
||||
def get_serial(self, index):
|
||||
psuid = '0' if index == 1 else '1'
|
||||
sysfs_path = '/sys/devices/platform/dell-n3248te-cpld.0/psu' + psuid + '_prs'
|
||||
found_psu = int(open(sysfs_path).read())
|
||||
if not found_psu : return ''
|
||||
bus_no = '10' if index == 1 else '11'
|
||||
sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom"
|
||||
val = (open(sysfs_path, "rb").read())[0xc4:0xd9]
|
||||
return val
|
||||
|
||||
def get_model(self, index):
|
||||
psuid = '0' if index == 1 else '1'
|
||||
sysfs_path = '/sys/devices/platform/dell-n3248te-cpld.0/psu' + psuid + '_prs'
|
||||
found_psu = int(open(sysfs_path).read())
|
||||
if not found_psu : return ''
|
||||
bus_no = '10' if index == 1 else '11'
|
||||
sysfs_path = "/sys/bus/i2c/devices/" + bus_no + "-0056/eeprom"
|
||||
val = (open(sysfs_path, "rb").read())[0x50:0x62]
|
||||
return val
|
||||
|
||||
def get_mfr_id(self, index):
|
||||
psuid = '0' if index == 1 else '1'
|
||||
sysfs_path = '/sys/devices/platform/dell-n3248te-cpld.0/psu' + psuid + '_prs'
|
||||
found_psu = int(open(sysfs_path).read())
|
||||
return 'DELTA' if found_psu else ''
|
172
device/dell/x86_64-dellemc_n3248te_c3338-r0/plugins/sfputil.py
Normal file
172
device/dell/x86_64-dellemc_n3248te_c3338-r0/plugins/sfputil.py
Normal file
@ -0,0 +1,172 @@
|
||||
# sfputil.py
|
||||
#
|
||||
# Platform-specific SFP transceiver interface for SONiC
|
||||
#
|
||||
|
||||
try:
|
||||
import time
|
||||
from socket import *
|
||||
from select import *
|
||||
from sonic_sfp.sfputilbase import SfpUtilBase
|
||||
except ImportError as e:
|
||||
raise ImportError("%s - required module not found" % str(e))
|
||||
|
||||
class SfpUtil(SfpUtilBase):
|
||||
"""Platform-specific SfpUtil class"""
|
||||
|
||||
PORT_START = 1
|
||||
PORT_END = 52
|
||||
PORTS_IN_BLOCK = 52
|
||||
SFP_PORT_START = 49
|
||||
SFP_PORT_END = 52
|
||||
|
||||
EEPROM_OFFSET = 14
|
||||
|
||||
_port_to_eeprom_mapping = {}
|
||||
_sfpp_port_i2c_mapping = {
|
||||
49 : 20,
|
||||
50 : 21,
|
||||
51 : 22,
|
||||
52 : 23
|
||||
}
|
||||
port_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(self.SFP_PORT_END+1, self.SFP_PORT_END+1)
|
||||
|
||||
@property
|
||||
def port_to_eeprom_mapping(self):
|
||||
return self._port_to_eeprom_mapping
|
||||
|
||||
@property
|
||||
def get_transceiver_status(self):
|
||||
|
||||
try:
|
||||
sfp_modprs_path = "/sys/devices/platform/dell-n3248te-cpld.0/sfp_modprs"
|
||||
reg_file = open(sfp_modprs_path)
|
||||
|
||||
except IOError as e:
|
||||
print ("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
|
||||
content = reg_file.readline().rstrip()
|
||||
|
||||
reg_file.close()
|
||||
|
||||
return int(content, 16)
|
||||
|
||||
|
||||
def __init__(self):
|
||||
|
||||
sfpplus_eeprom_path = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
|
||||
|
||||
for x in range(self.SFP_PORT_START, self.SFP_PORT_END + 1):
|
||||
self.port_to_eeprom_mapping[x] = sfpplus_eeprom_path.format(self._sfpp_port_i2c_mapping[x])
|
||||
# Get Transceiver status
|
||||
self.modprs_register = self.get_transceiver_status
|
||||
|
||||
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
|
||||
|
||||
if port_num < self.SFP_PORT_START :
|
||||
return False
|
||||
port_num -= self.SFP_PORT_START
|
||||
try:
|
||||
sfp_modprs_path = "/sys/devices/platform/dell-n3248te-cpld.0/sfp_modprs"
|
||||
reg_file = open(sfp_modprs_path)
|
||||
except IOError as e:
|
||||
print ("Error: unable to open file: %s" % str(e))
|
||||
return False
|
||||
|
||||
content = reg_file.readline().rstrip()
|
||||
|
||||
# content is a string containing the hex representation of the register
|
||||
reg_value = int(content, 16)
|
||||
|
||||
# Mask off the bit corresponding to our port
|
||||
mask = (1 << port_num)
|
||||
|
||||
# ModPrsL is active low
|
||||
if (reg_value & mask) == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def get_low_power_mode(self, port_num):
|
||||
return False
|
||||
|
||||
def set_low_power_mode(self, port_num, lpmode):
|
||||
return False
|
||||
|
||||
def reset(self, port_num):
|
||||
return False
|
||||
|
||||
def get_transceiver_change_event(self, timeout=0):
|
||||
|
||||
start_time = time.time()
|
||||
port = self.SFP_PORT_START
|
||||
forever = False
|
||||
|
||||
if timeout == 0:
|
||||
forever = True
|
||||
elif timeout > 0:
|
||||
timeout = timeout / float(1000) # Convert to secs
|
||||
else:
|
||||
print ('get_transceiver_change_event:Invalid timeout value', timeout)
|
||||
return False, {}
|
||||
|
||||
end_time = start_time + timeout
|
||||
if start_time > end_time:
|
||||
print ('get_transceiver_change_event:' \
|
||||
'time wrap / invalid timeout value', timeout)
|
||||
|
||||
return False, {} # Time wrap or possibly incorrect timeout
|
||||
|
||||
while timeout >= 0:
|
||||
# Check for OIR events and return updated port_dict
|
||||
reg_value = self.get_transceiver_status
|
||||
if reg_value != self.modprs_register:
|
||||
changed_ports = self.modprs_register ^ reg_value
|
||||
while port >= self.SFP_PORT_START and port <= self.SFP_PORT_END:
|
||||
|
||||
# Mask off the bit corresponding to our port
|
||||
mask = (1 << (port - self.SFP_PORT_START))
|
||||
|
||||
if changed_ports & mask:
|
||||
# ModPrsL is active low
|
||||
if reg_value & mask == 0:
|
||||
self.port_dict[port] = '1'
|
||||
else:
|
||||
self.port_dict[port] = '0'
|
||||
|
||||
port += 1
|
||||
|
||||
# Update reg value
|
||||
self.modprs_register = reg_value
|
||||
return True, self.port_dict
|
||||
|
||||
if forever:
|
||||
time.sleep(1)
|
||||
else:
|
||||
timeout = end_time - time.time()
|
||||
if timeout >= 1:
|
||||
time.sleep(1) # We poll at 1 second granularity
|
||||
else:
|
||||
if timeout > 0:
|
||||
time.sleep(timeout)
|
||||
return True, {}
|
||||
print ("get_transceiver_change_event: Should not reach here.")
|
||||
return False, {}
|
@ -0,0 +1,3 @@
|
||||
{
|
||||
"skip_ledd": true
|
||||
}
|
58
device/dell/x86_64-dellemc_n3248te_c3338-r0/sensors.conf
Normal file
58
device/dell/x86_64-dellemc_n3248te_c3338-r0/sensors.conf
Normal file
@ -0,0 +1,58 @@
|
||||
# libsensors configuration file for Dell N3248TE
|
||||
# The i2c bus portion is omit because adapter name
|
||||
# changes every time when system boot up.
|
||||
|
||||
bus "i2c-7" "i2c-0-mux (chan_id 5)"
|
||||
bus "i2c-5" "i2c-0-mux (chan_id 3)"
|
||||
bus "i2c-10" "i2c-5-mux (chan_id 0)"
|
||||
bus "i2c-11" "i2c-5-mux (chan_id 1)"
|
||||
|
||||
chip "tmp75-i2c-7-49"
|
||||
label temp1 "Switch Near Temperature"
|
||||
chip "tmp75-i2c-7-4a"
|
||||
label temp1 "Switch Rear Temperature"
|
||||
chip "tmp75-i2c-7-4b"
|
||||
label temp1 "Front Panel PHY Temperature"
|
||||
chip "tmp75-i2c-7-4c"
|
||||
label temp1 "Near Front Panel Temperature"
|
||||
chip "tmp75-i2c-7-4f"
|
||||
label temp1 "Middle Fan Tray Temperature"
|
||||
|
||||
|
||||
chip "emc2305-i2c-7-2c"
|
||||
ignore fan4
|
||||
ignore fan5
|
||||
label fan1 "Fan 1 "
|
||||
label fan2 "Fan 2 "
|
||||
label fan3 "Fan 3 "
|
||||
|
||||
chip "dps460-i2c-10-5e"
|
||||
label power1 "Input Power"
|
||||
label power2 "Output Power"
|
||||
label curr1 "Input Current"
|
||||
label curr2 "Output Current"
|
||||
label in1 "Input Voltage"
|
||||
ignore in2
|
||||
label in3 "Output Voltage"
|
||||
label fan1 "Fan RPM"
|
||||
ignore fan2
|
||||
ignore fan3
|
||||
ignore temp1
|
||||
label temp2 "FAN Airflow Temperature"
|
||||
label temp3 "FAN Normal Temperature"
|
||||
|
||||
|
||||
chip "dps460-i2c-11-5e"
|
||||
label power1 "Input Power"
|
||||
label power2 "Output Power"
|
||||
label curr1 "Input Current"
|
||||
label curr2 "Output Current"
|
||||
label in1 "Input Voltage"
|
||||
ignore in2
|
||||
label in3 "Output Voltage"
|
||||
label fan1 "Fan RPM"
|
||||
ignore fan2
|
||||
ignore fan3
|
||||
ignore temp1
|
||||
label temp2 "FAN Airflow Temperature"
|
||||
label temp3 "FAN Normal Temperature"
|
@ -15,6 +15,7 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \
|
||||
$(DELL_S5296F_PLATFORM_MODULE) \
|
||||
$(DELL_Z9100_PLATFORM_MODULE) \
|
||||
$(DELL_S6100_PLATFORM_MODULE) \
|
||||
$(DELL_N3248TE_PLATFORM_MODULE) \
|
||||
$(INGRASYS_S8900_54XC_PLATFORM_MODULE) \
|
||||
$(INGRASYS_S8900_64XC_PLATFORM_MODULE) \
|
||||
$(INGRASYS_S9100_PLATFORM_MODULE) \
|
||||
|
@ -8,6 +8,7 @@ DELL_S5232F_PLATFORM_MODULE_VERSION = 1.1
|
||||
DELL_Z9332F_PLATFORM_MODULE_VERSION = 1.1
|
||||
DELL_S5248F_PLATFORM_MODULE_VERSION = 1.1
|
||||
DELL_S5296F_PLATFORM_MODULE_VERSION = 1.1
|
||||
DELL_N3248TE_PLATFORM_MODULE_VERSION = 1.1
|
||||
|
||||
export DELL_S6000_PLATFORM_MODULE_VERSION
|
||||
export DELL_Z9100_PLATFORM_MODULE_VERSION
|
||||
@ -17,6 +18,7 @@ export DELL_S5232F_PLATFORM_MODULE_VERSION
|
||||
export DELL_Z9332F_PLATFORM_MODULE_VERSION
|
||||
export DELL_S5248F_PLATFORM_MODULE_VERSION
|
||||
export DELL_S5296F_PLATFORM_MODULE_VERSION
|
||||
export DELL_N3248TE_PLATFORM_MODULE_VERSION
|
||||
|
||||
DELL_Z9100_PLATFORM_MODULE = platform-modules-z9100_$(DELL_Z9100_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(DELL_Z9100_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-dell
|
||||
@ -49,6 +51,10 @@ DELL_S5248F_PLATFORM_MODULE = platform-modules-s5248f_$(DELL_S5248F_PLATFORM_MOD
|
||||
$(DELL_S5248F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5248f_c3538-r0
|
||||
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5248F_PLATFORM_MODULE)))
|
||||
|
||||
DELL_N3248TE_PLATFORM_MODULE = platform-modules-n3248te_$(DELL_N3248TE_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(DELL_N3248TE_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_n3248te_c3338-r0
|
||||
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_N3248TE_PLATFORM_MODULE)))
|
||||
|
||||
DELL_S5296F_PLATFORM_MODULE = platform-modules-s5296f_$(DELL_S5296F_PLATFORM_MODULE_VERSION)_amd64.deb
|
||||
$(DELL_S5296F_PLATFORM_MODULE)_PLATFORM = x86_64-dellemc_s5296f_c3538-r0
|
||||
$(eval $(call add_extra_package,$(DELL_Z9100_PLATFORM_MODULE),$(DELL_S5296F_PLATFORM_MODULE)))
|
||||
|
@ -35,6 +35,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-n3248te
|
||||
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-z9332f
|
||||
Architecture: amd64
|
||||
Depends: linux-image-4.19.0-12-2-amd64-unsigned
|
||||
|
@ -0,0 +1,39 @@
|
||||
#!/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 S3000 board.
|
||||
### END INIT INFO
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
echo -n "Setting up board... "
|
||||
|
||||
/usr/local/bin/n3248te_platform.sh init
|
||||
|
||||
echo "done."
|
||||
;;
|
||||
|
||||
stop)
|
||||
/usr/local/bin/n3248te_platform.sh deinit
|
||||
echo "done."
|
||||
|
||||
;;
|
||||
|
||||
force-reload|restart)
|
||||
echo "Not supported"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Usage: /etc/init.d/platform-modules-n3248te.init {start|stop}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
@ -0,0 +1,12 @@
|
||||
n3248te/scripts/n3248te_platform.sh usr/local/bin
|
||||
n3248te/scripts/platform_sensors.py usr/local/bin
|
||||
n3248te/scripts/sensors usr/bin
|
||||
n3248te/scripts//portiocfg.py usr/local/bin
|
||||
n3248te/scripts//ports_xcvrd_notify.py usr/local/bin
|
||||
n3248te/systemd/platform-modules-n3248te.service etc/systemd/system
|
||||
n3248te/cfg/n3248te-modules.conf etc/modules-load.d
|
||||
common/dell_i2c_utils.sh usr/local/bin
|
||||
n3248te/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-dellemc_n3248te_c3338-r0
|
||||
common/platform_reboot usr/share/sonic/device/x86_64-dellemc_n3248te_c3338-r0
|
||||
common/fw-updater /usr/local/bin
|
||||
common/onie_mode_set usr/local/bin
|
@ -0,0 +1,7 @@
|
||||
# postinst script for N3248TE
|
||||
|
||||
# Enable Dell-N3248TE-platform-service
|
||||
depmod -a
|
||||
systemctl enable platform-modules-n3248te.service
|
||||
systemctl start platform-modules-n3248te.service
|
||||
#DEBHELPER#
|
@ -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
|
||||
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f z9332f s5296f n3248te
|
||||
COMMON_DIR := common
|
||||
|
||||
%:
|
||||
@ -50,6 +50,11 @@ override_dh_auto_build:
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||
cd $(MOD_SRC_DIR); \
|
||||
elif [ $$mod = "n3248te" ]; 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 = "z9332f" ]; then \
|
||||
cp $(COMMON_DIR)/ipmihelper.py $(MOD_SRC_DIR)/$${mod}/sonic_platform/ipmihelper.py; \
|
||||
cd $(MOD_SRC_DIR)/$${mod}; \
|
||||
@ -118,6 +123,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 = "n3248te" ]; 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; \
|
||||
fi; \
|
||||
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules clean; \
|
||||
done); \
|
||||
|
@ -0,0 +1,14 @@
|
||||
# /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-isch
|
||||
i2c-ismt
|
||||
i2c-dev
|
||||
i2c-mux
|
||||
i2c-smbus
|
||||
|
||||
i2c-mux-pca954x
|
||||
dell_n3248te_platform
|
||||
|
@ -0,0 +1,2 @@
|
||||
obj-m := dell_n3248te_platform.o emc2305.o
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,877 @@
|
||||
/*
|
||||
* emc2305.c - hwmon driver for SMSC EMC2305 fan controller
|
||||
* (C) Copyright 2013
|
||||
* Reinhard Pfau, Guntermann & Drunck GmbH <pfau@gdsys.de>
|
||||
*
|
||||
* Based on emc2103 driver by SMSC.
|
||||
*
|
||||
* Datasheet available at:
|
||||
* http://www.smsc.com/Downloads/SMSC/Downloads_Public/Data_Sheets/2305.pdf
|
||||
*
|
||||
* Also supports the EMC2303 fan controller which has the same functionality
|
||||
* and register layout as EMC2305, but supports only up to 3 fans instead of 5.
|
||||
*
|
||||
* Also supports EMC2302 (up to 2 fans) and EMC2301 (1 fan) fan controller.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO / IDEAS:
|
||||
* - expose more of the configuration and features
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/hwmon-sysfs.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
/*
|
||||
* Addresses scanned.
|
||||
* Listed in the same order as they appear in the EMC2305, EMC2303 data sheets.
|
||||
*
|
||||
* Note: these are the I2C adresses which are possible for EMC2305 and EMC2303
|
||||
* chips.
|
||||
* The EMC2302 supports only 0x2e (EMC2302-1) and 0x2f (EMC2302-2).
|
||||
* The EMC2301 supports only 0x2f.
|
||||
*/
|
||||
static const unsigned short i2c_adresses[] = {
|
||||
0x2E,
|
||||
0x2F,
|
||||
0x2C,
|
||||
0x2D,
|
||||
0x4C,
|
||||
0x4D,
|
||||
I2C_CLIENT_END
|
||||
};
|
||||
|
||||
/*
|
||||
* global registers
|
||||
*/
|
||||
enum {
|
||||
REG_CONFIGURATION = 0x20,
|
||||
REG_FAN_STATUS = 0x24,
|
||||
REG_FAN_STALL_STATUS = 0x25,
|
||||
REG_FAN_SPIN_STATUS = 0x26,
|
||||
REG_DRIVE_FAIL_STATUS = 0x27,
|
||||
REG_FAN_INTERRUPT_ENABLE = 0x29,
|
||||
REG_PWM_POLARITY_CONFIG = 0x2a,
|
||||
REG_PWM_OUTPUT_CONFIG = 0x2b,
|
||||
REG_PWM_BASE_FREQ_1 = 0x2c,
|
||||
REG_PWM_BASE_FREQ_2 = 0x2d,
|
||||
REG_SOFTWARE_LOCK = 0xef,
|
||||
REG_PRODUCT_FEATURES = 0xfc,
|
||||
REG_PRODUCT_ID = 0xfd,
|
||||
REG_MANUFACTURER_ID = 0xfe,
|
||||
REG_REVISION = 0xff
|
||||
};
|
||||
|
||||
/*
|
||||
* fan specific registers
|
||||
*/
|
||||
enum {
|
||||
REG_FAN_SETTING = 0x30,
|
||||
REG_PWM_DIVIDE = 0x31,
|
||||
REG_FAN_CONFIGURATION_1 = 0x32,
|
||||
REG_FAN_CONFIGURATION_2 = 0x33,
|
||||
REG_GAIN = 0x35,
|
||||
REG_FAN_SPIN_UP_CONFIG = 0x36,
|
||||
REG_FAN_MAX_STEP = 0x37,
|
||||
REG_FAN_MINIMUM_DRIVE = 0x38,
|
||||
REG_FAN_VALID_TACH_COUNT = 0x39,
|
||||
REG_FAN_DRIVE_FAIL_BAND_LOW = 0x3a,
|
||||
REG_FAN_DRIVE_FAIL_BAND_HIGH = 0x3b,
|
||||
REG_TACH_TARGET_LOW = 0x3c,
|
||||
REG_TACH_TARGET_HIGH = 0x3d,
|
||||
REG_TACH_READ_HIGH = 0x3e,
|
||||
REG_TACH_READ_LOW = 0x3f,
|
||||
};
|
||||
|
||||
#define SEL_FAN(fan, reg) (reg + fan * 0x10)
|
||||
|
||||
/*
|
||||
* Factor by equations [2] and [3] from data sheet; valid for fans where the
|
||||
* number of edges equals (poles * 2 + 1).
|
||||
*/
|
||||
#define FAN_RPM_FACTOR 3932160
|
||||
|
||||
|
||||
struct emc2305_fan_data {
|
||||
bool enabled;
|
||||
bool valid;
|
||||
unsigned long last_updated;
|
||||
bool rpm_control;
|
||||
u8 multiplier;
|
||||
u8 poles;
|
||||
u16 target;
|
||||
u16 tach;
|
||||
u16 rpm_factor;
|
||||
u8 pwm;
|
||||
};
|
||||
|
||||
struct emc2305_data {
|
||||
struct device *hwmon_dev;
|
||||
struct mutex update_lock;
|
||||
int fans;
|
||||
struct emc2305_fan_data fan[5];
|
||||
};
|
||||
|
||||
static int read_u8_from_i2c(struct i2c_client *client, u8 i2c_reg, u8 *output)
|
||||
{
|
||||
int status = i2c_smbus_read_byte_data(client, i2c_reg);
|
||||
if (status < 0) {
|
||||
dev_warn(&client->dev, "reg 0x%02x, err %d\n",
|
||||
i2c_reg, status);
|
||||
} else {
|
||||
*output = status;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void read_fan_from_i2c(struct i2c_client *client, u16 *output,
|
||||
u8 hi_addr, u8 lo_addr)
|
||||
{
|
||||
u8 high_byte, lo_byte;
|
||||
|
||||
if (read_u8_from_i2c(client, hi_addr, &high_byte) < 0)
|
||||
return;
|
||||
|
||||
if (read_u8_from_i2c(client, lo_addr, &lo_byte) < 0)
|
||||
return;
|
||||
|
||||
*output = ((u16)high_byte << 5) | (lo_byte >> 3);
|
||||
}
|
||||
|
||||
static void write_fan_target_to_i2c(struct i2c_client *client, int fan,
|
||||
u16 new_target)
|
||||
{
|
||||
const u8 lo_reg = SEL_FAN(fan, REG_TACH_TARGET_LOW);
|
||||
const u8 hi_reg = SEL_FAN(fan, REG_TACH_TARGET_HIGH);
|
||||
u8 high_byte = (new_target & 0x1fe0) >> 5;
|
||||
u8 low_byte = (new_target & 0x001f) << 3;
|
||||
i2c_smbus_write_byte_data(client, lo_reg, low_byte);
|
||||
i2c_smbus_write_byte_data(client, hi_reg, high_byte);
|
||||
}
|
||||
|
||||
static void read_fan_config_from_i2c(struct i2c_client *client, int fan)
|
||||
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
u8 conf1;
|
||||
|
||||
if (read_u8_from_i2c(client, SEL_FAN(fan, REG_FAN_CONFIGURATION_1),
|
||||
&conf1) < 0)
|
||||
return;
|
||||
|
||||
data->fan[fan].rpm_control = (conf1 & 0x80) != 0;
|
||||
data->fan[fan].multiplier = 1 << ((conf1 & 0x60) >> 5);
|
||||
data->fan[fan].poles = ((conf1 & 0x18) >> 3) + 1;
|
||||
}
|
||||
|
||||
static void read_fan_setting(struct i2c_client *client, int fan)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
u8 setting;
|
||||
|
||||
if (read_u8_from_i2c(client, SEL_FAN(fan, REG_FAN_SETTING),
|
||||
&setting) < 0)
|
||||
return;
|
||||
|
||||
data->fan[fan].pwm = setting;
|
||||
}
|
||||
|
||||
static void read_fan_data(struct i2c_client *client, int fan_idx)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
|
||||
read_fan_from_i2c(client, &data->fan[fan_idx].target,
|
||||
SEL_FAN(fan_idx, REG_TACH_TARGET_HIGH),
|
||||
SEL_FAN(fan_idx, REG_TACH_TARGET_LOW));
|
||||
read_fan_from_i2c(client, &data->fan[fan_idx].tach,
|
||||
SEL_FAN(fan_idx, REG_TACH_READ_HIGH),
|
||||
SEL_FAN(fan_idx, REG_TACH_READ_LOW));
|
||||
}
|
||||
|
||||
static struct emc2305_fan_data *
|
||||
emc2305_update_fan(struct i2c_client *client, int fan_idx)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
struct emc2305_fan_data *fan_data = &data->fan[fan_idx];
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (time_after(jiffies, fan_data->last_updated + HZ + HZ / 2)
|
||||
|| !fan_data->valid) {
|
||||
read_fan_config_from_i2c(client, fan_idx);
|
||||
read_fan_data(client, fan_idx);
|
||||
read_fan_setting(client, fan_idx);
|
||||
fan_data->valid = true;
|
||||
fan_data->last_updated = jiffies;
|
||||
}
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return fan_data;
|
||||
}
|
||||
|
||||
static struct emc2305_fan_data *
|
||||
emc2305_update_device_fan(struct device *dev, struct device_attribute *da)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int fan_idx = to_sensor_dev_attr(da)->index;
|
||||
|
||||
return emc2305_update_fan(client, fan_idx);
|
||||
}
|
||||
|
||||
/*
|
||||
* set/ config functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: we also update the fan target here, because its value is
|
||||
* determined in part by the fan clock divider. This follows the principle
|
||||
* of least surprise; the user doesn't expect the fan target to change just
|
||||
* because the divider changed.
|
||||
*/
|
||||
static int
|
||||
emc2305_set_fan_div(struct i2c_client *client, int fan_idx, long new_div)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx);
|
||||
const u8 reg_conf1 = SEL_FAN(fan_idx, REG_FAN_CONFIGURATION_1);
|
||||
int new_range_bits, old_div = 8 / fan->multiplier;
|
||||
int status = 0;
|
||||
|
||||
if (new_div == old_div) /* No change */
|
||||
return 0;
|
||||
|
||||
switch (new_div) {
|
||||
case 1:
|
||||
new_range_bits = 3;
|
||||
break;
|
||||
case 2:
|
||||
new_range_bits = 2;
|
||||
break;
|
||||
case 4:
|
||||
new_range_bits = 1;
|
||||
break;
|
||||
case 8:
|
||||
new_range_bits = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
status = i2c_smbus_read_byte_data(client, reg_conf1);
|
||||
if (status < 0) {
|
||||
dev_dbg(&client->dev, "reg 0x%02x, err %d\n",
|
||||
reg_conf1, status);
|
||||
status = -EIO;
|
||||
goto exit_unlock;
|
||||
}
|
||||
status &= 0x9F;
|
||||
status |= (new_range_bits << 5);
|
||||
status = i2c_smbus_write_byte_data(client, reg_conf1, status);
|
||||
if (status < 0) {
|
||||
status = -EIO;
|
||||
goto exit_invalidate;
|
||||
}
|
||||
|
||||
fan->multiplier = 8 / new_div;
|
||||
|
||||
/* update fan target if high byte is not disabled */
|
||||
if ((fan->target & 0x1fe0) != 0x1fe0) {
|
||||
u16 new_target = (fan->target * old_div) / new_div;
|
||||
fan->target = min_t(u16, new_target, 0x1fff);
|
||||
write_fan_target_to_i2c(client, fan_idx, fan->target);
|
||||
}
|
||||
|
||||
exit_invalidate:
|
||||
/* invalidate fan data to force re-read from hardware */
|
||||
fan->valid = false;
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
emc2305_set_fan_target(struct i2c_client *client, int fan_idx, long rpm_target)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx);
|
||||
|
||||
/*
|
||||
* Datasheet states 16000 as maximum RPM target
|
||||
* (table 2.2 and section 4.3)
|
||||
*/
|
||||
if ((rpm_target < 0) || (rpm_target > 16000))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
if (rpm_target == 0)
|
||||
fan->target = 0x1fff;
|
||||
else
|
||||
fan->target = clamp_val(
|
||||
(FAN_RPM_FACTOR * fan->multiplier) / rpm_target,
|
||||
0, 0x1fff);
|
||||
|
||||
write_fan_target_to_i2c(client, fan_idx, fan->target);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
emc2305_set_pwm_enable(struct i2c_client *client, int fan_idx, long enable)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx);
|
||||
const u8 reg_fan_conf1 = SEL_FAN(fan_idx, REG_FAN_CONFIGURATION_1);
|
||||
int status = 0;
|
||||
u8 conf_reg;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
switch (enable) {
|
||||
case 0:
|
||||
fan->rpm_control = false;
|
||||
break;
|
||||
case 3:
|
||||
fan->rpm_control = true;
|
||||
break;
|
||||
default:
|
||||
status = -EINVAL;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
status = read_u8_from_i2c(client, reg_fan_conf1, &conf_reg);
|
||||
if (status < 0) {
|
||||
status = -EIO;
|
||||
goto exit_unlock;
|
||||
}
|
||||
|
||||
if (fan->rpm_control)
|
||||
conf_reg |= 0x80;
|
||||
else
|
||||
conf_reg &= ~0x80;
|
||||
|
||||
status = i2c_smbus_write_byte_data(client, reg_fan_conf1, conf_reg);
|
||||
if (status < 0)
|
||||
status = -EIO;
|
||||
|
||||
exit_unlock:
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int
|
||||
emc2305_set_pwm(struct i2c_client *client, int fan_idx, long pwm)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
struct emc2305_fan_data *fan = emc2305_update_fan(client, fan_idx);
|
||||
const u8 reg_fan_setting = SEL_FAN(fan_idx, REG_FAN_SETTING);
|
||||
int status = 0;
|
||||
|
||||
/*
|
||||
* Datasheet states 255 as maximum PWM
|
||||
* (section 5.7)
|
||||
*/
|
||||
if ((pwm < 0) || (pwm > 255))
|
||||
return -EINVAL;
|
||||
|
||||
fan->pwm = pwm;
|
||||
|
||||
mutex_lock(&data->update_lock);
|
||||
|
||||
status = i2c_smbus_write_byte_data(client, reg_fan_setting, fan->pwm);
|
||||
|
||||
mutex_unlock(&data->update_lock);
|
||||
return status;
|
||||
}
|
||||
/*
|
||||
* sysfs callback functions
|
||||
*
|
||||
* Note:
|
||||
* Naming of the funcs is modelled after the naming scheme described in
|
||||
* Documentation/hwmon/sysfs-interface:
|
||||
*
|
||||
* For a sysfs file <type><number>_<item> the functions are named like this:
|
||||
* the show function: show_<type>_<item>
|
||||
* the store function: set_<type>_<item>
|
||||
* For read only (RO) attributes of course only the show func is required.
|
||||
*
|
||||
* This convention allows us to define the sysfs attributes by using macros.
|
||||
*/
|
||||
|
||||
static ssize_t
|
||||
show_fan_input(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da);
|
||||
int rpm = 0;
|
||||
if (fan->tach != 0)
|
||||
rpm = (FAN_RPM_FACTOR * fan->multiplier) / fan->tach;
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_fan_fault(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da);
|
||||
bool fault = ((fan->tach & 0x1fe0) == 0x1fe0);
|
||||
return sprintf(buf, "%d\n", fault ? 1 : 0);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_fan_div(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da);
|
||||
int fan_div = 8 / fan->multiplier;
|
||||
return sprintf(buf, "%d\n", fan_div);
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
set_fan_div(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int fan_idx = to_sensor_dev_attr(da)->index;
|
||||
long new_div;
|
||||
int status;
|
||||
|
||||
status = kstrtol(buf, 10, &new_div);
|
||||
if (status < 0)
|
||||
return -EINVAL;
|
||||
|
||||
status = emc2305_set_fan_div(client, fan_idx, new_div);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_fan_target(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da);
|
||||
int rpm = 0;
|
||||
|
||||
/* high byte of 0xff indicates disabled so return 0 */
|
||||
if ((fan->target != 0) && ((fan->target & 0x1fe0) != 0x1fe0))
|
||||
rpm = (FAN_RPM_FACTOR * fan->multiplier)
|
||||
/ fan->target;
|
||||
|
||||
return sprintf(buf, "%d\n", rpm);
|
||||
}
|
||||
|
||||
static ssize_t set_fan_target(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int fan_idx = to_sensor_dev_attr(da)->index;
|
||||
long rpm_target;
|
||||
int status;
|
||||
|
||||
status = kstrtol(buf, 10, &rpm_target);
|
||||
if (status < 0)
|
||||
return -EINVAL;
|
||||
|
||||
status = emc2305_set_fan_target(client, fan_idx, rpm_target);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
show_pwm_enable(struct device *dev, struct device_attribute *da, char *buf)
|
||||
{
|
||||
struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da);
|
||||
return sprintf(buf, "%d\n", fan->rpm_control ? 3 : 0);
|
||||
}
|
||||
|
||||
static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int fan_idx = to_sensor_dev_attr(da)->index;
|
||||
long new_value;
|
||||
int status;
|
||||
|
||||
status = kstrtol(buf, 10, &new_value);
|
||||
if (status < 0)
|
||||
return -EINVAL;
|
||||
status = emc2305_set_pwm_enable(client, fan_idx, new_value);
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_pwm(struct device *dev, struct device_attribute *da,
|
||||
char *buf)
|
||||
{
|
||||
struct emc2305_fan_data *fan = emc2305_update_device_fan(dev, da);
|
||||
return sprintf(buf, "%d\n", fan->pwm);
|
||||
}
|
||||
|
||||
static ssize_t set_pwm(struct device *dev, struct device_attribute *da,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int fan_idx = to_sensor_dev_attr(da)->index;
|
||||
unsigned long val;
|
||||
int ret;
|
||||
int status;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (val > 255)
|
||||
return -EINVAL;
|
||||
|
||||
status = emc2305_set_pwm(client, fan_idx, val);
|
||||
return count;
|
||||
}
|
||||
|
||||
/* define a read only attribute */
|
||||
#define EMC2305_ATTR_RO(_type, _item, _num) \
|
||||
SENSOR_ATTR(_type ## _num ## _ ## _item, S_IRUGO, \
|
||||
show_## _type ## _ ## _item, NULL, _num - 1)
|
||||
|
||||
/* define a read/write attribute */
|
||||
#define EMC2305_ATTR_RW(_type, _item, _num) \
|
||||
SENSOR_ATTR(_type ## _num ## _ ## _item, S_IRUGO | S_IWUSR, \
|
||||
show_## _type ##_ ## _item, \
|
||||
set_## _type ## _ ## _item, _num - 1)
|
||||
|
||||
/*
|
||||
* TODO: Ugly hack, but temporary as this whole logic needs
|
||||
* to be rewritten as per standard HWMON sysfs registration
|
||||
*/
|
||||
|
||||
/* define a read/write attribute */
|
||||
#define EMC2305_ATTR_RW2(_type, _num) \
|
||||
SENSOR_ATTR(_type ## _num, S_IRUGO | S_IWUSR, \
|
||||
show_## _type, set_## _type, _num - 1)
|
||||
|
||||
/* defines the attributes for a single fan */
|
||||
#define EMC2305_DEFINE_FAN_ATTRS(_num) \
|
||||
static const \
|
||||
struct sensor_device_attribute emc2305_attr_fan ## _num[] = { \
|
||||
EMC2305_ATTR_RO(fan, input, _num), \
|
||||
EMC2305_ATTR_RO(fan, fault, _num), \
|
||||
EMC2305_ATTR_RW(fan, div, _num), \
|
||||
EMC2305_ATTR_RW(fan, target, _num), \
|
||||
EMC2305_ATTR_RW(pwm, enable, _num), \
|
||||
EMC2305_ATTR_RW2(pwm, _num) \
|
||||
}
|
||||
|
||||
#define EMC2305_NUM_FAN_ATTRS ARRAY_SIZE(emc2305_attr_fan1)
|
||||
|
||||
/* common attributes for EMC2303 and EMC2305 */
|
||||
static const struct sensor_device_attribute emc2305_attr_common[] = {
|
||||
};
|
||||
|
||||
/* fan attributes for the single fans */
|
||||
EMC2305_DEFINE_FAN_ATTRS(1);
|
||||
EMC2305_DEFINE_FAN_ATTRS(2);
|
||||
EMC2305_DEFINE_FAN_ATTRS(3);
|
||||
EMC2305_DEFINE_FAN_ATTRS(4);
|
||||
EMC2305_DEFINE_FAN_ATTRS(5);
|
||||
EMC2305_DEFINE_FAN_ATTRS(6);
|
||||
|
||||
/* fan attributes */
|
||||
static const struct sensor_device_attribute *emc2305_fan_attrs[] = {
|
||||
emc2305_attr_fan1,
|
||||
emc2305_attr_fan2,
|
||||
emc2305_attr_fan3,
|
||||
emc2305_attr_fan4,
|
||||
emc2305_attr_fan5,
|
||||
};
|
||||
|
||||
/*
|
||||
* driver interface
|
||||
*/
|
||||
|
||||
static int emc2305_remove(struct i2c_client *client)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
int fan_idx, i;
|
||||
|
||||
hwmon_device_unregister(data->hwmon_dev);
|
||||
|
||||
for (fan_idx = 0; fan_idx < data->fans; ++fan_idx)
|
||||
for (i = 0; i < EMC2305_NUM_FAN_ATTRS; ++i)
|
||||
device_remove_file(
|
||||
&client->dev,
|
||||
&emc2305_fan_attrs[fan_idx][i].dev_attr);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(emc2305_attr_common); ++i)
|
||||
device_remove_file(&client->dev,
|
||||
&emc2305_attr_common[i].dev_attr);
|
||||
|
||||
kfree(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
/*
|
||||
* device tree support
|
||||
*/
|
||||
|
||||
struct of_fan_attribute {
|
||||
const char *name;
|
||||
int (*set)(struct i2c_client*, int, long);
|
||||
};
|
||||
|
||||
struct of_fan_attribute of_fan_attributes[] = {
|
||||
{"fan-div", emc2305_set_fan_div},
|
||||
{"fan-target", emc2305_set_fan_target},
|
||||
{"pwm-enable", emc2305_set_pwm_enable},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
static int emc2305_config_of(struct i2c_client *client)
|
||||
{
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
struct device_node *node;
|
||||
unsigned int fan_idx;
|
||||
|
||||
if (!client->dev.of_node)
|
||||
return -EINVAL;
|
||||
if (!of_get_next_child(client->dev.of_node, NULL))
|
||||
return 0;
|
||||
|
||||
for (fan_idx = 0; fan_idx < data->fans; ++fan_idx)
|
||||
data->fan[fan_idx].enabled = false;
|
||||
|
||||
for_each_child_of_node(client->dev.of_node, node) {
|
||||
const __be32 *property;
|
||||
int len;
|
||||
struct of_fan_attribute *attr;
|
||||
|
||||
property = of_get_property(node, "reg", &len);
|
||||
if (!property || len != sizeof(int)) {
|
||||
dev_err(&client->dev, "invalid reg on %s\n",
|
||||
node->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
fan_idx = be32_to_cpup(property);
|
||||
if (fan_idx >= data->fans) {
|
||||
dev_err(&client->dev,
|
||||
"invalid fan index %d on %s\n",
|
||||
fan_idx, node->full_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
data->fan[fan_idx].enabled = true;
|
||||
|
||||
for (attr = of_fan_attributes; attr->name; ++attr) {
|
||||
int status = 0;
|
||||
long value;
|
||||
property = of_get_property(node, attr->name, &len);
|
||||
if (!property)
|
||||
continue;
|
||||
if (len != sizeof(int)) {
|
||||
dev_err(&client->dev, "invalid %s on %s\n",
|
||||
attr->name, node->full_name);
|
||||
continue;
|
||||
}
|
||||
value = be32_to_cpup(property);
|
||||
status = attr->set(client, fan_idx, value);
|
||||
if (status == -EINVAL) {
|
||||
dev_err(&client->dev,
|
||||
"invalid value for %s on %s\n",
|
||||
attr->name, node->full_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void emc2305_get_config(struct i2c_client *client)
|
||||
{
|
||||
int i;
|
||||
struct emc2305_data *data = i2c_get_clientdata(client);
|
||||
|
||||
for (i = 0; i < data->fans; ++i) {
|
||||
data->fan[i].enabled = true;
|
||||
emc2305_update_fan(client, i);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
emc2305_config_of(client);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
emc2305_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||
{
|
||||
struct emc2305_data *data;
|
||||
int status;
|
||||
int i;
|
||||
int fan_idx;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
data = kzalloc(sizeof(struct emc2305_data), GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, data);
|
||||
mutex_init(&data->update_lock);
|
||||
|
||||
status = i2c_smbus_read_byte_data(client, REG_PRODUCT_ID);
|
||||
switch (status) {
|
||||
case 0x34: /* EMC2305 */
|
||||
data->fans = 5;
|
||||
break;
|
||||
case 0x35: /* EMC2303 */
|
||||
data->fans = 3;
|
||||
break;
|
||||
case 0x36: /* EMC2302 */
|
||||
data->fans = 2;
|
||||
break;
|
||||
case 0x37: /* EMC2301 */
|
||||
data->fans = 1;
|
||||
break;
|
||||
default:
|
||||
if (status >= 0)
|
||||
status = -EINVAL;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
emc2305_get_config(client);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(emc2305_attr_common); ++i) {
|
||||
status = device_create_file(&client->dev,
|
||||
&emc2305_attr_common[i].dev_attr);
|
||||
if (status)
|
||||
goto exit_remove;
|
||||
}
|
||||
for (fan_idx = 0; fan_idx < data->fans; ++fan_idx)
|
||||
for (i = 0; i < EMC2305_NUM_FAN_ATTRS; ++i) {
|
||||
if (!data->fan[fan_idx].enabled)
|
||||
continue;
|
||||
status = device_create_file(
|
||||
&client->dev,
|
||||
&emc2305_fan_attrs[fan_idx][i].dev_attr);
|
||||
if (status)
|
||||
goto exit_remove_fans;
|
||||
}
|
||||
|
||||
data->hwmon_dev = hwmon_device_register(&client->dev);
|
||||
if (IS_ERR(data->hwmon_dev)) {
|
||||
status = PTR_ERR(data->hwmon_dev);
|
||||
goto exit_remove_fans;
|
||||
}
|
||||
|
||||
dev_info(&client->dev, "%s: sensor '%s'\n",
|
||||
dev_name(data->hwmon_dev), client->name);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_remove_fans:
|
||||
for (fan_idx = 0; fan_idx < data->fans; ++fan_idx)
|
||||
for (i = 0; i < EMC2305_NUM_FAN_ATTRS; ++i)
|
||||
device_remove_file(
|
||||
&client->dev,
|
||||
&emc2305_fan_attrs[fan_idx][i].dev_attr);
|
||||
|
||||
exit_remove:
|
||||
for (i = 0; i < ARRAY_SIZE(emc2305_attr_common); ++i)
|
||||
device_remove_file(&client->dev,
|
||||
&emc2305_attr_common[i].dev_attr);
|
||||
exit_free:
|
||||
kfree(data);
|
||||
return status;
|
||||
}
|
||||
|
||||
static const struct i2c_device_id emc2305_id[] = {
|
||||
{ "emc2305", 0 },
|
||||
{ "emc2303", 0 },
|
||||
{ "emc2302", 0 },
|
||||
{ "emc2301", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, emc2305_id);
|
||||
|
||||
/* Return 0 if detection is successful, -ENODEV otherwise */
|
||||
static int
|
||||
emc2305_detect(struct i2c_client *new_client, struct i2c_board_info *info)
|
||||
{
|
||||
struct i2c_adapter *adapter = new_client->adapter;
|
||||
int manufacturer, product;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
|
||||
return -ENODEV;
|
||||
|
||||
manufacturer =
|
||||
i2c_smbus_read_byte_data(new_client, REG_MANUFACTURER_ID);
|
||||
if (manufacturer != 0x5D)
|
||||
return -ENODEV;
|
||||
|
||||
product = i2c_smbus_read_byte_data(new_client, REG_PRODUCT_ID);
|
||||
|
||||
switch (product) {
|
||||
case 0x34:
|
||||
strlcpy(info->type, "emc2305", I2C_NAME_SIZE);
|
||||
break;
|
||||
case 0x35:
|
||||
strlcpy(info->type, "emc2303", I2C_NAME_SIZE);
|
||||
break;
|
||||
case 0x36:
|
||||
strlcpy(info->type, "emc2302", I2C_NAME_SIZE);
|
||||
break;
|
||||
case 0x37:
|
||||
strlcpy(info->type, "emc2301", I2C_NAME_SIZE);
|
||||
break;
|
||||
default:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver emc2305_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "emc2305",
|
||||
},
|
||||
.probe = emc2305_probe,
|
||||
.remove = emc2305_remove,
|
||||
.id_table = emc2305_id,
|
||||
/*
|
||||
.detect = emc2305_detect,
|
||||
.address_list = i2c_adresses,
|
||||
*/
|
||||
};
|
||||
|
||||
module_i2c_driver(emc2305_driver);
|
||||
|
||||
MODULE_AUTHOR("Reinhard Pfau <pfau@gdsys.de>");
|
||||
MODULE_DESCRIPTION("SMSC EMC2305 hwmon driver");
|
||||
MODULE_LICENSE("GPL");
|
@ -0,0 +1,425 @@
|
||||
/*
|
||||
* pmbus.h - Common defines and structures for PMBus devices
|
||||
*
|
||||
* Copyright (c) 2010, 2011 Ericsson AB.
|
||||
* Copyright (c) 2012 Guenter Roeck
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef PMBUS_H
|
||||
#define PMBUS_H
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/regulator/driver.h>
|
||||
|
||||
/*
|
||||
* Registers
|
||||
*/
|
||||
enum pmbus_regs {
|
||||
PMBUS_PAGE = 0x00,
|
||||
PMBUS_OPERATION = 0x01,
|
||||
PMBUS_ON_OFF_CONFIG = 0x02,
|
||||
PMBUS_CLEAR_FAULTS = 0x03,
|
||||
PMBUS_PHASE = 0x04,
|
||||
|
||||
PMBUS_CAPABILITY = 0x19,
|
||||
PMBUS_QUERY = 0x1A,
|
||||
|
||||
PMBUS_VOUT_MODE = 0x20,
|
||||
PMBUS_VOUT_COMMAND = 0x21,
|
||||
PMBUS_VOUT_TRIM = 0x22,
|
||||
PMBUS_VOUT_CAL_OFFSET = 0x23,
|
||||
PMBUS_VOUT_MAX = 0x24,
|
||||
PMBUS_VOUT_MARGIN_HIGH = 0x25,
|
||||
PMBUS_VOUT_MARGIN_LOW = 0x26,
|
||||
PMBUS_VOUT_TRANSITION_RATE = 0x27,
|
||||
PMBUS_VOUT_DROOP = 0x28,
|
||||
PMBUS_VOUT_SCALE_LOOP = 0x29,
|
||||
PMBUS_VOUT_SCALE_MONITOR = 0x2A,
|
||||
|
||||
PMBUS_COEFFICIENTS = 0x30,
|
||||
PMBUS_POUT_MAX = 0x31,
|
||||
|
||||
PMBUS_FAN_CONFIG_12 = 0x3A,
|
||||
PMBUS_FAN_COMMAND_1 = 0x3B,
|
||||
PMBUS_FAN_COMMAND_2 = 0x3C,
|
||||
PMBUS_FAN_CONFIG_34 = 0x3D,
|
||||
PMBUS_FAN_COMMAND_3 = 0x3E,
|
||||
PMBUS_FAN_COMMAND_4 = 0x3F,
|
||||
|
||||
PMBUS_VOUT_OV_FAULT_LIMIT = 0x40,
|
||||
PMBUS_VOUT_OV_FAULT_RESPONSE = 0x41,
|
||||
PMBUS_VOUT_OV_WARN_LIMIT = 0x42,
|
||||
PMBUS_VOUT_UV_WARN_LIMIT = 0x43,
|
||||
PMBUS_VOUT_UV_FAULT_LIMIT = 0x44,
|
||||
PMBUS_VOUT_UV_FAULT_RESPONSE = 0x45,
|
||||
PMBUS_IOUT_OC_FAULT_LIMIT = 0x46,
|
||||
PMBUS_IOUT_OC_FAULT_RESPONSE = 0x47,
|
||||
PMBUS_IOUT_OC_LV_FAULT_LIMIT = 0x48,
|
||||
PMBUS_IOUT_OC_LV_FAULT_RESPONSE = 0x49,
|
||||
PMBUS_IOUT_OC_WARN_LIMIT = 0x4A,
|
||||
PMBUS_IOUT_UC_FAULT_LIMIT = 0x4B,
|
||||
PMBUS_IOUT_UC_FAULT_RESPONSE = 0x4C,
|
||||
|
||||
PMBUS_OT_FAULT_LIMIT = 0x4F,
|
||||
PMBUS_OT_FAULT_RESPONSE = 0x50,
|
||||
PMBUS_OT_WARN_LIMIT = 0x51,
|
||||
PMBUS_UT_WARN_LIMIT = 0x52,
|
||||
PMBUS_UT_FAULT_LIMIT = 0x53,
|
||||
PMBUS_UT_FAULT_RESPONSE = 0x54,
|
||||
PMBUS_VIN_OV_FAULT_LIMIT = 0x55,
|
||||
PMBUS_VIN_OV_FAULT_RESPONSE = 0x56,
|
||||
PMBUS_VIN_OV_WARN_LIMIT = 0x57,
|
||||
PMBUS_VIN_UV_WARN_LIMIT = 0x58,
|
||||
PMBUS_VIN_UV_FAULT_LIMIT = 0x59,
|
||||
|
||||
PMBUS_IIN_OC_FAULT_LIMIT = 0x5B,
|
||||
PMBUS_IIN_OC_WARN_LIMIT = 0x5D,
|
||||
|
||||
PMBUS_POUT_OP_FAULT_LIMIT = 0x68,
|
||||
PMBUS_POUT_OP_WARN_LIMIT = 0x6A,
|
||||
PMBUS_PIN_OP_WARN_LIMIT = 0x6B,
|
||||
|
||||
PMBUS_STATUS_BYTE = 0x78,
|
||||
PMBUS_STATUS_WORD = 0x79,
|
||||
PMBUS_STATUS_VOUT = 0x7A,
|
||||
PMBUS_STATUS_IOUT = 0x7B,
|
||||
PMBUS_STATUS_INPUT = 0x7C,
|
||||
PMBUS_STATUS_TEMPERATURE = 0x7D,
|
||||
PMBUS_STATUS_CML = 0x7E,
|
||||
PMBUS_STATUS_OTHER = 0x7F,
|
||||
PMBUS_STATUS_MFR_SPECIFIC = 0x80,
|
||||
PMBUS_STATUS_FAN_12 = 0x81,
|
||||
PMBUS_STATUS_FAN_34 = 0x82,
|
||||
|
||||
PMBUS_READ_VIN = 0x88,
|
||||
PMBUS_READ_IIN = 0x89,
|
||||
PMBUS_READ_VCAP = 0x8A,
|
||||
PMBUS_READ_VOUT = 0x8B,
|
||||
PMBUS_READ_IOUT = 0x8C,
|
||||
PMBUS_READ_TEMPERATURE_1 = 0x8D,
|
||||
PMBUS_READ_TEMPERATURE_2 = 0x8E,
|
||||
PMBUS_READ_TEMPERATURE_3 = 0x8F,
|
||||
PMBUS_READ_FAN_SPEED_1 = 0x90,
|
||||
PMBUS_READ_FAN_SPEED_2 = 0x91,
|
||||
PMBUS_READ_FAN_SPEED_3 = 0x92,
|
||||
PMBUS_READ_FAN_SPEED_4 = 0x93,
|
||||
PMBUS_READ_DUTY_CYCLE = 0x94,
|
||||
PMBUS_READ_FREQUENCY = 0x95,
|
||||
PMBUS_READ_POUT = 0x96,
|
||||
PMBUS_READ_PIN = 0x97,
|
||||
|
||||
PMBUS_REVISION = 0x98,
|
||||
PMBUS_MFR_ID = 0x99,
|
||||
PMBUS_MFR_MODEL = 0x9A,
|
||||
PMBUS_MFR_REVISION = 0x9B,
|
||||
PMBUS_MFR_LOCATION = 0x9C,
|
||||
PMBUS_MFR_DATE = 0x9D,
|
||||
PMBUS_MFR_SERIAL = 0x9E,
|
||||
|
||||
/*
|
||||
* Virtual registers.
|
||||
* Useful to support attributes which are not supported by standard PMBus
|
||||
* registers but exist as manufacturer specific registers on individual chips.
|
||||
* Must be mapped to real registers in device specific code.
|
||||
*
|
||||
* Semantics:
|
||||
* Virtual registers are all word size.
|
||||
* READ registers are read-only; writes are either ignored or return an error.
|
||||
* RESET registers are read/write. Reading reset registers returns zero
|
||||
* (used for detection), writing any value causes the associated history to be
|
||||
* reset.
|
||||
* Virtual registers have to be handled in device specific driver code. Chip
|
||||
* driver code returns non-negative register values if a virtual register is
|
||||
* supported, or a negative error code if not. The chip driver may return
|
||||
* -ENODATA or any other error code in this case, though an error code other
|
||||
* than -ENODATA is handled more efficiently and thus preferred. Either case,
|
||||
* the calling PMBus core code will abort if the chip driver returns an error
|
||||
* code when reading or writing virtual registers.
|
||||
*/
|
||||
PMBUS_VIRT_BASE = 0x100,
|
||||
PMBUS_VIRT_READ_TEMP_AVG,
|
||||
PMBUS_VIRT_READ_TEMP_MIN,
|
||||
PMBUS_VIRT_READ_TEMP_MAX,
|
||||
PMBUS_VIRT_RESET_TEMP_HISTORY,
|
||||
PMBUS_VIRT_READ_VIN_AVG,
|
||||
PMBUS_VIRT_READ_VIN_MIN,
|
||||
PMBUS_VIRT_READ_VIN_MAX,
|
||||
PMBUS_VIRT_RESET_VIN_HISTORY,
|
||||
PMBUS_VIRT_READ_IIN_AVG,
|
||||
PMBUS_VIRT_READ_IIN_MIN,
|
||||
PMBUS_VIRT_READ_IIN_MAX,
|
||||
PMBUS_VIRT_RESET_IIN_HISTORY,
|
||||
PMBUS_VIRT_READ_PIN_AVG,
|
||||
PMBUS_VIRT_READ_PIN_MIN,
|
||||
PMBUS_VIRT_READ_PIN_MAX,
|
||||
PMBUS_VIRT_RESET_PIN_HISTORY,
|
||||
PMBUS_VIRT_READ_POUT_AVG,
|
||||
PMBUS_VIRT_READ_POUT_MIN,
|
||||
PMBUS_VIRT_READ_POUT_MAX,
|
||||
PMBUS_VIRT_RESET_POUT_HISTORY,
|
||||
PMBUS_VIRT_READ_VOUT_AVG,
|
||||
PMBUS_VIRT_READ_VOUT_MIN,
|
||||
PMBUS_VIRT_READ_VOUT_MAX,
|
||||
PMBUS_VIRT_RESET_VOUT_HISTORY,
|
||||
PMBUS_VIRT_READ_IOUT_AVG,
|
||||
PMBUS_VIRT_READ_IOUT_MIN,
|
||||
PMBUS_VIRT_READ_IOUT_MAX,
|
||||
PMBUS_VIRT_RESET_IOUT_HISTORY,
|
||||
PMBUS_VIRT_READ_TEMP2_AVG,
|
||||
PMBUS_VIRT_READ_TEMP2_MIN,
|
||||
PMBUS_VIRT_READ_TEMP2_MAX,
|
||||
PMBUS_VIRT_RESET_TEMP2_HISTORY,
|
||||
|
||||
PMBUS_VIRT_READ_VMON,
|
||||
PMBUS_VIRT_VMON_UV_WARN_LIMIT,
|
||||
PMBUS_VIRT_VMON_OV_WARN_LIMIT,
|
||||
PMBUS_VIRT_VMON_UV_FAULT_LIMIT,
|
||||
PMBUS_VIRT_VMON_OV_FAULT_LIMIT,
|
||||
PMBUS_VIRT_STATUS_VMON,
|
||||
};
|
||||
|
||||
/*
|
||||
* OPERATION
|
||||
*/
|
||||
#define PB_OPERATION_CONTROL_ON BIT(7)
|
||||
|
||||
/*
|
||||
* CAPABILITY
|
||||
*/
|
||||
#define PB_CAPABILITY_SMBALERT BIT(4)
|
||||
#define PB_CAPABILITY_ERROR_CHECK BIT(7)
|
||||
|
||||
/*
|
||||
* VOUT_MODE
|
||||
*/
|
||||
#define PB_VOUT_MODE_MODE_MASK 0xe0
|
||||
#define PB_VOUT_MODE_PARAM_MASK 0x1f
|
||||
|
||||
#define PB_VOUT_MODE_LINEAR 0x00
|
||||
#define PB_VOUT_MODE_VID 0x20
|
||||
#define PB_VOUT_MODE_DIRECT 0x40
|
||||
|
||||
/*
|
||||
* Fan configuration
|
||||
*/
|
||||
#define PB_FAN_2_PULSE_MASK (BIT(0) | BIT(1))
|
||||
#define PB_FAN_2_RPM BIT(2)
|
||||
#define PB_FAN_2_INSTALLED BIT(3)
|
||||
#define PB_FAN_1_PULSE_MASK (BIT(4) | BIT(5))
|
||||
#define PB_FAN_1_RPM BIT(6)
|
||||
#define PB_FAN_1_INSTALLED BIT(7)
|
||||
|
||||
/*
|
||||
* STATUS_BYTE, STATUS_WORD (lower)
|
||||
*/
|
||||
#define PB_STATUS_NONE_ABOVE BIT(0)
|
||||
#define PB_STATUS_CML BIT(1)
|
||||
#define PB_STATUS_TEMPERATURE BIT(2)
|
||||
#define PB_STATUS_VIN_UV BIT(3)
|
||||
#define PB_STATUS_IOUT_OC BIT(4)
|
||||
#define PB_STATUS_VOUT_OV BIT(5)
|
||||
#define PB_STATUS_OFF BIT(6)
|
||||
#define PB_STATUS_BUSY BIT(7)
|
||||
|
||||
/*
|
||||
* STATUS_WORD (upper)
|
||||
*/
|
||||
#define PB_STATUS_UNKNOWN BIT(8)
|
||||
#define PB_STATUS_OTHER BIT(9)
|
||||
#define PB_STATUS_FANS BIT(10)
|
||||
#define PB_STATUS_POWER_GOOD_N BIT(11)
|
||||
#define PB_STATUS_WORD_MFR BIT(12)
|
||||
#define PB_STATUS_INPUT BIT(13)
|
||||
#define PB_STATUS_IOUT_POUT BIT(14)
|
||||
#define PB_STATUS_VOUT BIT(15)
|
||||
|
||||
/*
|
||||
* STATUS_IOUT
|
||||
*/
|
||||
#define PB_POUT_OP_WARNING BIT(0)
|
||||
#define PB_POUT_OP_FAULT BIT(1)
|
||||
#define PB_POWER_LIMITING BIT(2)
|
||||
#define PB_CURRENT_SHARE_FAULT BIT(3)
|
||||
#define PB_IOUT_UC_FAULT BIT(4)
|
||||
#define PB_IOUT_OC_WARNING BIT(5)
|
||||
#define PB_IOUT_OC_LV_FAULT BIT(6)
|
||||
#define PB_IOUT_OC_FAULT BIT(7)
|
||||
|
||||
/*
|
||||
* STATUS_VOUT, STATUS_INPUT
|
||||
*/
|
||||
#define PB_VOLTAGE_UV_FAULT BIT(4)
|
||||
#define PB_VOLTAGE_UV_WARNING BIT(5)
|
||||
#define PB_VOLTAGE_OV_WARNING BIT(6)
|
||||
#define PB_VOLTAGE_OV_FAULT BIT(7)
|
||||
|
||||
/*
|
||||
* STATUS_INPUT
|
||||
*/
|
||||
#define PB_PIN_OP_WARNING BIT(0)
|
||||
#define PB_IIN_OC_WARNING BIT(1)
|
||||
#define PB_IIN_OC_FAULT BIT(2)
|
||||
|
||||
/*
|
||||
* STATUS_TEMPERATURE
|
||||
*/
|
||||
#define PB_TEMP_UT_FAULT BIT(4)
|
||||
#define PB_TEMP_UT_WARNING BIT(5)
|
||||
#define PB_TEMP_OT_WARNING BIT(6)
|
||||
#define PB_TEMP_OT_FAULT BIT(7)
|
||||
|
||||
/*
|
||||
* STATUS_FAN
|
||||
*/
|
||||
#define PB_FAN_AIRFLOW_WARNING BIT(0)
|
||||
#define PB_FAN_AIRFLOW_FAULT BIT(1)
|
||||
#define PB_FAN_FAN2_SPEED_OVERRIDE BIT(2)
|
||||
#define PB_FAN_FAN1_SPEED_OVERRIDE BIT(3)
|
||||
#define PB_FAN_FAN2_WARNING BIT(4)
|
||||
#define PB_FAN_FAN1_WARNING BIT(5)
|
||||
#define PB_FAN_FAN2_FAULT BIT(6)
|
||||
#define PB_FAN_FAN1_FAULT BIT(7)
|
||||
|
||||
/*
|
||||
* CML_FAULT_STATUS
|
||||
*/
|
||||
#define PB_CML_FAULT_OTHER_MEM_LOGIC BIT(0)
|
||||
#define PB_CML_FAULT_OTHER_COMM BIT(1)
|
||||
#define PB_CML_FAULT_PROCESSOR BIT(3)
|
||||
#define PB_CML_FAULT_MEMORY BIT(4)
|
||||
#define PB_CML_FAULT_PACKET_ERROR BIT(5)
|
||||
#define PB_CML_FAULT_INVALID_DATA BIT(6)
|
||||
#define PB_CML_FAULT_INVALID_COMMAND BIT(7)
|
||||
|
||||
enum pmbus_sensor_classes {
|
||||
PSC_VOLTAGE_IN = 0,
|
||||
PSC_VOLTAGE_OUT,
|
||||
PSC_CURRENT_IN,
|
||||
PSC_CURRENT_OUT,
|
||||
PSC_POWER,
|
||||
PSC_TEMPERATURE,
|
||||
PSC_FAN,
|
||||
PSC_NUM_CLASSES /* Number of power sensor classes */
|
||||
};
|
||||
|
||||
#define PMBUS_PAGES 32 /* Per PMBus specification */
|
||||
|
||||
/* Functionality bit mask */
|
||||
#define PMBUS_HAVE_VIN BIT(0)
|
||||
#define PMBUS_HAVE_VCAP BIT(1)
|
||||
#define PMBUS_HAVE_VOUT BIT(2)
|
||||
#define PMBUS_HAVE_IIN BIT(3)
|
||||
#define PMBUS_HAVE_IOUT BIT(4)
|
||||
#define PMBUS_HAVE_PIN BIT(5)
|
||||
#define PMBUS_HAVE_POUT BIT(6)
|
||||
#define PMBUS_HAVE_FAN12 BIT(7)
|
||||
#define PMBUS_HAVE_FAN34 BIT(8)
|
||||
#define PMBUS_HAVE_TEMP BIT(9)
|
||||
#define PMBUS_HAVE_TEMP2 BIT(10)
|
||||
#define PMBUS_HAVE_TEMP3 BIT(11)
|
||||
#define PMBUS_HAVE_STATUS_VOUT BIT(12)
|
||||
#define PMBUS_HAVE_STATUS_IOUT BIT(13)
|
||||
#define PMBUS_HAVE_STATUS_INPUT BIT(14)
|
||||
#define PMBUS_HAVE_STATUS_TEMP BIT(15)
|
||||
#define PMBUS_HAVE_STATUS_FAN12 BIT(16)
|
||||
#define PMBUS_HAVE_STATUS_FAN34 BIT(17)
|
||||
#define PMBUS_HAVE_VMON BIT(18)
|
||||
#define PMBUS_HAVE_STATUS_VMON BIT(19)
|
||||
|
||||
enum pmbus_data_format { linear = 0, direct, vid };
|
||||
enum vrm_version { vr11 = 0, vr12 };
|
||||
|
||||
struct pmbus_driver_info {
|
||||
int pages; /* Total number of pages */
|
||||
enum pmbus_data_format format[PSC_NUM_CLASSES];
|
||||
enum vrm_version vrm_version;
|
||||
/*
|
||||
* Support one set of coefficients for each sensor type
|
||||
* Used for chips providing data in direct mode.
|
||||
*/
|
||||
int m[PSC_NUM_CLASSES]; /* mantissa for direct data format */
|
||||
int b[PSC_NUM_CLASSES]; /* offset */
|
||||
int R[PSC_NUM_CLASSES]; /* exponent */
|
||||
|
||||
u32 func[PMBUS_PAGES]; /* Functionality, per page */
|
||||
/*
|
||||
* The following functions map manufacturing specific register values
|
||||
* to PMBus standard register values. Specify only if mapping is
|
||||
* necessary.
|
||||
* Functions return the register value (read) or zero (write) if
|
||||
* successful. A return value of -ENODATA indicates that there is no
|
||||
* manufacturer specific register, but that a standard PMBus register
|
||||
* may exist. Any other negative return value indicates that the
|
||||
* register does not exist, and that no attempt should be made to read
|
||||
* the standard register.
|
||||
*/
|
||||
int (*read_byte_data)(struct i2c_client *client, int page, int reg);
|
||||
int (*read_word_data)(struct i2c_client *client, int page, int reg);
|
||||
int (*write_word_data)(struct i2c_client *client, int page, int reg,
|
||||
u16 word);
|
||||
int (*write_byte)(struct i2c_client *client, int page, u8 value);
|
||||
/*
|
||||
* The identify function determines supported PMBus functionality.
|
||||
* This function is only necessary if a chip driver supports multiple
|
||||
* chips, and the chip functionality is not pre-determined.
|
||||
*/
|
||||
int (*identify)(struct i2c_client *client,
|
||||
struct pmbus_driver_info *info);
|
||||
|
||||
/* Regulator functionality, if supported by this chip driver. */
|
||||
int num_regulators;
|
||||
const struct regulator_desc *reg_desc;
|
||||
};
|
||||
|
||||
/* Regulator ops */
|
||||
|
||||
extern const struct regulator_ops pmbus_regulator_ops;
|
||||
|
||||
/* Macro for filling in array of struct regulator_desc */
|
||||
#define PMBUS_REGULATOR(_name, _id) \
|
||||
[_id] = { \
|
||||
.name = (_name # _id), \
|
||||
.id = (_id), \
|
||||
.of_match = of_match_ptr(_name # _id), \
|
||||
.regulators_node = of_match_ptr("regulators"), \
|
||||
.ops = &pmbus_regulator_ops, \
|
||||
.type = REGULATOR_VOLTAGE, \
|
||||
.owner = THIS_MODULE, \
|
||||
}
|
||||
|
||||
/* Function declarations */
|
||||
|
||||
void pmbus_clear_cache(struct i2c_client *client);
|
||||
int pmbus_set_page(struct i2c_client *client, u8 page);
|
||||
int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
|
||||
int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
|
||||
int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
|
||||
int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
|
||||
int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
|
||||
u8 value);
|
||||
int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
|
||||
u8 mask, u8 value);
|
||||
void pmbus_clear_faults(struct i2c_client *client);
|
||||
bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
|
||||
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
|
||||
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
|
||||
struct pmbus_driver_info *info);
|
||||
int pmbus_do_remove(struct i2c_client *client);
|
||||
const struct pmbus_driver_info *pmbus_get_driver_info(struct i2c_client
|
||||
*client);
|
||||
|
||||
#endif /* PMBUS_H */
|
78
platform/broadcom/sonic-platform-modules-dell/n3248te/scripts/fancontrol.sh
Executable file
78
platform/broadcom/sonic-platform-modules-dell/n3248te/scripts/fancontrol.sh
Executable file
@ -0,0 +1,78 @@
|
||||
#! /bin/sh
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: fancontrol
|
||||
# Required-Start: $remote_fs
|
||||
# Required-Stop: $remote_fs
|
||||
# Default-Start: 2 3 4 5
|
||||
# Default-Stop:
|
||||
# Short-Description: fancontrol
|
||||
# Description: fan speed regulator
|
||||
### END INIT INFO
|
||||
|
||||
. /lib/lsb/init-functions
|
||||
|
||||
[ -f /etc/default/rcS ] && . /etc/default/rcS
|
||||
PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin
|
||||
DAEMON=/usr/local/bin/fancontrol
|
||||
DESC="fan speed regulator"
|
||||
NAME="fancontrol"
|
||||
PIDFILE=/var/run/fancontrol.pid
|
||||
PLATFORMPATH=/sys/devices/platform/LPC
|
||||
MAIN_CONF=/usr/share/sonic/device/x86_64-dell_s3000_c2338-r0/fancontrol
|
||||
DEVPATH=/sys/devices/pci0000:00/0000:00:13.0/i2c-0/i2c-8/i2c-23/23-004d
|
||||
|
||||
test -x $DAEMON || exit 0
|
||||
|
||||
for i in 1 2 3
|
||||
do
|
||||
j=$i
|
||||
[ $i -eq 3 ] && j=4
|
||||
FANFAULT=$(cat ${DEVPATH}/fan${j}_fault)
|
||||
[ $FANFAULT = 1 ] && continue
|
||||
FANDIR=$(cat ${PLATFORMPATH}/fan${i}_dir)
|
||||
done
|
||||
CONF=${MAIN_CONF}-${FANDIR}
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
if [ -f $CONF ] ; then
|
||||
if $DAEMON --check $CONF 1>/dev/null 2>/dev/null ; then
|
||||
log_daemon_msg "Starting $DESC" "$NAME\n"
|
||||
start-stop-daemon --start --quiet --pidfile $PIDFILE --startas $DAEMON $CONF
|
||||
log_end_msg $?
|
||||
else
|
||||
log_failure_msg "Not starting fancontrol, broken configuration file; please re-run pwmconfig."
|
||||
fi
|
||||
else
|
||||
if [ "$VERBOSE" != no ]; then
|
||||
log_warning_msg "Not starting fancontrol; run pwmconfig first."
|
||||
fi
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
log_daemon_msg "Stopping $DESC" "$NAME"
|
||||
start-stop-daemon --stop --quiet --pidfile $PIDFILE --oknodo --startas $DAEMON $CONF
|
||||
rm -f $PIDFILE
|
||||
log_end_msg $?
|
||||
;;
|
||||
restart)
|
||||
$0 stop
|
||||
sleep 3
|
||||
$0 start
|
||||
;;
|
||||
force-reload)
|
||||
if start-stop-daemon --stop --test --quiet --pidfile $PIDFILE --startas $DAEMON $CONF ; then
|
||||
$0 restart
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
status_of_proc $DAEMON $NAME $CONF && exit 0 || exit $?
|
||||
;;
|
||||
*)
|
||||
log_success_msg "Usage: /etc/init.d/fancontrol {start|stop|restart|force-reload|status}"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
#platform init script for Dell N3248TE
|
||||
|
||||
source dell_i2c_utils.sh
|
||||
|
||||
#Attach/Detach the system devices
|
||||
sys_devices() {
|
||||
case $1 in
|
||||
"new_device") #syseeprom
|
||||
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-2/$1"
|
||||
#Attach Fan Controller
|
||||
i2c_config "echo emc2305 0x2c > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
#Attach temperature monitor
|
||||
i2c_config "echo tmp75 0x49 > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo tmp75 0x4a > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo tmp75 0x4b > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo tmp75 0x4c > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo tmp75 0x4f > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
#Attach PSU Controller
|
||||
i2c_config "echo dps460 0x5e > /sys/bus/i2c/devices/i2c-10/$1"
|
||||
i2c_config "echo dps460 0x5e > /sys/bus/i2c/devices/i2c-11/$1"
|
||||
#Attach PSU EEPROM
|
||||
i2c_config "echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-10/$1"
|
||||
i2c_config "echo 24c02 0x56 > /sys/bus/i2c/devices/i2c-11/$1"
|
||||
#Attach Fan EEPROM
|
||||
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-15/$1"
|
||||
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-16/$1"
|
||||
i2c_config "echo 24c02 0x50 > /sys/bus/i2c/devices/i2c-17/$1"
|
||||
;;
|
||||
"delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-2/$1"
|
||||
i2c_config "echo 0x2c > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo 0x49 > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo 0x4a > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo 0x4b > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo 0x4c > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo 0x4f > /sys/bus/i2c/devices/i2c-7/$1"
|
||||
i2c_config "echo 0x5e > /sys/bus/i2c/devices/i2c-10/$1"
|
||||
i2c_config "echo 0x5e > /sys/bus/i2c/devices/i2c-11/$1"
|
||||
i2c_config "echo 0x56 > /sys/bus/i2c/devices/i2c-10/$1"
|
||||
i2c_config "echo 0x56 > /sys/bus/i2c/devices/i2c-11/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-15/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-16/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-17/$1"
|
||||
;;
|
||||
*) echo "n3248te_platform: main_board_mux : invalid command !"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#Attach/Detach the SFP modules on PCA9548_2
|
||||
switch_board_sfp() {
|
||||
case $1 in
|
||||
"new_device") i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-20/$1"
|
||||
i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-21/$1"
|
||||
i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-22/$1"
|
||||
i2c_config "echo optoe2 0x50 > /sys/bus/i2c/devices/i2c-23/$1"
|
||||
i2c_config "echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-24/$1"
|
||||
i2c_config "echo optoe1 0x50 > /sys/bus/i2c/devices/i2c-25/$1"
|
||||
;;
|
||||
"delete_device") i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-20/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-21/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-22/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-23/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-24/$1"
|
||||
i2c_config "echo 0x50 > /sys/bus/i2c/devices/i2c-25/$1"
|
||||
;;
|
||||
*) echo "n3248te_platform: switch_board_sfp: invalid command !"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
#Forcibly bring quad-port phy out of reset for 48-1G port functionality
|
||||
|
||||
platform_firmware_versions() {
|
||||
|
||||
FIRMWARE_VERSION_FILE=/var/log/firmware_versions
|
||||
rm -rf ${FIRMWARE_VERSION_FILE}
|
||||
# Get BIOS version
|
||||
echo "BIOS: `dmidecode -s system-version `" > $FIRMWARE_VERSION_FILE
|
||||
# Get CPU CPLD version
|
||||
echo "CPU CPLD: $((`cat /sys/devices/platform/dell-n3248te-cpld.0/cpu_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-n3248te-cpld.0/cpu_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE
|
||||
# Get SYS CPLD version
|
||||
echo "SYS CPLD: $((`cat /sys/devices/platform/dell-n3248te-cpld.0/sys_cpld_mjr_ver`)).$((`cat /sys/devices/platform/dell-n3248te-cpld.0/sys_cpld_mnr_ver`))" >> $FIRMWARE_VERSION_FILE
|
||||
|
||||
}
|
||||
|
||||
install_python_api_package() {
|
||||
device="/usr/share/sonic/device"
|
||||
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
||||
|
||||
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"
|
||||
mkdir -p $(dirname $REBOOT_REASON_FILE)
|
||||
|
||||
# Handle First Boot into software version with reboot cause determination support
|
||||
if [[ ! -e $REBOOT_REASON_FILE ]]; then
|
||||
echo "0x0" > $REBOOT_REASON_FILE
|
||||
else
|
||||
cat /sys/devices/platform/dell-n3248te-cpld.0/reboot_cause > $REBOOT_REASON_FILE
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
if [[ "$1" == "init" ]]; then
|
||||
modprobe i2c-dev
|
||||
modprobe i2c-mux-pca954x force_deselect_on_exit=1
|
||||
modprobe pmbus
|
||||
modprobe emc2305
|
||||
modprobe dps200
|
||||
modprobe dell_n3248te_platform
|
||||
|
||||
sys_devices "new_device"
|
||||
get_reboot_cause
|
||||
switch_board_sfp "new_device"
|
||||
echo 0xf0 > /sys/devices/platform/dell-n3248te-cpld.0/sfp_txdis
|
||||
install_python_api_package
|
||||
platform_firmware_versions
|
||||
elif [[ "$1" == "deinit" ]]; then
|
||||
switch_board_sfp "delete_device"
|
||||
sysdevices "delete_device"
|
||||
|
||||
modprobe -r dell_n3248te_platform
|
||||
|
||||
modprobe -r dps200
|
||||
modprobe -r emc2305
|
||||
modprobe -r pmbus
|
||||
modprobe -r i2c-mux-pca954x
|
||||
modprobe -r i2c-dev
|
||||
remove_python_api_package
|
||||
else
|
||||
echo "n3248te_platform : Invalid option !"
|
||||
fi
|
@ -0,0 +1,136 @@
|
||||
#!/usr/bin/python
|
||||
# This provies support for the following objects:
|
||||
# * Onboard temperature sensors
|
||||
# * FAN trays
|
||||
# * PSU
|
||||
|
||||
|
||||
import subprocess
|
||||
|
||||
output = ""
|
||||
try:
|
||||
rc = 0
|
||||
output = subprocess.check_output('/usr/bin/sensors').splitlines()
|
||||
|
||||
valid = False
|
||||
for line in output:
|
||||
if line.startswith('acpitz') or line.startswith('coretemp'):
|
||||
valid = True
|
||||
if valid:
|
||||
print line
|
||||
if line == '': valid = False
|
||||
|
||||
print "Onboard Temperature Sensors:"
|
||||
idx = 0
|
||||
for line in output:
|
||||
if line.startswith('tmp75'):
|
||||
print '\t' + output[idx+2].split('(')[0]
|
||||
idx += 1
|
||||
|
||||
print "\nFanTrays:"
|
||||
idx = 0
|
||||
found_emc = False
|
||||
for line in output:
|
||||
if line.startswith('emc'):
|
||||
found_emc = True
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/fan0_prs') as f:
|
||||
line = f.readline()
|
||||
present = int(line, 0)
|
||||
if present :
|
||||
print '\t' + 'FanTray1:'
|
||||
print '\t\t' + 'Fan Speed:' + (output[idx+2].split('(')[0]).split(':')[1]
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/fan0_dir') as f:
|
||||
line = f.readline()
|
||||
dir = 'Intake' if line[:-1] == 'B2F' else 'Exhaust'
|
||||
print '\t\t' + 'Airflow:\t' + dir
|
||||
else : print '\t' + 'FanTray1:\tNot Present'
|
||||
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/fan1_prs') as f:
|
||||
line = f.readline()
|
||||
present = int(line, 0)
|
||||
if present :
|
||||
print '\t' + 'FanTray2:'
|
||||
print '\t\t' + 'Fan Speed:' + (output[idx+3].split('(')[0]).split(':')[1]
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/fan1_dir') as f:
|
||||
line = f.readline()
|
||||
dir = 'Intake' if line[:-1] == 'B2F' else 'Exhaust'
|
||||
print '\t\t' + 'Airflow:\t' + dir
|
||||
else : print '\t' + 'FanTray2:\tNot Present'
|
||||
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/fan2_prs') as f:
|
||||
line = f.readline()
|
||||
present = int(line, 0)
|
||||
if present :
|
||||
print '\t' + 'FanTray3:'
|
||||
print '\t\t' + 'Fan Speed:' + (output[idx+4].split('(')[0]).split(':')[1]
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/fan2_dir') as f:
|
||||
line = f.readline()
|
||||
dir = 'Intake' if line[:-1] == 'B2F' else 'Exhaust'
|
||||
print '\t\t' + 'Airflow:\t' + dir
|
||||
else : print '\t' + 'FanTray3:\tNot Present'
|
||||
idx += 1
|
||||
if not found_emc :
|
||||
print '\t' + 'FanTray1:\tNot Present'
|
||||
print '\t' + 'FanTray2:\tNot Present'
|
||||
print '\t' + 'FanTray3:\tNot Present'
|
||||
|
||||
print '\nPSUs:'
|
||||
idx = 0
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/psu0_prs') as f:
|
||||
line = f.readline()
|
||||
found_psu1 = int(line, 0)
|
||||
if not found_psu1 :
|
||||
print '\tPSU1:\tNot Present'
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/psu1_prs') as f:
|
||||
line = f.readline()
|
||||
found_psu2 = int(line, 0)
|
||||
for line in output:
|
||||
if line.startswith('dps460-i2c-10'):
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/psu0_status') as f:
|
||||
line = f.readline()
|
||||
status = int(line, 0)
|
||||
if not status :
|
||||
print '\tPSU1:\tNot OK'
|
||||
break
|
||||
with open('/sys/bus/i2c/devices/10-0056/eeprom') as f:
|
||||
line = f.readline()
|
||||
dir = 'Exhaust' if 'FORWARD' in line else 'Intake'
|
||||
print '\tPSU1:'
|
||||
print '\t\t' + output[idx+2].split('(')[0]
|
||||
print '\t\t' + output[idx+4].split('(')[0]
|
||||
print '\t\t' + output[idx+6].split('(')[0]
|
||||
print '\t\t' + output[idx+7].split('(')[0]
|
||||
print '\t\t' + output[idx+9].split('(')[0]
|
||||
print '\t\t' + output[idx+11].split('(')[0]
|
||||
print '\t\t' + output[idx+12].split('(')[0]
|
||||
print '\t\t' + output[idx+14].split('(')[0]
|
||||
print '\t\t' + output[idx+15].split('(')[0]
|
||||
print '\t\t' + 'Airflow:\t\t ' + dir
|
||||
if line.startswith('dps460-i2c-11'):
|
||||
with open('/sys/devices/platform/dell-n3248te-cpld.0/psu1_status') as f:
|
||||
line = f.readline()
|
||||
status = int(line, 0)
|
||||
if not status :
|
||||
print '\tPSU2:\tNot OK'
|
||||
break
|
||||
print '\tPSU2:'
|
||||
with open('/sys/bus/i2c/devices/11-0056/eeprom') as f:
|
||||
line = f.readline()
|
||||
dir = 'Exhaust' if 'FORWARD' in line else 'Intake'
|
||||
print '\t\t' + output[idx+2].split('(')[0]
|
||||
print '\t\t' + output[idx+4].split('(')[0]
|
||||
print '\t\t' + output[idx+6].split('(')[0]
|
||||
print '\t\t' + output[idx+7].split('(')[0]
|
||||
print '\t\t' + output[idx+9].split('(')[0]
|
||||
print '\t\t' + output[idx+11].split('(')[0]
|
||||
print '\t\t' + output[idx+12].split('(')[0]
|
||||
print '\t\t' + output[idx+14].split('(')[0]
|
||||
print '\t\t' + output[idx+15].split('(')[0]
|
||||
print '\t\t' + 'Airflow:\t\t ' + dir
|
||||
idx += 1
|
||||
if not found_psu2 :
|
||||
print '\tPSU2:\tNot Present'
|
||||
|
||||
except subprocess.CalledProcessError as err:
|
||||
print ("Exception when calling get_sonic_error -> %s\n" %(err))
|
||||
rc = err.returncode
|
105
platform/broadcom/sonic-platform-modules-dell/n3248te/scripts/portiocfg.py
Executable file
105
platform/broadcom/sonic-platform-modules-dell/n3248te/scripts/portiocfg.py
Executable file
@ -0,0 +1,105 @@
|
||||
#!/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.
|
||||
#Script to read/write the portio based registers
|
||||
|
||||
import sys
|
||||
import os
|
||||
import getopt
|
||||
import struct
|
||||
|
||||
resource='/dev/port'
|
||||
|
||||
def usage():
|
||||
''' This is the Usage Method '''
|
||||
|
||||
print '\t\t portiocfg.py --default'
|
||||
print '\t\t portiocfg.py --get --offset <offset>'
|
||||
print '\t\t portiocfg.py --set --val <val> --offset <offset>'
|
||||
sys.exit(1)
|
||||
|
||||
def portio_reg_read(resource,offset):
|
||||
fd=os.open(resource, os.O_RDONLY)
|
||||
if(fd<0):
|
||||
print 'file open failed %s"%resource'
|
||||
return
|
||||
if(os.lseek(fd, offset, os.SEEK_SET) != offset):
|
||||
print 'lseek failed on %s'%resource
|
||||
return
|
||||
buf=os.read(fd,1)
|
||||
reg_val1=ord(buf)
|
||||
print 'reg value %x'%reg_val1
|
||||
os.close(fd)
|
||||
|
||||
def portio_reg_write(resource,offset,val):
|
||||
fd=os.open(resource,os.O_RDWR)
|
||||
if(fd<0):
|
||||
print 'file open failed %s"%resource'
|
||||
return
|
||||
if(os.lseek(fd, offset, os.SEEK_SET) != offset):
|
||||
print 'lseek failed on %s'%resource
|
||||
return
|
||||
ret=os.write(fd,struct.pack('B',val))
|
||||
if(ret != 1):
|
||||
print 'write failed %d'%ret
|
||||
return
|
||||
os.close(fd)
|
||||
|
||||
def main(argv):
|
||||
|
||||
''' The main function will read the user input from the
|
||||
command line argument and process the request '''
|
||||
|
||||
opts = ''
|
||||
val = ''
|
||||
choice = ''
|
||||
offset = ''
|
||||
|
||||
try:
|
||||
opts, args = getopt.getopt(argv, "hgs:" , \
|
||||
["val=","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 == '--offset':
|
||||
offset = int(arg,16)
|
||||
|
||||
elif opt == '--val':
|
||||
val = int(arg,16)
|
||||
|
||||
if choice == 'get' and offset != '':
|
||||
portio_reg_read(resource,offset)
|
||||
|
||||
elif choice == 'set' and offset != '' and val != '':
|
||||
portio_reg_write(resource,offset,val)
|
||||
|
||||
else:
|
||||
usage()
|
||||
|
||||
#Calling the main method
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv[1:])
|
||||
|
@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
port_notify
|
||||
port notify status change for SONiC
|
||||
"""
|
||||
|
||||
try:
|
||||
from datetime import datetime
|
||||
from swsscommon import swsscommon
|
||||
from sonic_py_common import daemon_base, logger
|
||||
except ImportError as e:
|
||||
raise ImportError (str(e) + " - required module not found")
|
||||
|
||||
#
|
||||
# Constants ====================================================================
|
||||
#
|
||||
|
||||
SYSLOG_IDENTIFIER = "port_notify"
|
||||
|
||||
|
||||
STATE_PORT_TABLE = 'PORT_TABLE'
|
||||
|
||||
|
||||
RJ45_PORT_START = 0;
|
||||
RJ45_PORT_END = 47;
|
||||
|
||||
# Global logger class instance
|
||||
helper_logger = logger.Logger(SYSLOG_IDENTIFIER)
|
||||
|
||||
XCVR_STATE_EMPTY = 0
|
||||
XCVR_STATE_ERROR = 1
|
||||
XCVR_STATE_INCOMP = 2
|
||||
XCVR_STATE_CONFIG = 3
|
||||
XCVR_STATE_READY = 4
|
||||
XCVR_STATE_TIMEOUT = 5
|
||||
|
||||
xcvr_state_tbl = {
|
||||
XCVR_STATE_EMPTY: { "xcvr_state": "N/A", "xcvr_app_status": "down" },
|
||||
XCVR_STATE_ERROR: { "xcvr_state": "Error", "xcvr_app_status": "down" },
|
||||
XCVR_STATE_INCOMP: { "xcvr_state": "Incompatible", "xcvr_app_status": "up" },
|
||||
XCVR_STATE_CONFIG: { "xcvr_state": "Config", "xcvr_app_status": "down" },
|
||||
XCVR_STATE_TIMEOUT: { "xcvr_state": "Timeout", "xcvr_app_status": "up" },
|
||||
XCVR_STATE_READY: { "xcvr_state": "Ready", "xcvr_app_status": "up" }
|
||||
}
|
||||
|
||||
# Wait for port init is done
|
||||
def wait_for_port_init_done():
|
||||
# Connect to APPL_DB and subscribe to PORT table notifications
|
||||
appl_db = daemon_base.db_connect("APPL_DB")
|
||||
|
||||
sel = swsscommon.Select()
|
||||
sst = swsscommon.SubscriberStateTable(appl_db, swsscommon.APP_PORT_TABLE_NAME)
|
||||
sel.addSelectable(sst)
|
||||
|
||||
# Make sure this daemon started after all port configured
|
||||
while True:
|
||||
(state, c) = sel.select(1000)
|
||||
if state == swsscommon.Select.TIMEOUT:
|
||||
continue
|
||||
if state != swsscommon.Select.OBJECT:
|
||||
helper_logger.log_warning("sel.select() did not return swsscommon.Select.OBJECT")
|
||||
continue
|
||||
|
||||
(key, op, fvp) = sst.pop()
|
||||
|
||||
# Wait until PortInitDone
|
||||
if key in ["PortInitDone"]:
|
||||
break
|
||||
|
||||
def notify_port_xcvr_status(port_name, app_status_port_tbl, state_port_tbl, flag):
|
||||
|
||||
fvs = swsscommon.FieldValuePairs([("xcvr_status", xcvr_state_tbl[flag]["xcvr_app_status"])])
|
||||
tm = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||
state_fvs = swsscommon.FieldValuePairs([("xcvr_status", xcvr_state_tbl[flag]["xcvr_state"]), ("xcvr_time", tm)])
|
||||
|
||||
state_port_tbl.set(port_name, state_fvs)
|
||||
|
||||
app_status_port_tbl.set(port_name, fvs)
|
||||
|
||||
helper_logger.log_notice("Port {} xcvr_app_status change to {}".format(port_name, xcvr_state_tbl[flag]["xcvr_app_status"]))
|
||||
return True
|
||||
|
||||
|
||||
def main():
|
||||
helper_logger.log_notice("Start port_notify")
|
||||
# Connect to APP_DB and create transceiver dom info table
|
||||
appl_db = daemon_base.db_connect("APPL_DB")
|
||||
|
||||
app_status_port_tbl = swsscommon.ProducerStateTable(appl_db,
|
||||
swsscommon.APP_PORT_APP_STATUS_TABLE_NAME)
|
||||
|
||||
state_db = daemon_base.db_connect("STATE_DB")
|
||||
state_port_tbl = swsscommon.Table(state_db, STATE_PORT_TABLE)
|
||||
|
||||
# Wait for PortInitDone
|
||||
wait_for_port_init_done()
|
||||
|
||||
for port in range(RJ45_PORT_START, RJ45_PORT_END+1):
|
||||
#print("Ethernet{}".format(port))
|
||||
notify_port_xcvr_status("Ethernet{}".format(port), app_status_port_tbl, state_port_tbl, XCVR_STATE_READY)
|
||||
|
||||
helper_logger.log_notice("End port_notify")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
8
platform/broadcom/sonic-platform-modules-dell/n3248te/scripts/sensors
Executable file
8
platform/broadcom/sonic-platform-modules-dell/n3248te/scripts/sensors
Executable 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
|
1
platform/broadcom/sonic-platform-modules-dell/n3248te/setup.py
Symbolic link
1
platform/broadcom/sonic-platform-modules-dell/n3248te/setup.py
Symbolic link
@ -0,0 +1 @@
|
||||
../s6100/setup.py
|
@ -0,0 +1,8 @@
|
||||
"""
|
||||
Module sonic_platform provides the platform dependent population of
|
||||
platform.py, chassis.py, component.py, sfp.py, thermal.py, psu.py,
|
||||
fan.py and watchdog.py
|
||||
"""
|
||||
__all__ = ["platform", "chassis", "sfp", "eeprom", "component", "thermal", "psu", "fan", "fan_drawer", "watchdog"]
|
||||
from sonic_platform import *
|
||||
|
@ -0,0 +1,350 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DELLEMC N3248TE
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
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
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
MAX_N3248TE_FANTRAY = 3
|
||||
MAX_N3248TE_FAN = 1
|
||||
MAX_N3248TE_PSU = 2
|
||||
MAX_N3248TE_THERMAL = 5
|
||||
MAX_N3248TE_COMPONENT = 3 # BIOS, CPU CPLD and SYS CPLD
|
||||
|
||||
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
|
||||
"""
|
||||
CPLD_DIR = '/sys/devices/platform/dell-n3248te-cpld.0/'
|
||||
|
||||
_global_port_pres_dict = {}
|
||||
|
||||
_sfpp_port_to_i2c_mapping = {
|
||||
49: 20,
|
||||
50: 21,
|
||||
51: 22,
|
||||
52: 23,
|
||||
53: 24,
|
||||
54: 25,
|
||||
}
|
||||
|
||||
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 = 54
|
||||
self.PORTS_IN_BLOCK = (self.PORT_END + 1)
|
||||
self.SFP_PORT_START = 49
|
||||
self._sfp_port = range(self.SFP_PORT_START, self.PORTS_IN_BLOCK)
|
||||
eeprom_base = "/sys/class/i2c-adapter/i2c-{0}/{0}-0050/eeprom"
|
||||
for index in range(self.PORT_START, self.PORTS_IN_BLOCK):
|
||||
eeprom_path = ''
|
||||
if index in self._sfp_port:
|
||||
eeprom_path = eeprom_base.format(self._sfpp_port_to_i2c_mapping[index])
|
||||
if(index < 53):
|
||||
port_type = 'SFP'
|
||||
else:
|
||||
port_type = 'QSFP'
|
||||
|
||||
sfp_node = Sfp(index, port_type, eeprom_path)
|
||||
self._sfp_list.append(sfp_node)
|
||||
|
||||
self._eeprom = Eeprom()
|
||||
self._watchdog = Watchdog()
|
||||
self._num_sfps = 54
|
||||
self._num_fans = MAX_N3248TE_FANTRAY * MAX_N3248TE_FAN
|
||||
self._fan_list = [Fan(i, j) for i in range(MAX_N3248TE_FANTRAY) \
|
||||
for j in range(MAX_N3248TE_FAN)]
|
||||
for k in range(MAX_N3248TE_FANTRAY):
|
||||
fandrawer = FanDrawer(k)
|
||||
self._fan_drawer_list.append(fandrawer)
|
||||
self._fan_list.extend(fandrawer._fan_list)
|
||||
|
||||
self._psu_list = [Psu(i) for i in range(MAX_N3248TE_PSU)]
|
||||
self._thermal_list = [Thermal(i) for i in range(MAX_N3248TE_THERMAL)]
|
||||
self._component_list = [Component(i) for i in range(MAX_N3248TE_COMPONENT)]
|
||||
for port_num in self._sfp_port:
|
||||
# sfp get uses zero-indexing, but port numbers start from 1
|
||||
presence = self.get_sfp(port_num-1).get_presence()
|
||||
self._global_port_pres_dict[port_num] = '1' if presence else '0'
|
||||
|
||||
self._watchdog = Watchdog()
|
||||
self.locator_led_reg = "locator_led"
|
||||
self.LOCATOR_LED_ON = "blink_blue"
|
||||
self.LOCATOR_LED_OFF = self.STATUS_LED_COLOR_OFF
|
||||
|
||||
def _get_cpld_register(self, reg_name):
|
||||
# On successful read, returns the value read from given
|
||||
# reg name and on failure rethrns 'ERR'
|
||||
cpld_reg_file = self.CPLD_DIR + '/' + reg_name
|
||||
try:
|
||||
rv = open(cpld_reg_file, 'r').read()
|
||||
except IOError : return 'ERR'
|
||||
return rv.strip('\r\n').lstrip(' ')
|
||||
|
||||
def _set_cpld_register(self, reg_name, value):
|
||||
# On successful write, returns the value will be written on
|
||||
# reg_name and on failure returns 'ERR'
|
||||
rv = 'ERR'
|
||||
cpld_reg_file = self.CPLD_DIR + '/' + reg_name
|
||||
|
||||
if (not os.path.isfile(cpld_reg_file)):
|
||||
#print "open error"
|
||||
return rv
|
||||
|
||||
try:
|
||||
with open(cpld_reg_file, 'w') as fd:
|
||||
rv = fd.write(str(value))
|
||||
except Exception:
|
||||
rv = 'ERR'
|
||||
|
||||
return rv
|
||||
|
||||
# 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
|
||||
"""
|
||||
port_dict = {}
|
||||
change_dict = {}
|
||||
change_dict['sfp'] = port_dict
|
||||
while True:
|
||||
for port_num in self._sfp_port:
|
||||
# sfp get uses zero-indexing, but port numbers start from 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
|
||||
|
||||
time.sleep(0.5)
|
||||
|
||||
|
||||
|
||||
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().decode()
|
||||
|
||||
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_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.
|
||||
"""
|
||||
|
||||
reset_reason = int(self._get_cpld_register('reboot_cause'), 16)
|
||||
|
||||
if (reset_reason & 0x02) :
|
||||
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Shutdown by CPU')
|
||||
elif (reset_reason & 0x04) :
|
||||
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Failed to boot from configured boot device")
|
||||
elif (reset_reason & 0x8) :
|
||||
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, "Booted from Backup BIOS")
|
||||
elif (reset_reason & 0x10) :
|
||||
return(ChassisBase.REBOOT_CAUSE_WATCHDOG, None)
|
||||
elif (reset_reason & 0x20):
|
||||
return(ChassisBase.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU)
|
||||
elif (reset_reason & 0x40) :
|
||||
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Warm Reset')
|
||||
elif (reset_reason & 0x80) :
|
||||
return (ChassisBase.REBOOT_CAUSE_NON_HARDWARE, 'Cold Reset')
|
||||
elif (reset_reason & 0x01) :
|
||||
return (ChassisBase.REBOOT_CAUSE_POWER_LOSS, None)
|
||||
|
||||
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_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
|
||||
|
||||
"""
|
||||
if color == self.LOCATOR_LED_ON or color == self.LOCATOR_LED_OFF:
|
||||
rv = self._set_cpld_register(self.locator_led_reg, color)
|
||||
if (rv != 'ERR'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def get_locator_led(self):
|
||||
"""
|
||||
Gets the state of the Chassis Locator LED
|
||||
|
||||
Returns:
|
||||
LOCATOR_LED_ON or LOCATOR_LED_OFF
|
||||
"""
|
||||
loc_led = self._get_cpld_register(self.locator_led_reg)
|
||||
if (loc_led != 'ERR'):
|
||||
# Actually driver returns the color code 'blink_blue'
|
||||
# Returning "blue_blink" to make it common to all platforms output
|
||||
if (loc_led == self.LOCATOR_LED_ON):
|
||||
self.LOCATOR_LED_ON = self.STATUS_LED_COLOR_BLUE_BLINK
|
||||
return self.LOCATOR_LED_ON
|
||||
else:
|
||||
return self.LOCATOR_LED_OFF
|
||||
else:
|
||||
return self.LOCATOR_LED_OFF
|
@ -0,0 +1,82 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DELLEMC N3248TE
|
||||
#
|
||||
# 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
|
||||
|
||||
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().decode()
|
||||
|
||||
def get_cpld_version(cpld):
|
||||
mjr_ver=subprocess.check_output('cat /sys/devices/platform/dell-n3248te-cpld.0/' + cpld + '_mjr_ver', shell=True).strip()[2:].decode()
|
||||
mnr_ver=subprocess.check_output('cat /sys/devices/platform/dell-n3248te-cpld.0/' + cpld + '_mnr_ver', shell=True).strip()[2:].decode()
|
||||
return (str(mjr_ver) + '.' + str(mnr_ver))
|
||||
|
||||
class Component(ComponentBase):
|
||||
"""DellEMC Platform-specific Component class"""
|
||||
|
||||
CHASSIS_COMPONENTS = [
|
||||
['BIOS',
|
||||
'Performs initialization of hardware components during booting',
|
||||
get_bios_version()
|
||||
],
|
||||
['CPU CPLD',
|
||||
'Used for managing the CPU power sequence and CPU states',
|
||||
get_cpld_version('cpu_cpld')
|
||||
],
|
||||
['SYS CPLD',
|
||||
'Used for managing FAN, PSU, SFP modules (1-48) SFP Plus modules (49-62)',
|
||||
get_cpld_version('sys_cpld')
|
||||
]
|
||||
]
|
||||
|
||||
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
|
@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DellEmc Z9332F
|
||||
#
|
||||
# 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
|
||||
import binascii
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Eeprom(eeprom_tlvinfo.TlvInfoDecoder):
|
||||
|
||||
def __init__(self):
|
||||
self.eeprom_path = None
|
||||
f = '/sys/class/i2c-adapter/i2c-2/2-0050/eeprom'
|
||||
if not os.path.exists(f):
|
||||
return
|
||||
self.eeprom_path = f
|
||||
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([binascii.b2a_hex(T) for T in t[2]])
|
||||
|
||||
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]
|
||||
|
||||
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]
|
||||
|
||||
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]
|
||||
|
||||
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]
|
||||
|
||||
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
|
||||
|
||||
|
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC Z9332F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Fans' information which are available in the platform.
|
||||
#
|
||||
########################################################################
|
||||
try:
|
||||
import os
|
||||
from sonic_platform_base.fan_base import FanBase
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
|
||||
class Fan(FanBase):
|
||||
"""DellEMC Platform-specific Fan class"""
|
||||
|
||||
def __init__(self, fantray_index=0, fan_index=0, psu_fan=False, dependency=None):
|
||||
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.presence_reg = "fan{}_prs".format(fantray_index)
|
||||
self.dir_reg = "fan{}_dir".format(fantray_index)
|
||||
self.rpm_file = "/sys/bus/i2c/devices/7-002c/fan{}_input".format(fantray_index+1)
|
||||
self.eeprom = "/sys/bus/i2c/devices/{}-0050/eeprom".format(15 + fantray_index)
|
||||
self.fantray_index = fantray_index
|
||||
else:
|
||||
self.presence_reg = "psu{}_prs".format(fantray_index)
|
||||
self.psu_index = fantray_index
|
||||
self.dependancy = dependency
|
||||
self.dir_reg = ""
|
||||
self.dps_hwmon = "/sys/bus/i2c/devices/{}-005e/hwmon/".format(fantray_index+10)
|
||||
self.eeprom = "/sys/bus/i2c/devices/{}-0056/eeprom".format(10 + fantray_index)
|
||||
self.max_speed = 0
|
||||
|
||||
def _get_cpld_register(self, reg_name):
|
||||
# On successful read, returns the value read from given
|
||||
# reg name and on failure rethrns 'ERR'
|
||||
cpld_dir = "/sys/devices/platform/dell-n3248te-cpld.0/"
|
||||
cpld_reg_file = cpld_dir + '/' + reg_name
|
||||
try:
|
||||
buf = open(cpld_reg_file, 'r').read()
|
||||
except (IOError, AttributeError):
|
||||
return 'ERR'
|
||||
return buf.strip('\r\n').lstrip(' ')
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
Returns:
|
||||
String: The name of the device
|
||||
"""
|
||||
if self.is_psu_fan:
|
||||
return "PSU{} Fan".format(self.psu_index)
|
||||
else:
|
||||
return "Fan{}".format(self.fantray_index+1)
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the FAN
|
||||
Returns:
|
||||
String: Part number of FAN
|
||||
"""
|
||||
try:
|
||||
val = open(self.eeprom, "rb").read()[13:19]
|
||||
except Exception:
|
||||
val = None
|
||||
return val.decode()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the FAN
|
||||
Returns:
|
||||
String: Serial number of FAN
|
||||
"""
|
||||
try:
|
||||
val = open(self.eeprom, "rb").read()[21:41]
|
||||
except Exception:
|
||||
val = None
|
||||
return val.decode()
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the FAN
|
||||
Returns:
|
||||
bool: True if fan is present, False if not
|
||||
"""
|
||||
|
||||
presence = self._get_cpld_register(self.presence_reg)
|
||||
if presence == 'ERR':
|
||||
return False
|
||||
if int(presence,0) == 1:
|
||||
return True
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the FAN
|
||||
Returns:
|
||||
bool: True if FAN is operating properly, False if not
|
||||
"""
|
||||
return True
|
||||
|
||||
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.
|
||||
"""
|
||||
if not self.is_psu_fan:
|
||||
val = self._get_cpld_register(self.dir_reg)
|
||||
direction = 'Exhaust' if val == 'F2B' else 'Intake'
|
||||
if direction == 'ERR':
|
||||
return None
|
||||
else:
|
||||
try:
|
||||
val = open(self.eeprom, "rb").read()[0xe1:0xe8]
|
||||
except Exception:
|
||||
return None
|
||||
direction = 'Exhaust' if val == 'FORWARD' else 'Intake'
|
||||
return direction
|
||||
|
||||
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 = 23500
|
||||
fan_speed = 0
|
||||
try:
|
||||
if not self.is_psu_fan:
|
||||
rpm_file = self.rpm_file
|
||||
else:
|
||||
dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0]
|
||||
rpm_file = dps_dir + '/' + 'fan1_input'
|
||||
fan_speed = int(open(rpm_file, "rb").read())
|
||||
except Exception:
|
||||
return None
|
||||
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
|
||||
try:
|
||||
if not self.is_psu_fan:
|
||||
rpm_file = self.rpm_file
|
||||
else:
|
||||
dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0]
|
||||
rpm_file = dps_dir + '/' + 'fan1_input'
|
||||
fan_speed = int(open(rpm_file, "rb").read())
|
||||
except Exception:
|
||||
return None
|
||||
return fan_speed
|
@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC N3248TE
|
||||
#
|
||||
# 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")
|
||||
|
||||
N3248TE_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(N3248TE_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)
|
@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
#
|
||||
# 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()
|
@ -0,0 +1,207 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC Z9332F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the PSUs' information which are available in the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
try:
|
||||
import os
|
||||
from sonic_platform_base.psu_base import PsuBase
|
||||
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"""
|
||||
|
||||
def __init__(self, psu_index):
|
||||
PsuBase.__init__(self)
|
||||
self.index = psu_index + 1 # PSU is 1-based in DellEMC platforms
|
||||
self.psu_presence_reg = "psu{}_prs".format(psu_index)
|
||||
self.psu_status = "psu{}_status".format(psu_index)
|
||||
self.eeprom = "/sys/bus/i2c/devices/{}-0056/eeprom".format(10+psu_index)
|
||||
self.psu_voltage_reg = 'in3_input'
|
||||
self.psu_current_reg = 'curr2_input'
|
||||
self.psu_power_reg = 'power2_input'
|
||||
self.dps_hwmon = "/sys/bus/i2c/devices/{}-005e/hwmon/".format(10 + psu_index)
|
||||
self.dps_hwmon_exist = os.path.exists(self.dps_hwmon)
|
||||
self._fan_list.append(Fan(fan_index=self.index, psu_fan=True, dependency=self))
|
||||
|
||||
def _get_cpld_register(self, reg_name):
|
||||
# On successful read, returns the value read from given
|
||||
# reg name and on failure rethrns 'ERR'
|
||||
cpld_dir = "/sys/devices/platform/dell-n3248te-cpld.0/"
|
||||
cpld_reg_file = cpld_dir + '/' + reg_name
|
||||
try:
|
||||
rv = open(cpld_reg_file, 'r').read()
|
||||
except IOError : return 'ERR'
|
||||
return rv.strip('\r\n').lstrip(' ')
|
||||
|
||||
def _get_dps_register(self, reg_name):
|
||||
try :
|
||||
dps_dir = self.dps_hwmon + '/' + os.listdir(self.dps_hwmon)[0]
|
||||
dps_reg_file = dps_dir + '/' + reg_name
|
||||
rv = open(dps_reg_file, 'r').read()
|
||||
except (IOError, OSError) : return 'ERR'
|
||||
return rv
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the device
|
||||
|
||||
Returns:
|
||||
string: The name of the device
|
||||
"""
|
||||
return "PSU{}".format(self.index)
|
||||
|
||||
def _reload_dps_module(self):
|
||||
try:
|
||||
del_cmd = "echo 0x56 > /sys/bus/i2c/devices/i2c-{}/delete_device".format(10 + self.index - 1)
|
||||
os.system(del_cmd)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
try:
|
||||
del_cmd = "echo 0x5e > /sys/bus/i2c/devices/i2c-{}/delete_device".format(10 + self.index - 1)
|
||||
os.system(del_cmd)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
try:
|
||||
ins_cmd = "echo '24c02 0x56' > /sys/bus/i2c/devices/i2c-{}/new_device".format(10 + self.index - 1)
|
||||
os.system(ins_cmd)
|
||||
ins_cmd = "echo 'dps460 0x5e' > /sys/bus/i2c/devices/i2c-{}/new_device".format(10 + self.index - 1)
|
||||
os.system(ins_cmd)
|
||||
except (IOError, OSError):
|
||||
pass
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the Power Supply Unit (PSU)
|
||||
|
||||
Returns:
|
||||
bool: True if PSU is present, False if not
|
||||
"""
|
||||
presence = self._get_cpld_register(self.psu_presence_reg).strip()
|
||||
if presence == 'ERR' : return False
|
||||
if not self.dps_hwmon_exist and int(presence, 0):
|
||||
self.dps_hwmon_exist = os.path.exists(self.dps_hwmon)
|
||||
if not self.dps_hwmon_exist:
|
||||
self._reload_dps_module()
|
||||
return int(presence, 0)
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the part number of the PSU
|
||||
|
||||
Returns:
|
||||
string: Part number of PSU
|
||||
"""
|
||||
try: val = open(self.eeprom, "rb").read()[0x50:0x62]
|
||||
except Exception:
|
||||
val = None
|
||||
return val.decode()
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the PSU
|
||||
|
||||
Returns:
|
||||
string: Serial number of PSU
|
||||
"""
|
||||
try: val = open(self.eeprom, "rb").read()[0xc4:0xd9]
|
||||
except Exception:
|
||||
val = None
|
||||
return val.decode()
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the PSU
|
||||
|
||||
Returns:
|
||||
bool: True if PSU is operating properly, False if not
|
||||
"""
|
||||
status = self._get_cpld_register(self.psu_status).strip()
|
||||
if status == 'ERR' : return False
|
||||
return int(status, 0)
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves current PSU voltage output
|
||||
|
||||
Returns:
|
||||
A float number, the output voltage in volts,
|
||||
e.g. 12.1
|
||||
"""
|
||||
volt_reading = self._get_dps_register(self.psu_voltage_reg)
|
||||
try:
|
||||
voltage = int(volt_reading)/1000
|
||||
except Exception:
|
||||
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
|
||||
"""
|
||||
curr_reading = self._get_dps_register(self.psu_current_reg)
|
||||
try:
|
||||
current = int(curr_reading)/1000
|
||||
except Exception:
|
||||
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
|
||||
"""
|
||||
power_reading = self._get_dps_register(self.psu_power_reg)
|
||||
try:
|
||||
power = int(power_reading)/1000
|
||||
except Exception:
|
||||
return None
|
||||
return "{:.1f}".format(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.
|
||||
"""
|
||||
power_good = self._get_cpld_register(self.psu_status).strip()
|
||||
if power_good == 'ERR' : return False
|
||||
return int(power_good, 0)
|
||||
|
||||
def get_mfr_id(self):
|
||||
"""
|
||||
Retrives the Manufacturer Id of PSU
|
||||
|
||||
Returns:
|
||||
A string, the manunfacturer id.
|
||||
"""
|
||||
return 'DELTA'
|
||||
|
||||
def get_type(self):
|
||||
"""
|
||||
Retrives the Power Type of PSU
|
||||
|
||||
Returns :
|
||||
A string, PSU power type
|
||||
"""
|
||||
try: val = open(self.eeprom, "rb").read()[0xe8:0xea]
|
||||
except Exception:
|
||||
return None
|
||||
return val
|
@ -0,0 +1,783 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
#############################################################################
|
||||
# DELLEMC S5248F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the platform information
|
||||
#
|
||||
#############################################################################
|
||||
|
||||
try:
|
||||
import os
|
||||
import struct
|
||||
import mmap
|
||||
from sonic_platform_base.sfp_base import SfpBase
|
||||
from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId
|
||||
from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom
|
||||
from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId
|
||||
from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom
|
||||
|
||||
except ImportError as e:
|
||||
raise ImportError(str(e) + "- required module not found")
|
||||
|
||||
PAGE_OFFSET = 0
|
||||
KEY_OFFSET = 1
|
||||
KEY_WIDTH = 2
|
||||
FUNC_NAME = 3
|
||||
|
||||
QSFP_INFO_OFFSET = 128
|
||||
QSFP_DOM_OFFSET = 0
|
||||
QSFP_DOM_OFFSET1 = 384
|
||||
|
||||
SFP_PORT_START = 49
|
||||
SFP_PORT_END = 54
|
||||
|
||||
SFP_INFO_OFFSET = 0
|
||||
SFP_DOM_OFFSET = 256
|
||||
|
||||
SFP_STATUS_CONTROL_OFFSET = 110
|
||||
SFP_STATUS_CONTROL_WIDTH = 7
|
||||
SFP_TX_DISABLE_HARD_BIT = 7
|
||||
SFP_TX_DISABLE_SOFT_BIT = 6
|
||||
|
||||
qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', 'Length OM2(m)',
|
||||
'Length OM1(m)', 'Length Cable Assembly(m)')
|
||||
|
||||
qsfp_compliance_code_tup = (
|
||||
'10/40G Ethernet Compliance Code',
|
||||
'SONET Compliance codes',
|
||||
'SAS/SATA compliance codes',
|
||||
'Gigabit Ethernet Compliant codes',
|
||||
'Fibre Channel link length/Transmitter Technology',
|
||||
'Fibre Channel transmission media',
|
||||
'Fibre Channel Speed')
|
||||
|
||||
sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)',
|
||||
'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)',
|
||||
'LengthOM3(UnitsOf10m)', 'LengthCable(UnitsOfm)')
|
||||
|
||||
sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode',
|
||||
'ESCONComplianceCodes', 'SONETComplianceCodes',
|
||||
'EthernetComplianceCodes', 'FibreChannelLinkLength',
|
||||
'FibreChannelTechnology', 'SFP+CableTechnology',
|
||||
'FibreChannelTransmissionMedia', 'FibreChannelSpeed')
|
||||
|
||||
info_dict_keys = ['type', 'hardware_rev', 'serial',
|
||||
'manufacturer', 'model', 'connector',
|
||||
'encoding', 'ext_identifier', 'ext_rateselect_compliance',
|
||||
'cable_type', 'cable_length', 'nominal_bit_rate',
|
||||
'specification_compliance', 'type_abbrv_name','vendor_date', 'vendor_oui']
|
||||
|
||||
dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status',
|
||||
'power_lpmode', 'tx_disable', 'tx_disable_channel',
|
||||
'temperature', 'voltage', 'rx1power',
|
||||
'rx2power', 'rx3power', 'rx4power',
|
||||
'tx1bias', 'tx2bias', 'tx3bias',
|
||||
'tx4bias', 'tx1power', 'tx2power',
|
||||
'tx3power', 'tx4power']
|
||||
|
||||
threshold_dict_keys = ['temphighalarm', 'temphighwarning',
|
||||
'templowalarm', 'templowwarning',
|
||||
'vcchighalarm', 'vcchighwarning',
|
||||
'vcclowalarm', 'vcclowwarning',
|
||||
'rxpowerhighalarm', 'rxpowerhighwarning',
|
||||
'rxpowerlowalarm', 'rxpowerlowwarning',
|
||||
'txpowerhighalarm', 'txpowerhighwarning',
|
||||
'txpowerlowalarm', 'txpowerlowwarning',
|
||||
'txbiashighalarm', 'txbiashighwarning',
|
||||
'txbiaslowalarm', 'txbiaslowwarning']
|
||||
|
||||
sff8436_parser = {
|
||||
'reset_status': [QSFP_DOM_OFFSET, 2, 1, 'parse_dom_status_indicator'],
|
||||
'rx_los': [QSFP_DOM_OFFSET, 3, 1, 'parse_dom_tx_rx_los'],
|
||||
'tx_fault': [QSFP_DOM_OFFSET, 4, 1, 'parse_dom_tx_fault'],
|
||||
'tx_disable': [QSFP_DOM_OFFSET, 86, 1, 'parse_dom_tx_disable'],
|
||||
'power_lpmode': [QSFP_DOM_OFFSET, 93, 1, 'parse_dom_power_control'],
|
||||
'power_override': [QSFP_DOM_OFFSET, 93, 1, 'parse_dom_power_control'],
|
||||
'Temperature': [QSFP_DOM_OFFSET, 22, 2, 'parse_temperature'],
|
||||
'Voltage': [QSFP_DOM_OFFSET, 26, 2, 'parse_voltage'],
|
||||
'ChannelMonitor': [QSFP_DOM_OFFSET, 34, 16, 'parse_channel_monitor_params'],
|
||||
'ChannelMonitor_TxPower':
|
||||
[QSFP_DOM_OFFSET, 34, 24, 'parse_channel_monitor_params_with_tx_power'],
|
||||
|
||||
'cable_type': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
|
||||
'cable_length': [QSFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
|
||||
'connector': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'type': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'encoding': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'ext_identifier': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'ext_rateselect_compliance':
|
||||
[QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'nominal_bit_rate': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'specification_compliance':
|
||||
[QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'type_abbrv_name': [QSFP_INFO_OFFSET, 0, 20, 'parse_sfp_info_bulk'],
|
||||
'manufacturer': [QSFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'],
|
||||
'vendor_oui': [QSFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'],
|
||||
'model': [QSFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'],
|
||||
'hardware_rev': [QSFP_INFO_OFFSET, 56, 2, 'parse_vendor_rev'],
|
||||
'serial': [QSFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'],
|
||||
'vendor_date': [QSFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'],
|
||||
'dom_capability': [QSFP_INFO_OFFSET, 92, 1, 'parse_qsfp_dom_capability'],
|
||||
'dom_rev': [QSFP_DOM_OFFSET, 1, 1, 'parse_sfp_dom_rev'],
|
||||
'ModuleThreshold': [QSFP_DOM_OFFSET1, 128, 24, 'parse_module_threshold_values'],
|
||||
'ChannelThreshold': [QSFP_DOM_OFFSET1, 176, 16, 'parse_channel_threshold_values'],
|
||||
}
|
||||
|
||||
sff8472_parser = {
|
||||
'Temperature': [SFP_DOM_OFFSET, 96, 2, 'parse_temperature'],
|
||||
'Voltage': [SFP_DOM_OFFSET, 98, 2, 'parse_voltage'],
|
||||
'ChannelMonitor': [SFP_DOM_OFFSET, 100, 6, 'parse_channel_monitor_params'],
|
||||
|
||||
'cable_type': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
|
||||
'cable_length': [SFP_INFO_OFFSET, -1, -1, 'parse_sfp_info_bulk'],
|
||||
'connector': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'type': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'encoding': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'ext_identifier': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'ext_rateselect_compliance':
|
||||
[SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'nominal_bit_rate': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'specification_compliance':
|
||||
[SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'type_abbrv_name': [SFP_INFO_OFFSET, 0, 21, 'parse_sfp_info_bulk'],
|
||||
'manufacturer': [SFP_INFO_OFFSET, 20, 16, 'parse_vendor_name'],
|
||||
'vendor_oui': [SFP_INFO_OFFSET, 37, 3, 'parse_vendor_oui'],
|
||||
'model': [SFP_INFO_OFFSET, 40, 16, 'parse_vendor_pn'],
|
||||
'hardware_rev': [SFP_INFO_OFFSET, 56, 4, 'parse_vendor_rev'],
|
||||
'serial': [SFP_INFO_OFFSET, 68, 16, 'parse_vendor_sn'],
|
||||
'vendor_date': [SFP_INFO_OFFSET, 84, 8, 'parse_vendor_date'],
|
||||
'ModuleThreshold': [SFP_DOM_OFFSET, 0, 56, 'parse_alarm_warning_threshold'],
|
||||
}
|
||||
|
||||
|
||||
class Sfp(SfpBase):
|
||||
"""
|
||||
DELLEMC Platform-specific Sfp class
|
||||
"""
|
||||
|
||||
def __init__(self, index, sfp_type, eeprom_path):
|
||||
SfpBase.__init__(self)
|
||||
self.sfp_type = sfp_type
|
||||
self.index = index
|
||||
self.eeprom_path = eeprom_path
|
||||
self.qsfpInfo = sff8436InterfaceId()
|
||||
self.qsfpDomInfo = sff8436Dom()
|
||||
self.sfpInfo = sff8472InterfaceId()
|
||||
self.sfpDomInfo = sff8472Dom(None,1)
|
||||
|
||||
def get_eeprom_sysfs_path(self):
|
||||
return self.eeprom_path
|
||||
|
||||
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 = os.open(resource, os.O_RDWR)
|
||||
mm = mmap.mmap(fd, 0)
|
||||
val = self.pci_mem_write(mm, offset, val)
|
||||
mm.close()
|
||||
os.close(fd)
|
||||
return val
|
||||
|
||||
def pci_get_value(self, resource, offset):
|
||||
fd = os.open(resource, os.O_RDWR)
|
||||
mm = mmap.mmap(fd, 0)
|
||||
val = self.pci_mem_read(mm, offset)
|
||||
mm.close()
|
||||
os.close(fd)
|
||||
return val
|
||||
|
||||
def _read_eeprom_bytes(self, eeprom_path, offset, num_bytes):
|
||||
eeprom_raw = []
|
||||
try:
|
||||
eeprom = open(eeprom_path, mode="rb", buffering=0)
|
||||
except IOError:
|
||||
return None
|
||||
|
||||
for i in range(0, num_bytes):
|
||||
eeprom_raw.append("0x00")
|
||||
|
||||
try:
|
||||
eeprom.seek(offset)
|
||||
raw = eeprom.read(num_bytes)
|
||||
except IOError:
|
||||
eeprom.close()
|
||||
return None
|
||||
|
||||
raw = bytearray(raw)
|
||||
|
||||
try:
|
||||
for n in range(0, num_bytes):
|
||||
eeprom_raw[n] = hex((raw[n]))[2:].zfill(2)
|
||||
except BaseException:
|
||||
eeprom.close()
|
||||
return None
|
||||
|
||||
eeprom.close()
|
||||
return eeprom_raw
|
||||
|
||||
def _get_eeprom_data(self, eeprom_key):
|
||||
eeprom_data = None
|
||||
page_offset = None
|
||||
|
||||
if(self.sfp_type == 'QSFP'):
|
||||
page_offset = sff8436_parser[eeprom_key][PAGE_OFFSET]
|
||||
eeprom_data_raw = self._read_eeprom_bytes(
|
||||
self.eeprom_path,
|
||||
(sff8436_parser[eeprom_key][PAGE_OFFSET] +
|
||||
sff8436_parser[eeprom_key][KEY_OFFSET]),
|
||||
sff8436_parser[eeprom_key][KEY_WIDTH])
|
||||
if (eeprom_data_raw is not None):
|
||||
# Offset 128 is used to retrieve sff8436InterfaceId Info
|
||||
# Offset 0 is used to retrieve sff8436Dom Info
|
||||
if (page_offset == 128):
|
||||
if ( self.qsfpInfo is None):
|
||||
return None
|
||||
eeprom_data = getattr(
|
||||
self.qsfpInfo, sff8436_parser[eeprom_key][FUNC_NAME])(
|
||||
eeprom_data_raw, 0)
|
||||
else:
|
||||
if ( self.qsfpDomInfo is None):
|
||||
return None
|
||||
eeprom_data = getattr(
|
||||
self.qsfpDomInfo, sff8436_parser[eeprom_key][FUNC_NAME])(
|
||||
eeprom_data_raw, 0)
|
||||
else:
|
||||
page_offset = sff8472_parser[eeprom_key][PAGE_OFFSET]
|
||||
eeprom_data_raw = self._read_eeprom_bytes(
|
||||
self.eeprom_path,
|
||||
(sff8472_parser[eeprom_key][PAGE_OFFSET] +
|
||||
sff8472_parser[eeprom_key][KEY_OFFSET]),
|
||||
sff8472_parser[eeprom_key][KEY_WIDTH])
|
||||
if (eeprom_data_raw is not None):
|
||||
# Offset 0 is used to retrieve sff8472InterfaceId Info
|
||||
# Offset 256 is used to retrieve sff8472Dom Info
|
||||
if (page_offset == 0):
|
||||
if ( self.sfpInfo is None):
|
||||
return None
|
||||
eeprom_data = getattr(
|
||||
self.sfpInfo, sff8472_parser[eeprom_key][FUNC_NAME])(
|
||||
eeprom_data_raw, 0)
|
||||
else:
|
||||
if ( self.sfpDomInfo is None):
|
||||
return None
|
||||
eeprom_data = getattr(
|
||||
self.sfpDomInfo, sff8472_parser[eeprom_key][FUNC_NAME])(
|
||||
eeprom_data_raw, 0)
|
||||
|
||||
return eeprom_data
|
||||
|
||||
def get_transceiver_info(self):
|
||||
"""
|
||||
Retrieves transceiver info of this SFP
|
||||
"""
|
||||
transceiver_info_dict = {}
|
||||
compliance_code_dict = {}
|
||||
transceiver_info_dict = dict.fromkeys(info_dict_keys, 'N/A')
|
||||
# BaseInformation
|
||||
try:
|
||||
iface_data = self._get_eeprom_data('type')
|
||||
connector = iface_data['data']['Connector']['value']
|
||||
encoding = iface_data['data']['EncodingCodes']['value']
|
||||
ext_id = iface_data['data']['Extended Identifier']['value']
|
||||
rate_identifier = iface_data['data']['RateIdentifier']['value']
|
||||
identifier = iface_data['data']['type']['value']
|
||||
type_abbrv_name=iface_data['data']['type_abbrv_name']['value']
|
||||
if(self.sfp_type == 'QSFP'):
|
||||
bit_rate = str(
|
||||
iface_data['data']['Nominal Bit Rate(100Mbs)']['value'])
|
||||
for key in qsfp_compliance_code_tup:
|
||||
if key in iface_data['data']['Specification compliance']['value']:
|
||||
compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value']
|
||||
for key in qsfp_cable_length_tup:
|
||||
if key in iface_data['data']:
|
||||
cable_type = key
|
||||
cable_length = str(iface_data['data'][key]['value'])
|
||||
else:
|
||||
bit_rate = str(
|
||||
iface_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value'])
|
||||
for key in sfp_compliance_code_tup:
|
||||
if key in iface_data['data']['Specification compliance']['value']:
|
||||
compliance_code_dict[key] = iface_data['data']['Specification compliance']['value'][key]['value']
|
||||
for key in sfp_cable_length_tup:
|
||||
if key in iface_data['data']:
|
||||
cable_type = key
|
||||
cable_length = str(iface_data['data'][key]['value'])
|
||||
|
||||
transceiver_info_dict['type_abbrv_name']=type_abbrv_name
|
||||
transceiver_info_dict['type'] = identifier
|
||||
transceiver_info_dict['connector'] = connector
|
||||
transceiver_info_dict['encoding'] = encoding
|
||||
transceiver_info_dict['ext_identifier'] = ext_id
|
||||
transceiver_info_dict['ext_rateselect_compliance'] = rate_identifier
|
||||
transceiver_info_dict['cable_type'] = cable_type
|
||||
transceiver_info_dict['cable_length'] = cable_length
|
||||
transceiver_info_dict['nominal_bit_rate'] = bit_rate
|
||||
transceiver_info_dict['specification_compliance'] = str(compliance_code_dict)
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
# Vendor Date
|
||||
try:
|
||||
vendor_date_data = self._get_eeprom_data('vendor_date')
|
||||
vendor_date = vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']
|
||||
transceiver_info_dict['vendor_date'] = vendor_date
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
# Vendor Name
|
||||
try:
|
||||
vendor_name_data = self._get_eeprom_data('manufacturer')
|
||||
vendor_name = vendor_name_data['data']['Vendor Name']['value']
|
||||
transceiver_info_dict['manufacturer'] = vendor_name
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
# Vendor OUI
|
||||
try:
|
||||
vendor_oui_data = self._get_eeprom_data('vendor_oui')
|
||||
vendor_oui = vendor_oui_data['data']['Vendor OUI']['value']
|
||||
transceiver_info_dict['vendor_oui'] = vendor_oui
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
# Vendor PN
|
||||
try:
|
||||
vendor_pn_data = self._get_eeprom_data('model')
|
||||
vendor_pn = vendor_pn_data['data']['Vendor PN']['value']
|
||||
transceiver_info_dict['model'] = vendor_pn
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
# Vendor Revision
|
||||
try:
|
||||
vendor_rev_data = self._get_eeprom_data('hardware_rev')
|
||||
vendor_rev = vendor_rev_data['data']['Vendor Rev']['value']
|
||||
transceiver_info_dict['hardware_rev'] = vendor_rev
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
# Vendor Serial Number
|
||||
try:
|
||||
vendor_sn_data = self._get_eeprom_data('serial')
|
||||
vendor_sn = vendor_sn_data['data']['Vendor SN']['value']
|
||||
transceiver_info_dict['serial'] = vendor_sn
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
return transceiver_info_dict
|
||||
|
||||
def get_transceiver_threshold_info(self):
|
||||
"""
|
||||
Retrieves transceiver threshold info of this SFP
|
||||
"""
|
||||
transceiver_dom_threshold_dict = {}
|
||||
transceiver_dom_threshold_dict = dict.fromkeys(
|
||||
threshold_dict_keys, 'N/A')
|
||||
|
||||
try:
|
||||
# Module Threshold
|
||||
module_threshold_data = self._get_eeprom_data('ModuleThreshold')
|
||||
if (self.sfp_type == 'QSFP'):
|
||||
transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['data']['TempHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['data']['TempHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['data']['TempLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['data']['TempLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['data']['VccHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['data']['VccHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['data']['VccLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['data']['VccLowWarning']['value']
|
||||
else: #SFP
|
||||
transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['data']['TempHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['data']['TempLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['data']['TempHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['data']['TempLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['data']['VoltageHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['data']['VoltageLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['data']['VoltageHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['data']['VoltageLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['txbiashighalarm'] = module_threshold_data['data']['BiasHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txbiaslowalarm'] = module_threshold_data['data']['BiasLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txbiashighwarning'] = module_threshold_data['data']['BiasHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['txbiaslowwarning'] = module_threshold_data['data']['BiasLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['txpowerhighalarm'] = module_threshold_data['data']['TXPowerHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txpowerlowalarm'] = module_threshold_data['data']['TXPowerLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txpowerhighwarning'] = module_threshold_data['data']['TXPowerHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['txpowerlowwarning'] = module_threshold_data['data']['TXPowerLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerhighalarm'] = module_threshold_data['data']['RXPowerHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerlowalarm'] = module_threshold_data['data']['RXPowerLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerhighwarning'] = module_threshold_data['data']['RXPowerHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerlowwarning'] = module_threshold_data['data']['RXPowerLowWarning']['value']
|
||||
except (ValueError, TypeError) : pass
|
||||
|
||||
try:
|
||||
if (self.sfp_type == 'QSFP'):
|
||||
channel_threshold_data = self._get_eeprom_data('ChannelThreshold')
|
||||
transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['data']['RxPowerHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['data']['RxPowerHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['data']['RxPowerLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['data']['RxPowerLowWarning']['value']
|
||||
transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['data']['TxBiasHighAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['data']['TxBiasHighWarning']['value']
|
||||
transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['data']['TxBiasLowAlarm']['value']
|
||||
transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['data']['TxBiasLowWarning']['value']
|
||||
|
||||
except (ValueError, TypeError) : pass
|
||||
return transceiver_dom_threshold_dict
|
||||
|
||||
def get_transceiver_bulk_status(self):
|
||||
"""
|
||||
Retrieves transceiver bulk status of this SFP
|
||||
"""
|
||||
tx_bias_list = []
|
||||
rx_power_list = []
|
||||
transceiver_dom_dict = {}
|
||||
transceiver_dom_dict = dict.fromkeys(dom_dict_keys, 'N/A')
|
||||
|
||||
# RxLos
|
||||
rx_los = self.get_rx_los()
|
||||
|
||||
# TxFault
|
||||
tx_fault = self.get_tx_fault()
|
||||
|
||||
# ResetStatus
|
||||
reset_state = self.get_reset_status()
|
||||
|
||||
# LowPower Mode
|
||||
lp_mode = self.get_lpmode()
|
||||
|
||||
# TxDisable
|
||||
tx_disable = self.get_tx_disable()
|
||||
|
||||
# TxDisable Channel
|
||||
tx_disable_channel = self.get_tx_disable_channel()
|
||||
|
||||
# Temperature
|
||||
temperature = self.get_temperature()
|
||||
|
||||
# Voltage
|
||||
voltage = self.get_voltage()
|
||||
|
||||
# Channel Monitor
|
||||
tx_power_list = self.get_tx_power()
|
||||
|
||||
# tx bias
|
||||
tx_bias_list = self.get_tx_bias()
|
||||
|
||||
# rx power
|
||||
rx_power_list = self.get_rx_power()
|
||||
|
||||
if tx_bias_list is not None:
|
||||
transceiver_dom_dict['tx1bias'] = tx_bias_list[0]
|
||||
transceiver_dom_dict['tx2bias'] = tx_bias_list[1]
|
||||
transceiver_dom_dict['tx3bias'] = tx_bias_list[2]
|
||||
transceiver_dom_dict['tx4bias'] = tx_bias_list[3]
|
||||
|
||||
if rx_power_list is not None:
|
||||
transceiver_dom_dict['rx1power'] = rx_power_list[0]
|
||||
transceiver_dom_dict['rx2power'] = rx_power_list[1]
|
||||
transceiver_dom_dict['rx3power'] = rx_power_list[2]
|
||||
transceiver_dom_dict['rx4power'] = rx_power_list[3]
|
||||
|
||||
if tx_power_list is not None:
|
||||
transceiver_dom_dict['tx1power'] = tx_power_list[0]
|
||||
transceiver_dom_dict['tx2power'] = tx_power_list[1]
|
||||
transceiver_dom_dict['tx3power'] = tx_power_list[2]
|
||||
transceiver_dom_dict['tx4power'] = tx_power_list[3]
|
||||
|
||||
transceiver_dom_dict['rx_los'] = rx_los
|
||||
transceiver_dom_dict['tx_fault'] = tx_fault
|
||||
transceiver_dom_dict['reset_status'] = reset_state
|
||||
transceiver_dom_dict['power_lpmode'] = lp_mode
|
||||
transceiver_dom_dict['tx_disable'] = tx_disable
|
||||
transceiver_dom_dict['tx_disable_channel'] = tx_disable_channel
|
||||
transceiver_dom_dict['temperature'] = temperature
|
||||
transceiver_dom_dict['voltage'] = voltage
|
||||
|
||||
return transceiver_dom_dict
|
||||
|
||||
def get_name(self):
|
||||
"""
|
||||
Retrieves the name of the sfp
|
||||
Returns : QSFP or QSFP+ or QSFP28
|
||||
"""
|
||||
try:
|
||||
iface_data = self._get_eeprom_data('type')
|
||||
identifier = iface_data['data']['type']['value']
|
||||
except (TypeError, ValueError):
|
||||
return 'N/A'
|
||||
return identifier
|
||||
|
||||
def _get_cpld_register(self, reg):
|
||||
reg_file = '/sys/devices/platform/dell-n3248te-cpld.0/' + reg
|
||||
try:
|
||||
rv = open(reg_file, 'r').read()
|
||||
except IOError : return 'ERR'
|
||||
return rv.strip('\r\n').lstrip(' ')
|
||||
|
||||
def get_presence(self):
|
||||
"""
|
||||
Retrieves the presence of the sfp
|
||||
Returns : True if sfp is present and false if it is absent
|
||||
"""
|
||||
# Check for invalid port_num
|
||||
presence = False
|
||||
if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return presence
|
||||
bit_mask = 1 << (self.index - SFP_PORT_START)
|
||||
try:
|
||||
sfp_mod_prs = self._get_cpld_register('sfp_modprs')
|
||||
if sfp_mod_prs == 'ERR' : return presence
|
||||
presence = ((int(sfp_mod_prs, 16) & bit_mask) == 0)
|
||||
except Exception:
|
||||
pass
|
||||
return presence
|
||||
|
||||
def get_model(self):
|
||||
"""
|
||||
Retrieves the model number (or part number) of the sfp
|
||||
"""
|
||||
try:
|
||||
vendor_pn_data = self._get_eeprom_data('model')
|
||||
vendor_pn = vendor_pn_data['data']['Vendor PN']['value']
|
||||
except (TypeError, ValueError):
|
||||
return 'N/A'
|
||||
|
||||
return vendor_pn
|
||||
|
||||
def get_serial(self):
|
||||
"""
|
||||
Retrieves the serial number of the sfp
|
||||
"""
|
||||
try:
|
||||
vendor_sn_data = self._get_eeprom_data('serial')
|
||||
vendor_sn = vendor_sn_data['data']['Vendor SN']['value']
|
||||
except (TypeError, ValueError):
|
||||
return 'N/A'
|
||||
|
||||
return vendor_sn
|
||||
|
||||
def get_reset_status(self):
|
||||
"""
|
||||
Retrives the reset status of SFP
|
||||
"""
|
||||
reset_status = False
|
||||
return reset_status
|
||||
|
||||
def get_rx_los(self):
|
||||
"""
|
||||
Retrieves the RX LOS (lost-of-signal) status of SFP
|
||||
"""
|
||||
rx_los = False
|
||||
if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return rx_los
|
||||
bit_mask = 1 << (self.index - SFP_PORT_START)
|
||||
try:
|
||||
sfp_rxlos = self._get_cpld_register('sfp_rxlos')
|
||||
if sfp_rxlos == 'ERR' : return rx_los
|
||||
rx_los = ((int(sfp_rxlos, 16) & bit_mask) != 0)
|
||||
except Exception:
|
||||
pass
|
||||
return rx_los
|
||||
|
||||
def get_tx_fault(self):
|
||||
"""
|
||||
Retrieves the TX fault status of SFP
|
||||
"""
|
||||
tx_fault = False
|
||||
if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return tx_fault
|
||||
bit_mask = 1 << (self.index - SFP_PORT_START)
|
||||
try:
|
||||
sfp_txfault = self._get_cpld_register('sfp_txfault')
|
||||
if sfp_txfault == 'ERR' : return tx_fault
|
||||
tx_fault = ((int(sfp_txfault, 16) & bit_mask) != 0)
|
||||
except Exception:
|
||||
pass
|
||||
return tx_fault
|
||||
|
||||
def get_tx_disable(self):
|
||||
"""
|
||||
Retrieves the tx_disable status of this SFP
|
||||
"""
|
||||
tx_disable = False
|
||||
if not (self.index >= SFP_PORT_START and self.index <= SFP_PORT_END): return tx_disable
|
||||
bit_mask = 1 << (self.index - SFP_PORT_START)
|
||||
try:
|
||||
sfp_txdisable = self._get_cpld_register('sfp_txdis')
|
||||
if sfp_txdisable == 'ERR' : return tx_disable
|
||||
tx_disable = ((int(sfp_txdisable, 16) & bit_mask) != 0)
|
||||
except Exception:
|
||||
pass
|
||||
return tx_disable
|
||||
|
||||
def get_tx_disable_channel(self):
|
||||
"""
|
||||
Retrieves the TX disabled channels in this SFP
|
||||
"""
|
||||
tx_disable_channel = 0
|
||||
try:
|
||||
if (self.sfp_type == 'QSFP'):
|
||||
tx_disable_data = self._get_eeprom_data('tx_disable')
|
||||
for tx_disable_id in ('Tx1Disable', 'Tx2Disable', 'Tx3Disable', 'Tx4Disable'):
|
||||
tx_disable_channel <<= 1
|
||||
tx_disable_channel |= (tx_disable_data['data']['Tx1Disable']['value'] is 'On')
|
||||
except (TypeError, ValueError):
|
||||
return 'N/A'
|
||||
return tx_disable_channel
|
||||
|
||||
def get_lpmode(self):
|
||||
"""
|
||||
Retrieves the lpmode(low power mode) of this SFP
|
||||
"""
|
||||
lpmode_state = False
|
||||
return lpmode_state
|
||||
|
||||
def get_power_override(self):
|
||||
"""
|
||||
Retrieves the power-override status of this SFP
|
||||
"""
|
||||
power_override_state = False
|
||||
|
||||
try:
|
||||
if (self.sfp_type == 'QSFP'):
|
||||
power_override_data = self._get_eeprom_data('power_override')
|
||||
power_override = power_override_data['data']['PowerOverRide']['value']
|
||||
power_override_state = (power_override is 'On')
|
||||
except (TypeError, ValueError): pass
|
||||
return power_override_state
|
||||
|
||||
def get_temperature(self):
|
||||
"""
|
||||
Retrieves the temperature of this SFP
|
||||
"""
|
||||
try :
|
||||
temperature_data = self._get_eeprom_data('Temperature')
|
||||
temperature = temperature_data['data']['Temperature']['value']
|
||||
except (TypeError, ValueError):
|
||||
return 'N/A'
|
||||
return temperature
|
||||
|
||||
def get_voltage(self):
|
||||
"""
|
||||
Retrieves the supply voltage of this SFP
|
||||
"""
|
||||
try:
|
||||
voltage_data = self._get_eeprom_data('Voltage')
|
||||
voltage = voltage_data['data']['Vcc']['value']
|
||||
except (TypeError, ValueError):
|
||||
return 'N/A'
|
||||
return voltage
|
||||
|
||||
def get_tx_bias(self):
|
||||
"""
|
||||
Retrieves the TX bias current of this SFP
|
||||
"""
|
||||
tx_bias_list = []
|
||||
try:
|
||||
tx_bias_data = self._get_eeprom_data('ChannelMonitor')
|
||||
if (self.sfp_type == 'QSFP'):
|
||||
for tx_bias_id in ('TX1Bias', 'TX2Bias', 'TX3Bias', 'TX4Bias') :
|
||||
tx_bias = tx_bias_data['data'][tx_bias_id]['value']
|
||||
tx_bias_list.append(tx_bias)
|
||||
else:
|
||||
tx1_bias = tx_bias_data['data']['TXBias']['value']
|
||||
tx_bias_list = [tx1_bias, "N/A", "N/A", "N/A"]
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return tx_bias_list
|
||||
|
||||
def get_rx_power(self):
|
||||
"""
|
||||
Retrieves the received optical power for this SFP
|
||||
"""
|
||||
rx_power_list = []
|
||||
try:
|
||||
rx_power_data = self._get_eeprom_data('ChannelMonitor')
|
||||
if (self.sfp_type == 'QSFP'):
|
||||
for rx_power_id in ('RX1Power', 'RX2Power', 'RX3Power', 'RX4Power'):
|
||||
rx_power = rx_power_data['data'][rx_power_id]['value']
|
||||
rx_power_list.append(rx_power)
|
||||
else:
|
||||
rx1_pw = rx_power_data['data']['RXPower']['value']
|
||||
rx_power_list = [rx1_pw, "N/A", "N/A", "N/A"]
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return rx_power_list
|
||||
|
||||
def get_tx_power(self):
|
||||
"""
|
||||
Retrieves the TX power of this SFP
|
||||
"""
|
||||
tx_power_list = []
|
||||
try:
|
||||
if(self.sfp_type == 'QSFP'):
|
||||
# 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.
|
||||
qspf_dom_capability_data = self._get_eeprom_data('dom_capability')
|
||||
qsfp_dom_rev_data = self._get_eeprom_data('dom_rev')
|
||||
qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value']
|
||||
qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['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.
|
||||
if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')):
|
||||
return None
|
||||
channel_monitor_data = self._get_eeprom_data('ChannelMonitor_TxPower')
|
||||
for tx_power_id in ('TX1Power', 'TX2Power', 'TX3Power', 'TX4Power'):
|
||||
tx_pw = channel_monitor_data['data'][tx_power_id]['value']
|
||||
tx_power_list.append(tx_pw)
|
||||
else:
|
||||
channel_monitor_data = self._get_eeprom_data('ChannelMonitor')
|
||||
tx1_pw = channel_monitor_data['data']['TXPower']['value']
|
||||
tx_power_list = [tx1_pw, 'N/A', 'N/A', 'N/A']
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return tx_power_list
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Reset the SFP and returns all user settings to their default state
|
||||
"""
|
||||
return True
|
||||
|
||||
def set_lpmode(self, lpmode):
|
||||
"""
|
||||
Sets the lpmode(low power mode) of this SFP
|
||||
"""
|
||||
return True
|
||||
|
||||
def tx_disable(self, tx_disable):
|
||||
"""
|
||||
Disable SFP TX for all channels
|
||||
"""
|
||||
return False
|
||||
|
||||
def tx_disable_channel(self, channel, disable):
|
||||
"""
|
||||
Sets the tx_disable for specified SFP channels
|
||||
"""
|
||||
return False
|
||||
|
||||
def set_power_override(self, power_override, power_set):
|
||||
"""
|
||||
Sets SFP power level using power_override and power_set
|
||||
"""
|
||||
return False
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
Retrieves the operational status of the device
|
||||
"""
|
||||
reset = self.get_reset_status()
|
||||
return (not reset)
|
||||
|
||||
def get_max_port_power(self):
|
||||
"""
|
||||
Retrieves the maximumum power allowed on the port in watts
|
||||
"""
|
||||
return 2.5
|
@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
# DellEMC Z9332F
|
||||
#
|
||||
# Module contains an implementation of SONiC Platform Base API and
|
||||
# provides the Thermals' information which are available in the platform
|
||||
#
|
||||
########################################################################
|
||||
|
||||
|
||||
try:
|
||||
import os
|
||||
from sonic_platform_base.thermal_base import ThermalBase
|
||||
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 = [
|
||||
['Switch Near Temperature', '7-0049'],
|
||||
['Switch Rear Temperature', '7-004a'],
|
||||
['Front Panel PHY Temperature', '7-004b'],
|
||||
['Near Front Panel Temperature', '7-004c'],
|
||||
['Middle Fan Tray Temperature', '7-004f'],
|
||||
]
|
||||
|
||||
def __init__(self, thermal_index):
|
||||
ThermalBase.__init__(self)
|
||||
self.index = thermal_index + 1
|
||||
temp_hwmon = '/sys/bus/i2c/devices/' + self.SENSOR_MAPPING[thermal_index][1] + '/hwmon'
|
||||
self.temp_file = temp_hwmon + '/' + os.listdir(temp_hwmon)[0] + '/' + 'temp1_input'
|
||||
|
||||
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
|
||||
"""
|
||||
temperature = 0.0
|
||||
try :
|
||||
temperature = float(open(self.temp_file).read()) / 1000.0
|
||||
except Exception:
|
||||
pass
|
||||
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
|
||||
"""
|
||||
return 75.0
|
||||
|
||||
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
|
||||
"""
|
||||
return 0.0
|
||||
|
||||
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
|
@ -0,0 +1,210 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
########################################################################
|
||||
#
|
||||
# DELLEMC N3248TE
|
||||
#
|
||||
# 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
|
||||
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]
|
||||
|
||||
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')
|
||||
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
|
||||
|
||||
# Extracting 5th to 7th bits for WD timer values
|
||||
# 000 - 15 sec
|
||||
# 001 - 20 sec
|
||||
# 010 - 30 sec
|
||||
# 011 - 40 sec
|
||||
# 100 - 50 sec
|
||||
# 101 - 60 sec
|
||||
# 110 - 65 sec
|
||||
# 111 - 70 sec
|
||||
reg_val = self._get_reg_val()
|
||||
wd_timer_offset = (reg_val >> 4) & 0x7
|
||||
|
||||
if wd_timer_offset != timer_offset:
|
||||
# Setting 5th to 7th bits
|
||||
# value from timer_offset
|
||||
self.disarm()
|
||||
self._set_reg_val(reg_val | (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.
|
||||
|
||||
S5232 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
|
||||
|
@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Dell N3248TE Platform modules
|
||||
Before=pmon.service
|
||||
After=platform-init.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/n3248te_platform.sh init
|
||||
ExecStop=/usr/local/bin/n3248te_platform.sh deinit
|
||||
RemainAfterExit=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -286,3 +286,7 @@ lb_port_pipe1_int
|
||||
ing_origin_id_device_id_mask
|
||||
egr_origin_id_device_id_mask
|
||||
port_count_in_pb_stream
|
||||
ifa_enable
|
||||
port_gmii_mode
|
||||
phy_force_firmware_load
|
||||
phy_pcs_repeater
|
Loading…
Reference in New Issue
Block a user