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:
arunlk-dell 2021-09-24 09:17:32 +05:30 committed by GitHub
parent 27aef53054
commit 8325500560
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 6682 additions and 1 deletions

View File

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

View File

@ -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 %}

View File

@ -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 %}

View File

@ -0,0 +1,3 @@
{
"copp_rx_rate":15000
}

View File

@ -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"
}
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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 %}
}
}

View File

@ -0,0 +1 @@
SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/hx5-n3248te-48x1G+4x10G.config.bcm

View File

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

View File

@ -0,0 +1 @@
DellEMC-N3248TE t1

View File

@ -0,0 +1,13 @@
{
"FEATURE": {
"tam": {
"state": "disabled"
},
"telemetry": {
"state": "disabled"
},
"nat": {
"state": "disabled"
}
}
}

View File

@ -0,0 +1,3 @@
CONSOLE_PORT=0x3f8
CONSOLE_DEV=0
VAR_LOG_SIZE=512

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)'

View 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 ''

View 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, {}

View File

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

View 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"

View File

@ -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) \

View File

@ -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)))

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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#

View File

@ -5,7 +5,7 @@ export INSTALL_MOD_DIR:=extra
KVERSION ?= $(shell uname -r)
KERNEL_SRC := /lib/modules/$(KVERSION)
MOD_SRC_DIR:= $(shell pwd)
MODULE_DIRS:= s6000 z9100 s6100 z9264f s5232f s5248f z9332f s5296f
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); \

View File

@ -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

View File

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

View File

@ -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");

View File

@ -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 */

View 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

View File

@ -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

View File

@ -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

View 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:])

View File

@ -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()

View File

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

View File

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

View File

@ -0,0 +1,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 *

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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