diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers.json.j2 b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_def.j2 b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_def.j2 new file mode 100644 index 0000000000..740cfdf79e --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_def.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "4625920", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_t0.j2 b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..44fcf21887 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_t0.j2 @@ -0,0 +1,45 @@ +{%- 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": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_t1.j2 b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..5fe9cabcfd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "196608", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "33004032", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "12766208", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"33004032" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/l2/config b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/l2/config new file mode 100644 index 0000000000..b2d4a1e805 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/l2/config @@ -0,0 +1,3 @@ +l2_mem_entries=294912 +l3_mem_entries=16384 +l3_alpm_enable=0 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/l3/config b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/l3/config new file mode 100644 index 0000000000..fff0cf54b0 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/l3/config @@ -0,0 +1,5 @@ +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 +sai_tunnel_support=1 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/pg_profile_lookup.ini b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/pg_profile_lookup.ini new file mode 100644 index 0000000000..6d91d03ae6 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/pg_profile_lookup.ini @@ -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 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/platform-def.json b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/platform-def.json new file mode 100644 index 0000000000..ed3f9fcbf2 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/platform-def.json @@ -0,0 +1,32 @@ +{ + "fec-mode": { + "Ethernet0-127": { + "1": { + "10000": [ "none", "fc" ], + "25000": [ "none", "rs" ] + }, + "2": { + "20000": [ "none", "fc" ], + "50000": [ "none", "rs" ] + }, + "4": { + "40000": [ "none", "fc" ], + "100000": [ "none", "rs" ] + } + } + }, + "default-fec-mode": { + "Ethernet0-127": { + "4": { + "40000": "none", + "100000": "rs" + } + } + }, + "native-port-supported-speeds": { + "Ethernet0-127": { + "4": ["100000","40000"] + } + } +} + diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/port_config.ini b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/port_config.ini new file mode 100644 index 0000000000..14f4716d90 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed +Ethernet0 29,30,31,32 hundredGigE1 1 100000 +Ethernet4 33,34,35,36 hundredGigE2 2 100000 +Ethernet8 41,42,43,44 hundredGigE3 3 100000 +Ethernet12 45,46,47,48 hundredGigE4 4 100000 +Ethernet16 1,2,3,4 hundredGigE5 5 100000 +Ethernet20 5,6,7,8 hundredGigE6 6 100000 +Ethernet24 9,10,11,12 hundredGigE7 7 100000 +Ethernet28 13,14,15,16 hundredGigE8 8 100000 +Ethernet32 17,18,19,20 hundredGigE9 9 100000 +Ethernet36 21,22,23,24 hundredGigE10 10 100000 +Ethernet40 25,26,27,28 hundredGigE11 11 100000 +Ethernet44 37,38,39,40 hundredGigE12 12 100000 +Ethernet48 49,50,51,52 hundredGigE13 13 100000 +Ethernet52 53,54,55,56 hundredGigE14 14 100000 +Ethernet56 57,58,59,60 hundredGigE15 15 100000 +Ethernet60 61,62,63,64 hundredGigE16 16 100000 +Ethernet64 65,66,67,68 hundredGigE17 17 100000 +Ethernet68 69,70,71,72 hundredGigE18 18 100000 +Ethernet72 73,74,75,76 hundredGigE19 19 100000 +Ethernet76 77,78,79,80 hundredGigE20 20 100000 +Ethernet80 93,94,95,96 hundredGigE21 21 100000 +Ethernet84 101,102,103,104 hundredGigE22 22 100000 +Ethernet88 105,106,107,108 hundredGigE23 23 100000 +Ethernet92 109,110,111,112 hundredGigE24 24 100000 +Ethernet96 113,114,115,116 hundredGigE25 25 100000 +Ethernet100 117,118,119,120 hundredGigE26 26 100000 +Ethernet104 121,122,123,124 hundredGigE27 27 100000 +Ethernet108 125,126,127,128 hundredGigE28 28 100000 +Ethernet112 81,82,83,84 hundredGigE29 29 100000 +Ethernet116 85,86,87,88 hundredGigE30 30 100000 +Ethernet120 89,90,91,92 hundredGigE31 31 100000 +Ethernet124 97,98,99,100 hundredGigE32 32 100000 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/qos.json.j2 b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/qos.json.j2 new file mode 100644 index 0000000000..ee67c6e262 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config_t1.j2' %} diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/qos_config_t1.j2 b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/qos_config_t1.j2 new file mode 100644 index 0000000000..5fe5324a85 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/qos_config_t1.j2 @@ -0,0 +1,175 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "AZURE": { + "0" : "1", + "1" : "1", + "2" : "1", + "3" : "3", + "4" : "4", + "5" : "2", + "6" : "1", + "7" : "1", + "8" : "0", + "9" : "1", + "10": "1", + "11": "1", + "12": "1", + "13": "1", + "14": "1", + "15": "1", + "16": "1", + "17": "1", + "18": "1", + "19": "1", + "20": "1", + "21": "1", + "22": "1", + "23": "1", + "24": "1", + "25": "1", + "26": "1", + "27": "1", + "28": "1", + "29": "1", + "30": "1", + "31": "1", + "32": "1", + "33": "1", + "34": "1", + "35": "1", + "36": "1", + "37": "1", + "38": "1", + "39": "1", + "40": "1", + "41": "1", + "42": "1", + "43": "1", + "44": "1", + "45": "1", + "46": "5", + "47": "1", + "48": "6", + "49": "1", + "50": "1", + "51": "1", + "52": "1", + "53": "1", + "54": "1", + "55": "1", + "56": "1", + "57": "1", + "58": "1", + "59": "1", + "60": "1", + "61": "1", + "62": "1", + "63": "1" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "14" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "15" + } + }, +{% if asic_type in pfc_to_pg_map_supported_asics %} + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "3": "3", + "4": "4" + } + }, +{% endif %} + "PORT_QOS_MAP": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]", +{% if asic_type in pfc_to_pg_map_supported_asics %} + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]", +{% endif %} + "pfc_enable" : "3,4" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/sai.profile b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/sai.profile new file mode 100644 index 0000000000..5f6bb03915 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-ix7-bwde-32x100G.config.bcm +SAI_NUM_ECMP_MEMBERS=64 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/td3-ix7-bwde-32x100G.config.bcm b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/td3-ix7-bwde-32x100G.config.bcm new file mode 100644 index 0000000000..0f64dfeed2 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/Quanta-IX7-BWDE-32X/td3-ix7-bwde-32x100G.config.bcm @@ -0,0 +1,612 @@ +#polarity/lanemap is using TH2 style. +core_clock_frequency=1525 +dpp_clock_ratio=2:3 + +oversubscribe_mode=1 + +#RIOT Enable +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=32768 +l3_ecmp_levels=2 +riot_overlay_ecmp_resilient_hash_size=16384 + +pbmp_xport_xe=0x3ffffffffffffffffffffffffffffffffe + +port_flex_enable=1 +mem_cache_enable=0 + +l3_alpm_ipv6_128b_bkt_rsvd=1 +fpem_mem_entries=0 +ifp_inports_support_enable=1 +l2xmsg_mode=1 + +# Platform specfic +bcm_num_cos=10 +default_cpu_tx_queue=9 +bcm_stat_interval=2000000 +cdma_timeout_usec=3000000 +ipv6_lpm_128b_enable=0x1 +l3_max_ecmp_mode=1 +lpm_scaling_enable=0 +max_vp_lags=0 +miim_intr_enable=0 +module_64ports=1 +schan_intr_enable=0 +stable_size=0x5500000 +tdma_timeout_usec=3000000 +skip_L2_USER_ENTRY=0 +bcm_tunnel_term_compatible_mode=1 + +phy_an_c73=1 +# portmap settings + +portmap_1=1:100 +portmap_5=5:100 +portmap_9=9:100 +portmap_13=13:100 +portmap_17=17:100 +portmap_21=21:100 +portmap_25=25:100 +portmap_29=29:100 + +portmap_33=33:100 +portmap_37=37:100 +portmap_41=41:100 +portmap_45=45:100 +portmap_49=49:100 +portmap_53=53:100 +portmap_57=57:100 +portmap_61=61:100 + +portmap_67=65:100 +portmap_71=69:100 +portmap_75=73:100 +portmap_79=77:100 +portmap_83=81:100 +portmap_87=85:100 +portmap_91=89:100 +portmap_95=93:100 + +portmap_99=97:100 +portmap_103=101:100 +portmap_107=105:100 +portmap_111=109:100 +portmap_115=113:100 +portmap_119=117:100 +portmap_123=121:100 +portmap_127=125:100 + +# datapath port -- MerlinCore +#Hide these to prevent SAI from initializing them...they are physically not on system +#front panel +#portmap_66=129:10:m +#portmap_130=128:10:m + +# loopback port +portmap_65=130:10 +portmap_131=131:10 + +# port order remap +dport_map_port_29=1 +dport_map_port_30=2 +dport_map_port_31=3 +dport_map_port_32=4 + +dport_map_port_33=5 +dport_map_port_34=6 +dport_map_port_35=7 +dport_map_port_36=8 + +dport_map_port_41=9 +dport_map_port_42=10 +dport_map_port_43=11 +dport_map_port_44=12 + +dport_map_port_45=13 +dport_map_port_46=14 +dport_map_port_47=15 +dport_map_port_48=16 + +dport_map_port_1=17 +dport_map_port_2=18 +dport_map_port_3=19 +dport_map_port_4=20 + +dport_map_port_5=21 +dport_map_port_6=22 +dport_map_port_7=23 +dport_map_port_8=24 + +dport_map_port_9=25 +dport_map_port_10=26 +dport_map_port_11=27 +dport_map_port_12=28 + +dport_map_port_13=29 +dport_map_port_14=30 +dport_map_port_15=31 +dport_map_port_16=32 + +dport_map_port_17=33 +dport_map_port_18=34 +dport_map_port_19=35 +dport_map_port_20=36 + +dport_map_port_21=37 +dport_map_port_22=38 +dport_map_port_23=39 +dport_map_port_24=40 + +dport_map_port_25=41 +dport_map_port_26=42 +dport_map_port_27=43 +dport_map_port_28=44 + +dport_map_port_37=45 +dport_map_port_38=46 +dport_map_port_39=47 +dport_map_port_40=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 + +dport_map_port_61=61 +dport_map_port_62=62 +dport_map_port_63=63 +dport_map_port_64=64 + +dport_map_port_67=65 +dport_map_port_68=66 +dport_map_port_69=67 +dport_map_port_70=68 + +dport_map_port_71=69 +dport_map_port_72=70 +dport_map_port_73=71 +dport_map_port_74=72 + +dport_map_port_75=73 +dport_map_port_76=74 +dport_map_port_77=75 +dport_map_port_78=76 + +dport_map_port_79=77 +dport_map_port_80=78 +dport_map_port_81=79 +dport_map_port_82=80 + +dport_map_port_95=81 +dport_map_port_96=82 +dport_map_port_97=83 +dport_map_port_98=84 + +dport_map_port_103=85 +dport_map_port_104=86 +dport_map_port_105=87 +dport_map_port_106=88 + +dport_map_port_107=89 +dport_map_port_108=90 +dport_map_port_109=91 +dport_map_port_110=92 + +dport_map_port_111=93 +dport_map_port_112=94 +dport_map_port_113=95 +dport_map_port_114=96 + +dport_map_port_115=97 +dport_map_port_116=98 +dport_map_port_117=99 +dport_map_port_118=100 + +dport_map_port_119=101 +dport_map_port_120=102 +dport_map_port_121=103 +dport_map_port_122=104 + +dport_map_port_123=105 +dport_map_port_124=106 +dport_map_port_125=107 +dport_map_port_126=108 + +dport_map_port_127=109 +dport_map_port_128=110 +dport_map_port_129=111 +dport_map_port_130=112 + +dport_map_port_83=113 +dport_map_port_84=114 +dport_map_port_85=115 +dport_map_port_86=116 + +dport_map_port_87=117 +dport_map_port_88=118 +dport_map_port_89=119 +dport_map_port_90=120 + +dport_map_port_91=121 +dport_map_port_92=122 +dport_map_port_93=123 +dport_map_port_94=124 + +dport_map_port_99=125 +dport_map_port_100=126 +dport_map_port_101=127 +dport_map_port_102=128 + +dport_map_port_66=129 +dport_map_port_130=130 + + +### lane swap and polarity follow physical port +phy_chain_tx_lane_map_physical{29.0}=0x1230 +phy_chain_tx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x1 +phy_chain_tx_polarity_flip_physical{32.0}=0x1 +phy_chain_rx_lane_map_physical{29.0}=0x1302 +phy_chain_rx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{30.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x1 +phy_chain_rx_polarity_flip_physical{32.0}=0x1 + +phy_chain_tx_lane_map_physical{33.0}=0x3210 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_tx_polarity_flip_physical{34.0}=0x1 +phy_chain_tx_polarity_flip_physical{35.0}=0x1 +phy_chain_tx_polarity_flip_physical{36.0}=0x1 +phy_chain_rx_lane_map_physical{33.0}=0x0123 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_rx_polarity_flip_physical{36.0}=0x1 + +phy_chain_tx_lane_map_physical{41.0}=0x0213 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x1 +phy_chain_tx_polarity_flip_physical{43.0}=0x1 +phy_chain_tx_polarity_flip_physical{44.0}=0x0 +phy_chain_rx_lane_map_physical{41.0}=0x1302 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x1 +phy_chain_rx_polarity_flip_physical{43.0}=0x0 +phy_chain_rx_polarity_flip_physical{44.0}=0x0 + +phy_chain_tx_lane_map_physical{45.0}=0x3210 +phy_chain_tx_polarity_flip_physical{45.0}=0x1 +phy_chain_tx_polarity_flip_physical{46.0}=0x1 +phy_chain_tx_polarity_flip_physical{47.0}=0x1 +phy_chain_tx_polarity_flip_physical{48.0}=0x1 +phy_chain_rx_lane_map_physical{45.0}=0x2103 +phy_chain_rx_polarity_flip_physical{45.0}=0x0 +phy_chain_rx_polarity_flip_physical{46.0}=0x0 +phy_chain_rx_polarity_flip_physical{47.0}=0x1 +phy_chain_rx_polarity_flip_physical{48.0}=0x0 + +phy_chain_tx_lane_map_physical{1.0}=0x0213 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x1 +phy_chain_tx_polarity_flip_physical{3.0}=0x1 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_rx_lane_map_physical{1.0}=0x1302 +phy_chain_rx_polarity_flip_physical{1.0}=0x0 +phy_chain_rx_polarity_flip_physical{2.0}=0x0 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x1 + +phy_chain_tx_lane_map_physical{5.0}=0x3210 +phy_chain_tx_polarity_flip_physical{5.0}=0x1 +phy_chain_tx_polarity_flip_physical{6.0}=0x1 +phy_chain_tx_polarity_flip_physical{7.0}=0x1 +phy_chain_tx_polarity_flip_physical{8.0}=0x1 +phy_chain_rx_lane_map_physical{5.0}=0x2103 +phy_chain_rx_polarity_flip_physical{5.0}=0x1 +phy_chain_rx_polarity_flip_physical{6.0}=0x1 +phy_chain_rx_polarity_flip_physical{7.0}=0x0 +phy_chain_rx_polarity_flip_physical{8.0}=0x1 + +phy_chain_tx_lane_map_physical{9.0}=0x0213 +phy_chain_tx_polarity_flip_physical{9.0}=0x0 +phy_chain_tx_polarity_flip_physical{10.0}=0x1 +phy_chain_tx_polarity_flip_physical{11.0}=0x1 +phy_chain_tx_polarity_flip_physical{12.0}=0x0 +phy_chain_rx_lane_map_physical{9.0}=0x1302 +phy_chain_rx_polarity_flip_physical{9.0}=0x0 +phy_chain_rx_polarity_flip_physical{10.0}=0x1 +phy_chain_rx_polarity_flip_physical{11.0}=0x1 +phy_chain_rx_polarity_flip_physical{12.0}=0x1 + +phy_chain_tx_lane_map_physical{13.0}=0x3210 +phy_chain_tx_polarity_flip_physical{13.0}=0x1 +phy_chain_tx_polarity_flip_physical{14.0}=0x1 +phy_chain_tx_polarity_flip_physical{15.0}=0x1 +phy_chain_tx_polarity_flip_physical{16.0}=0x1 +phy_chain_rx_lane_map_physical{13.0}=0x2031 +phy_chain_rx_polarity_flip_physical{13.0}=0x1 +phy_chain_rx_polarity_flip_physical{14.0}=0x0 +phy_chain_rx_polarity_flip_physical{15.0}=0x1 +phy_chain_rx_polarity_flip_physical{16.0}=0x1 + +phy_chain_tx_lane_map_physical{17.0}=0x0123 +phy_chain_tx_polarity_flip_physical{17.0}=0x0 +phy_chain_tx_polarity_flip_physical{18.0}=0x0 +phy_chain_tx_polarity_flip_physical{19.0}=0x1 +phy_chain_tx_polarity_flip_physical{20.0}=0x1 +phy_chain_rx_lane_map_physical{17.0}=0x1302 +phy_chain_rx_polarity_flip_physical{17.0}=0x0 +phy_chain_rx_polarity_flip_physical{18.0}=0x0 +phy_chain_rx_polarity_flip_physical{19.0}=0x1 +phy_chain_rx_polarity_flip_physical{20.0}=0x1 + +phy_chain_tx_lane_map_physical{21.0}=0x3210 +phy_chain_tx_polarity_flip_physical{21.0}=0x1 +phy_chain_tx_polarity_flip_physical{22.0}=0x1 +phy_chain_tx_polarity_flip_physical{23.0}=0x1 +phy_chain_tx_polarity_flip_physical{24.0}=0x1 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{22.0}=0x1 +phy_chain_rx_polarity_flip_physical{23.0}=0x1 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 + +phy_chain_tx_lane_map_physical{25.0}=0x0213 +phy_chain_tx_polarity_flip_physical{25.0}=0x1 +phy_chain_tx_polarity_flip_physical{26.0}=0x0 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_tx_polarity_flip_physical{28.0}=0x1 +phy_chain_rx_lane_map_physical{25.0}=0x1302 +phy_chain_rx_polarity_flip_physical{25.0}=0x1 +phy_chain_rx_polarity_flip_physical{26.0}=0x1 +phy_chain_rx_polarity_flip_physical{27.0}=0x0 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 + +phy_chain_tx_lane_map_physical{37.0}=0x3210 +phy_chain_tx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x1 +phy_chain_tx_polarity_flip_physical{39.0}=0x1 +phy_chain_tx_polarity_flip_physical{40.0}=0x1 +phy_chain_rx_lane_map_physical{37.0}=0x2103 +phy_chain_rx_polarity_flip_physical{37.0}=0x0 +phy_chain_rx_polarity_flip_physical{38.0}=0x0 +phy_chain_rx_polarity_flip_physical{39.0}=0x1 +phy_chain_rx_polarity_flip_physical{40.0}=0x0 + +phy_chain_tx_lane_map_physical{49.0}=0x0213 +phy_chain_tx_polarity_flip_physical{49.0}=0x1 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x1 +phy_chain_rx_lane_map_physical{49.0}=0x1302 +phy_chain_rx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x1 +phy_chain_rx_polarity_flip_physical{51.0}=0x0 +phy_chain_rx_polarity_flip_physical{52.0}=0x0 + +phy_chain_tx_lane_map_physical{53.0}=0x3210 +phy_chain_tx_polarity_flip_physical{53.0}=0x0 +phy_chain_tx_polarity_flip_physical{54.0}=0x0 +phy_chain_tx_polarity_flip_physical{55.0}=0x0 +phy_chain_tx_polarity_flip_physical{56.0}=0x0 +phy_chain_rx_lane_map_physical{53.0}=0x2103 +phy_chain_rx_polarity_flip_physical{53.0}=0x0 +phy_chain_rx_polarity_flip_physical{54.0}=0x0 +phy_chain_rx_polarity_flip_physical{55.0}=0x1 +phy_chain_rx_polarity_flip_physical{56.0}=0x0 + +phy_chain_tx_lane_map_physical{57.0}=0x0213 +phy_chain_tx_polarity_flip_physical{57.0}=0x0 +phy_chain_tx_polarity_flip_physical{58.0}=0x1 +phy_chain_tx_polarity_flip_physical{59.0}=0x1 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 +phy_chain_rx_lane_map_physical{57.0}=0x1302 +phy_chain_rx_polarity_flip_physical{57.0}=0x1 +phy_chain_rx_polarity_flip_physical{58.0}=0x1 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 + +phy_chain_tx_lane_map_physical{61.0}=0x3210 +phy_chain_tx_polarity_flip_physical{61.0}=0x1 +phy_chain_tx_polarity_flip_physical{62.0}=0x1 +phy_chain_tx_polarity_flip_physical{63.0}=0x1 +phy_chain_tx_polarity_flip_physical{64.0}=0x1 +phy_chain_rx_lane_map_physical{61.0}=0x2103 +phy_chain_rx_polarity_flip_physical{61.0}=0x0 +phy_chain_rx_polarity_flip_physical{62.0}=0x0 +phy_chain_rx_polarity_flip_physical{63.0}=0x1 +phy_chain_rx_polarity_flip_physical{64.0}=0x0 + +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_tx_polarity_flip_physical{65.0}=0x0 +phy_chain_tx_polarity_flip_physical{66.0}=0x0 +phy_chain_tx_polarity_flip_physical{67.0}=0x1 +phy_chain_tx_polarity_flip_physical{68.0}=0x1 +phy_chain_rx_lane_map_physical{65.0}=0x3120 +phy_chain_rx_polarity_flip_physical{65.0}=0x0 +phy_chain_rx_polarity_flip_physical{66.0}=0x0 +phy_chain_rx_polarity_flip_physical{67.0}=0x1 +phy_chain_rx_polarity_flip_physical{68.0}=0x1 + +phy_chain_tx_lane_map_physical{69.0}=0x0123 +phy_chain_tx_polarity_flip_physical{69.0}=0x0 +phy_chain_tx_polarity_flip_physical{70.0}=0x0 +phy_chain_tx_polarity_flip_physical{71.0}=0x0 +phy_chain_tx_polarity_flip_physical{72.0}=0x0 +phy_chain_rx_lane_map_physical{69.0}=0x2301 +phy_chain_rx_polarity_flip_physical{69.0}=0x1 +phy_chain_rx_polarity_flip_physical{70.0}=0x0 +phy_chain_rx_polarity_flip_physical{71.0}=0x0 +phy_chain_rx_polarity_flip_physical{72.0}=0x0 + +phy_chain_tx_lane_map_physical{73.0}=0x3120 +phy_chain_tx_polarity_flip_physical{73.0}=0x1 +phy_chain_tx_polarity_flip_physical{74.0}=0x0 +phy_chain_tx_polarity_flip_physical{75.0}=0x0 +phy_chain_tx_polarity_flip_physical{76.0}=0x1 +phy_chain_rx_lane_map_physical{73.0}=0x3120 +phy_chain_rx_polarity_flip_physical{73.0}=0x0 +phy_chain_rx_polarity_flip_physical{74.0}=0x0 +phy_chain_rx_polarity_flip_physical{75.0}=0x1 +phy_chain_rx_polarity_flip_physical{76.0}=0x1 + +phy_chain_tx_lane_map_physical{77.0}=0x0213 +phy_chain_tx_polarity_flip_physical{77.0}=0x1 +phy_chain_tx_polarity_flip_physical{78.0}=0x0 +phy_chain_tx_polarity_flip_physical{79.0}=0x0 +phy_chain_tx_polarity_flip_physical{80.0}=0x1 +phy_chain_rx_lane_map_physical{77.0}=0x0321 +phy_chain_rx_polarity_flip_physical{77.0}=0x1 +phy_chain_rx_polarity_flip_physical{78.0}=0x1 +phy_chain_rx_polarity_flip_physical{79.0}=0x0 +phy_chain_rx_polarity_flip_physical{80.0}=0x1 + +phy_chain_tx_lane_map_physical{93.0}=0x3120 +phy_chain_tx_polarity_flip_physical{93.0}=0x1 +phy_chain_tx_polarity_flip_physical{94.0}=0x0 +phy_chain_tx_polarity_flip_physical{95.0}=0x0 +phy_chain_tx_polarity_flip_physical{96.0}=0x1 +phy_chain_rx_lane_map_physical{93.0}=0x3120 +phy_chain_rx_polarity_flip_physical{93.0}=0x1 +phy_chain_rx_polarity_flip_physical{94.0}=0x1 +phy_chain_rx_polarity_flip_physical{95.0}=0x0 +phy_chain_rx_polarity_flip_physical{96.0}=0x0 + +phy_chain_tx_lane_map_physical{101.0}=0x0321 +phy_chain_tx_polarity_flip_physical{101.0}=0x0 +phy_chain_tx_polarity_flip_physical{102.0}=0x1 +phy_chain_tx_polarity_flip_physical{103.0}=0x1 +phy_chain_tx_polarity_flip_physical{104.0}=0x1 +phy_chain_rx_lane_map_physical{101.0}=0x0321 +phy_chain_rx_polarity_flip_physical{101.0}=0x1 +phy_chain_rx_polarity_flip_physical{102.0}=0x1 +phy_chain_rx_polarity_flip_physical{103.0}=0x0 +phy_chain_rx_polarity_flip_physical{104.0}=0x1 + +phy_chain_tx_lane_map_physical{105.0}=0x3120 +phy_chain_tx_polarity_flip_physical{105.0}=0x1 +phy_chain_tx_polarity_flip_physical{106.0}=0x0 +phy_chain_tx_polarity_flip_physical{107.0}=0x0 +phy_chain_tx_polarity_flip_physical{108.0}=0x1 +phy_chain_rx_lane_map_physical{105.0}=0x3120 +phy_chain_rx_polarity_flip_physical{105.0}=0x1 +phy_chain_rx_polarity_flip_physical{106.0}=0x1 +phy_chain_rx_polarity_flip_physical{107.0}=0x0 +phy_chain_rx_polarity_flip_physical{108.0}=0x0 + +phy_chain_tx_lane_map_physical{109.0}=0x0123 +phy_chain_tx_polarity_flip_physical{109.0}=0x1 +phy_chain_tx_polarity_flip_physical{110.0}=0x1 +phy_chain_tx_polarity_flip_physical{111.0}=0x1 +phy_chain_tx_polarity_flip_physical{112.0}=0x1 +phy_chain_rx_lane_map_physical{109.0}=0x0321 +phy_chain_rx_polarity_flip_physical{109.0}=0x0 +phy_chain_rx_polarity_flip_physical{110.0}=0x0 +phy_chain_rx_polarity_flip_physical{111.0}=0x1 +phy_chain_rx_polarity_flip_physical{112.0}=0x0 + +phy_chain_tx_lane_map_physical{113.0}=0x0312 +phy_chain_tx_polarity_flip_physical{113.0}=0x0 +phy_chain_tx_polarity_flip_physical{114.0}=0x0 +phy_chain_tx_polarity_flip_physical{115.0}=0x1 +phy_chain_tx_polarity_flip_physical{116.0}=0x0 +phy_chain_rx_lane_map_physical{113.0}=0x3120 +phy_chain_rx_polarity_flip_physical{113.0}=0x1 +phy_chain_rx_polarity_flip_physical{114.0}=0x1 +phy_chain_rx_polarity_flip_physical{115.0}=0x0 +phy_chain_rx_polarity_flip_physical{116.0}=0x1 + +phy_chain_tx_lane_map_physical{117.0}=0x0123 +phy_chain_tx_polarity_flip_physical{117.0}=0x1 +phy_chain_tx_polarity_flip_physical{118.0}=0x1 +phy_chain_tx_polarity_flip_physical{119.0}=0x1 +phy_chain_tx_polarity_flip_physical{120.0}=0x1 +phy_chain_rx_lane_map_physical{117.0}=0x1320 +phy_chain_rx_polarity_flip_physical{117.0}=0x1 +phy_chain_rx_polarity_flip_physical{118.0}=0x1 +phy_chain_rx_polarity_flip_physical{119.0}=0x1 +phy_chain_rx_polarity_flip_physical{120.0}=0x0 + +phy_chain_tx_lane_map_physical{121.0}=0x3120 +phy_chain_tx_polarity_flip_physical{121.0}=0x1 +phy_chain_tx_polarity_flip_physical{122.0}=0x0 +phy_chain_tx_polarity_flip_physical{123.0}=0x0 +phy_chain_tx_polarity_flip_physical{124.0}=0x1 +phy_chain_rx_lane_map_physical{121.0}=0x0123 +phy_chain_rx_polarity_flip_physical{121.0}=0x0 +phy_chain_rx_polarity_flip_physical{122.0}=0x1 +phy_chain_rx_polarity_flip_physical{123.0}=0x0 +phy_chain_rx_polarity_flip_physical{124.0}=0x1 + +phy_chain_tx_lane_map_physical{125.0}=0x0123 +phy_chain_tx_polarity_flip_physical{125.0}=0x0 +phy_chain_tx_polarity_flip_physical{126.0}=0x0 +phy_chain_tx_polarity_flip_physical{127.0}=0x0 +phy_chain_tx_polarity_flip_physical{128.0}=0x0 +phy_chain_rx_lane_map_physical{125.0}=0x0321 +phy_chain_rx_polarity_flip_physical{125.0}=0x0 +phy_chain_rx_polarity_flip_physical{126.0}=0x0 +phy_chain_rx_polarity_flip_physical{127.0}=0x1 +phy_chain_rx_polarity_flip_physical{128.0}=0x0 + +phy_chain_tx_lane_map_physical{81.0}=0x3201 +phy_chain_tx_polarity_flip_physical{81.0}=0x0 +phy_chain_tx_polarity_flip_physical{82.0}=0x1 +phy_chain_tx_polarity_flip_physical{83.0}=0x1 +phy_chain_tx_polarity_flip_physical{84.0}=0x1 +phy_chain_rx_lane_map_physical{81.0}=0x3120 +phy_chain_rx_polarity_flip_physical{81.0}=0x0 +phy_chain_rx_polarity_flip_physical{82.0}=0x0 +phy_chain_rx_polarity_flip_physical{83.0}=0x1 +phy_chain_rx_polarity_flip_physical{84.0}=0x0 + +phy_chain_tx_lane_map_physical{85.0}=0x0123 +phy_chain_tx_polarity_flip_physical{85.0}=0x1 +phy_chain_tx_polarity_flip_physical{86.0}=0x1 +phy_chain_tx_polarity_flip_physical{87.0}=0x1 +phy_chain_tx_polarity_flip_physical{88.0}=0x1 +phy_chain_rx_lane_map_physical{85.0}=0x0321 +phy_chain_rx_polarity_flip_physical{85.0}=0x1 +phy_chain_rx_polarity_flip_physical{86.0}=0x1 +phy_chain_rx_polarity_flip_physical{87.0}=0x0 +phy_chain_rx_polarity_flip_physical{88.0}=0x1 + +phy_chain_tx_lane_map_physical{89.0}=0x3210 +phy_chain_tx_polarity_flip_physical{89.0}=0x1 +phy_chain_tx_polarity_flip_physical{90.0}=0x1 +phy_chain_tx_polarity_flip_physical{91.0}=0x1 +phy_chain_tx_polarity_flip_physical{92.0}=0x1 +phy_chain_rx_lane_map_physical{89.0}=0x0123 +phy_chain_rx_polarity_flip_physical{89.0}=0x1 +phy_chain_rx_polarity_flip_physical{90.0}=0x0 +phy_chain_rx_polarity_flip_physical{91.0}=0x1 +phy_chain_rx_polarity_flip_physical{92.0}=0x0 + +phy_chain_tx_lane_map_physical{97.0}=0x0312 +phy_chain_tx_polarity_flip_physical{97.0}=0x0 +phy_chain_tx_polarity_flip_physical{98.0}=0x0 +phy_chain_tx_polarity_flip_physical{99.0}=0x1 +phy_chain_tx_polarity_flip_physical{100.0}=0x1 +phy_chain_rx_lane_map_physical{97.0}=0x0321 +phy_chain_rx_polarity_flip_physical{97.0}=0x1 +phy_chain_rx_polarity_flip_physical{98.0}=0x0 +phy_chain_rx_polarity_flip_physical{99.0}=0x1 +phy_chain_rx_polarity_flip_physical{100.0}=0x0 + + +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/custom_led.bin b/device/quanta/x86_64-quanta_ix7_bwde-r0/custom_led.bin new file mode 100644 index 0000000000..813addd1ac Binary files /dev/null and b/device/quanta/x86_64-quanta_ix7_bwde-r0/custom_led.bin differ diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/default_sku b/device/quanta/x86_64-quanta_ix7_bwde-r0/default_sku new file mode 100644 index 0000000000..bd318bb8fc --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/default_sku @@ -0,0 +1 @@ +Quanta-IX7-BWDE-32X t1 diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/installer.conf b/device/quanta/x86_64-quanta_ix7_bwde-r0/installer.conf new file mode 100644 index 0000000000..90f773149c --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/installer.conf @@ -0,0 +1,4 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 + diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/led_proc_init.soc b/device/quanta/x86_64-quanta_ix7_bwde-r0/led_proc_init.soc new file mode 100644 index 0000000000..7b049da0ea --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/led_proc_init.soc @@ -0,0 +1,4 @@ +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin +led start + +rcload /usr/share/sonic/platform/preemphasis-32x100G.soc \ No newline at end of file diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/eeprom.py b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/eeprom.py new file mode 100644 index 0000000000..0a6121c3cd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/eeprom.py @@ -0,0 +1,12 @@ +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/fanutil.py b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/fanutil.py new file mode 100644 index 0000000000..2cf72ddf7e --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/fanutil.py @@ -0,0 +1,110 @@ +# +# fanutil.py +# Platform-specific Fan status interface for SONiC +# + +import logging +import os.path + +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""" + + SYS_FAN_NUM = 6 + NUM_FANS_PERTRAY = 2 + HWMON_PATH = '/sys/class/hwmon/hwmon2/' + FAN_INDEX_START = 18 + + logger = logging.getLogger(__name__) + + def __init__(self, log_level=logging.DEBUG): + FanBase.__init__(self) + self.num_fans = (self.SYS_FAN_NUM * self.NUM_FANS_PERTRAY) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def check_fan_index(self, index): + if index is None: + return False + + if index < 1 or index > self.num_fans: + logging.error("Invalid Fan index:", index) + return False + + return True + + def get_num_fans(self): + return self.num_fans + + def get_status(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + if fantray_speed == '0.0' : + return False + + return True + + def get_presence(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_present_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_present' + fantray_present = self.get_attr_value(self.HWMON_PATH + fantray_present_file) + + if fantray_present == '1' : + return True + + return False + + def get_direction(self, index): + if self.check_fan_index(index) == False: + return None + + fantray_direction_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_direction' + fantray_direction = self.get_attr_value(self.HWMON_PATH + fantray_direction_file) + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if fantray_direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_speed(self, index): + if self.check_fan_index(index) == False: + return 0 + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + return int(float(fantray_speed)) + + + def set_speed(self, val): + logging.error("Not allowed to set fan speed!") + + return False diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/psuutil.py b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/psuutil.py new file mode 100644 index 0000000000..1761fcd3d3 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/psuutil.py @@ -0,0 +1,251 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + +import logging +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + HWMON_PATH = '/sys/class/hwmon/hwmon2/' + PSU1_PREFIX = 'power39_' + PSU2_PREFIX = 'power49_' + MAX_PSUS = 2 + def __init__(self): + PsuBase.__init__(self) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def get_attr_filename(self, index, attr): + if (index == 1): + attr_file = self.PSU1_PREFIX + attr + elif (index == 2): + attr_file = self.PSU2_PREFIX + attr + else: + logging.error("Invalid PSU number:", index) + return '' + + return attr_file + + 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 + """ + + return self.MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'present') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check PSU status + if (attr_value == 1): + status = True + return status + + def get_powergood_status(self, index): + status = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_model(self, index): + attr_filename = self.get_attr_filename(index, 'model') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_mfr_id(self, index): + attr_filename = self.get_attr_filename(index, 'mfrid') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_serial(self, index): + attr_filename = self.get_attr_filename(index, 'sn') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_direction(self, index): + if (index == 1): + direction_file = 'fan37_direction' + elif (index == 2): + direction_file = 'fan47_direction' + else: + logging.error("Invalid PSU number:", index) + return None + + direction = self.get_attr_value(self.HWMON_PATH + direction_file) + direction = direction.rstrip() + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_output_voltage(self, index): + if (index == 1): + attr_file = 'in44_input' + elif (index == 2): + attr_file = 'in54_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + voltage = self.get_attr_value(self.HWMON_PATH + attr_file) + voltage = voltage.rstrip() + + if (voltage != 'ERR'): + voltage, dummy = voltage.split('.', 1) + else: + return 0.0 + + return float(voltage)/1000 + + def get_output_current(self, index): + if (index == 1): + attr_file = 'curr36_input' + elif (index == 2): + attr_file = 'curr46_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + current = self.get_attr_value(self.HWMON_PATH + attr_file) + current = current.rstrip() + + if (current != 'ERR'): + current, dummy = current.split('.',1) + else: + return 0.0 + + return float(current)/1000 + + def get_output_power(self, index): + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return 0.0 + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + else: + return 0.0 + + return float(attr_value/1000) + + def get_fan_rpm(self, index, fan_idx): + if (index == 1): + rpm_file = 'fan37_input' + elif (index == 2): + rpm_file = 'fan47_input' + else: + logging.error("Invalid PSU number:", index) + return 0 + + rpm = self.get_attr_value(self.HWMON_PATH + rpm_file) + rpm = rpm.rstrip() + if (rpm != 'ERR'): + rpm = float(rpm) + else: + return 0 + + return int(rpm) diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/sfputil.py b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/sfputil.py new file mode 100644 index 0000000000..1cc3a12b37 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/plugins/sfputil.py @@ -0,0 +1,172 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + 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 = 32 + PORTS_IN_BLOCK = 32 + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_ports(self): + return list(range(self.PORT_START, self.PORTS_IN_BLOCK + 1)) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x]) + SfpUtilBase.__init__(self) + + 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 + + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(port_num)+"/module_present") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + if reg_value == '1': + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(port_num)+"/lpmode") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = int(reg_file.readline().rstrip()) + + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(port_num)+"/lpmode", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(port_num)+"/reset", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(port_num)+"/reset", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/pmon_daemon_control.json b/device/quanta/x86_64-quanta_ix7_bwde-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..94592fa8ce --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/quanta/x86_64-quanta_ix7_bwde-r0/preemphasis-32x100G.soc b/device/quanta/x86_64-quanta_ix7_bwde-r0/preemphasis-32x100G.soc new file mode 100644 index 0000000000..986bb271ca --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_bwde-r0/preemphasis-32x100G.soc @@ -0,0 +1,546 @@ +# Pre-emphasis + +phy raw c45 0xa5 0x1 0xffde 0 +phy raw c45 0xa5 0x1 0xd130 0x4d +phy raw c45 0xa5 0x1 0xd131 0x0611 +phy raw c45 0xa5 0x1 0xd134 1 +phy raw c45 0xa5 0x1 0xffde 1 +phy raw c45 0xa5 0x1 0xd130 0x4d +phy raw c45 0xa5 0x1 0xd131 0x0611 +phy raw c45 0xa5 0x1 0xd134 1 +phy raw c45 0xa5 0x1 0xffde 2 +phy raw c45 0xa5 0x1 0xd130 0x4e +phy raw c45 0xa5 0x1 0xd131 0x0610 +phy raw c45 0xa5 0x1 0xd134 1 +phy raw c45 0xa5 0x1 0xffde 3 +phy raw c45 0xa5 0x1 0xd130 0x4e +phy raw c45 0xa5 0x1 0xd131 0x0610 +phy raw c45 0xa5 0x1 0xd134 1 + +phy raw c45 0xa9 0x1 0xffde 0 +phy raw c45 0xa9 0x1 0xd130 0x4e +phy raw c45 0xa9 0x1 0xd131 0x0610 +phy raw c45 0xa9 0x1 0xd134 1 +phy raw c45 0xa9 0x1 0xffde 1 +phy raw c45 0xa9 0x1 0xd130 0x4e +phy raw c45 0xa9 0x1 0xd131 0x0610 +phy raw c45 0xa9 0x1 0xd134 1 +phy raw c45 0xa9 0x1 0xffde 2 +phy raw c45 0xa9 0x1 0xd130 0x4e +phy raw c45 0xa9 0x1 0xd131 0x0610 +phy raw c45 0xa9 0x1 0xd134 1 +phy raw c45 0xa9 0x1 0xffde 3 +phy raw c45 0xa9 0x1 0xd130 0x4e +phy raw c45 0xa9 0x1 0xd131 0x0610 +phy raw c45 0xa9 0x1 0xd134 1 + +phy raw c45 0xc1 0x1 0xffde 0 +phy raw c45 0xc1 0x1 0xd130 0x4e +phy raw c45 0xc1 0x1 0xd131 0x0610 +phy raw c45 0xc1 0x1 0xd134 1 +phy raw c45 0xc1 0x1 0xffde 1 +phy raw c45 0xc1 0x1 0xd130 0x4d +phy raw c45 0xc1 0x1 0xd131 0x0611 +phy raw c45 0xc1 0x1 0xd134 1 +phy raw c45 0xc1 0x1 0xffde 2 +phy raw c45 0xc1 0x1 0xd130 0x4e +phy raw c45 0xc1 0x1 0xd131 0x0610 +phy raw c45 0xc1 0x1 0xd134 1 +phy raw c45 0xc1 0x1 0xffde 3 +phy raw c45 0xc1 0x1 0xd130 0x4e +phy raw c45 0xc1 0x1 0xd131 0x0610 +phy raw c45 0xc1 0x1 0xd134 1 + +phy raw c45 0xc5 0x1 0xffde 0 +phy raw c45 0xc5 0x1 0xd130 0x4e +phy raw c45 0xc5 0x1 0xd131 0x0610 +phy raw c45 0xc5 0x1 0xd134 1 +phy raw c45 0xc5 0x1 0xffde 1 +phy raw c45 0xc5 0x1 0xd130 0x4e +phy raw c45 0xc5 0x1 0xd131 0x0610 +phy raw c45 0xc5 0x1 0xd134 1 +phy raw c45 0xc5 0x1 0xffde 2 +phy raw c45 0xc5 0x1 0xd130 0x4d +phy raw c45 0xc5 0x1 0xd131 0x0611 +phy raw c45 0xc5 0x1 0xd134 1 +phy raw c45 0xc5 0x1 0xffde 3 +phy raw c45 0xc5 0x1 0xd130 0x4e +phy raw c45 0xc5 0x1 0xd131 0x0610 +phy raw c45 0xc5 0x1 0xd134 1 + +phy raw c45 0x81 0x1 0xffde 0 +phy raw c45 0x81 0x1 0xd130 0x4e +phy raw c45 0x81 0x1 0xd131 0x0610 +phy raw c45 0x81 0x1 0xd134 1 +phy raw c45 0x81 0x1 0xffde 1 +phy raw c45 0x81 0x1 0xd130 0x4d +phy raw c45 0x81 0x1 0xd131 0x0611 +phy raw c45 0x81 0x1 0xd134 1 +phy raw c45 0x81 0x1 0xffde 2 +phy raw c45 0x81 0x1 0xd130 0x4e +phy raw c45 0x81 0x1 0xd131 0x0610 +phy raw c45 0x81 0x1 0xd134 1 +phy raw c45 0x81 0x1 0xffde 3 +phy raw c45 0x81 0x1 0xd130 0x4e +phy raw c45 0x81 0x1 0xd131 0x0610 +phy raw c45 0x81 0x1 0xd134 1 + +phy raw c45 0x85 0x1 0xffde 0 +phy raw c45 0x85 0x1 0xd130 0x4e +phy raw c45 0x85 0x1 0xd131 0x0610 +phy raw c45 0x85 0x1 0xd134 1 +phy raw c45 0x85 0x1 0xffde 1 +phy raw c45 0x85 0x1 0xd130 0x4e +phy raw c45 0x85 0x1 0xd131 0x0610 +phy raw c45 0x85 0x1 0xd134 1 +phy raw c45 0x85 0x1 0xffde 2 +phy raw c45 0x85 0x1 0xd130 0x4e +phy raw c45 0x85 0x1 0xd131 0x0610 +phy raw c45 0x85 0x1 0xd134 1 +phy raw c45 0x85 0x1 0xffde 3 +phy raw c45 0x85 0x1 0xd130 0x4d +phy raw c45 0x85 0x1 0xd131 0x0611 +phy raw c45 0x85 0x1 0xd134 1 + +phy raw c45 0x89 0x1 0xffde 0 +phy raw c45 0x89 0x1 0xd130 0x50 +phy raw c45 0x89 0x1 0xd131 0x060e +phy raw c45 0x89 0x1 0xd134 1 +phy raw c45 0x89 0x1 0xffde 1 +phy raw c45 0x89 0x1 0xd130 0x50 +phy raw c45 0x89 0x1 0xd131 0x060e +phy raw c45 0x89 0x1 0xd134 1 +phy raw c45 0x89 0x1 0xffde 2 +phy raw c45 0x89 0x1 0xd130 0x50 +phy raw c45 0x89 0x1 0xd131 0x060e +phy raw c45 0x89 0x1 0xd134 1 +phy raw c45 0x89 0x1 0xffde 3 +phy raw c45 0x89 0x1 0xd130 0x50 +phy raw c45 0x89 0x1 0xd131 0x060e +phy raw c45 0x89 0x1 0xd134 1 + +phy raw c45 0x8d 0x1 0xffde 0 +phy raw c45 0x8d 0x1 0xd130 0x4f +phy raw c45 0x8d 0x1 0xd131 0x060f +phy raw c45 0x8d 0x1 0xd134 1 +phy raw c45 0x8d 0x1 0xffde 1 +phy raw c45 0x8d 0x1 0xd130 0x4f +phy raw c45 0x8d 0x1 0xd131 0x060f +phy raw c45 0x8d 0x1 0xd134 1 +phy raw c45 0x8d 0x1 0xffde 2 +phy raw c45 0x8d 0x1 0xd130 0x4f +phy raw c45 0x8d 0x1 0xd131 0x060f +phy raw c45 0x8d 0x1 0xd134 1 +phy raw c45 0x8d 0x1 0xffde 3 +phy raw c45 0x8d 0x1 0xd130 0x4f +phy raw c45 0x8d 0x1 0xd131 0x060f +phy raw c45 0x8d 0x1 0xd134 1 + +phy raw c45 0x91 0x1 0xffde 0 +phy raw c45 0x91 0x1 0xd130 0x50 +phy raw c45 0x91 0x1 0xd131 0x060e +phy raw c45 0x91 0x1 0xd134 1 +phy raw c45 0x91 0x1 0xffde 1 +phy raw c45 0x91 0x1 0xd130 0x50 +phy raw c45 0x91 0x1 0xd131 0x060e +phy raw c45 0x91 0x1 0xd134 1 +phy raw c45 0x91 0x1 0xffde 2 +phy raw c45 0x91 0x1 0xd130 0x50 +phy raw c45 0x91 0x1 0xd131 0x060e +phy raw c45 0x91 0x1 0xd134 1 +phy raw c45 0x91 0x1 0xffde 3 +phy raw c45 0x91 0x1 0xd130 0x50 +phy raw c45 0x91 0x1 0xd131 0x060e +phy raw c45 0x91 0x1 0xd134 1 + +phy raw c45 0x95 0x1 0xffde 0 +phy raw c45 0x95 0x1 0xd130 0x52 +phy raw c45 0x95 0x1 0xd131 0x060c +phy raw c45 0x95 0x1 0xd134 1 +phy raw c45 0x95 0x1 0xffde 1 +phy raw c45 0x95 0x1 0xd130 0x52 +phy raw c45 0x95 0x1 0xd131 0x060c +phy raw c45 0x95 0x1 0xd134 1 +phy raw c45 0x95 0x1 0xffde 2 +phy raw c45 0x95 0x1 0xd130 0x52 +phy raw c45 0x95 0x1 0xd131 0x060c +phy raw c45 0x95 0x1 0xd134 1 +phy raw c45 0x95 0x1 0xffde 3 +phy raw c45 0x95 0x1 0xd130 0x52 +phy raw c45 0x95 0x1 0xd131 0x060c +phy raw c45 0x95 0x1 0xd134 1 + +phy raw c45 0xa1 0x1 0xffde 0 +phy raw c45 0xa1 0x1 0xd130 0x52 +phy raw c45 0xa1 0x1 0xd131 0x060c +phy raw c45 0xa1 0x1 0xd134 1 +phy raw c45 0xa1 0x1 0xffde 1 +phy raw c45 0xa1 0x1 0xd130 0x52 +phy raw c45 0xa1 0x1 0xd131 0x060c +phy raw c45 0xa1 0x1 0xd134 1 +phy raw c45 0xa1 0x1 0xffde 2 +phy raw c45 0xa1 0x1 0xd130 0x52 +phy raw c45 0xa1 0x1 0xd131 0x060c +phy raw c45 0xa1 0x1 0xd134 1 +phy raw c45 0xa1 0x1 0xffde 3 +phy raw c45 0xa1 0x1 0xd130 0x52 +phy raw c45 0xa1 0x1 0xd131 0x060c +phy raw c45 0xa1 0x1 0xd134 1 + +phy raw c45 0xad 0x1 0xffde 0 +phy raw c45 0xad 0x1 0xd130 0x53 +phy raw c45 0xad 0x1 0xd131 0x060b +phy raw c45 0xad 0x1 0xd134 1 +phy raw c45 0xad 0x1 0xffde 1 +phy raw c45 0xad 0x1 0xd130 0x53 +phy raw c45 0xad 0x1 0xd131 0x060b +phy raw c45 0xad 0x1 0xd134 1 +phy raw c45 0xad 0x1 0xffde 2 +phy raw c45 0xad 0x1 0xd130 0x53 +phy raw c45 0xad 0x1 0xd131 0x060b +phy raw c45 0xad 0x1 0xd134 1 +phy raw c45 0xad 0x1 0xffde 3 +phy raw c45 0xad 0x1 0xd130 0x53 +phy raw c45 0xad 0x1 0xd131 0x060b +phy raw c45 0xad 0x1 0xd134 1 + +phy raw c45 0xc9 0x1 0xffde 0 +phy raw c45 0xc9 0x1 0xd130 0x53 +phy raw c45 0xc9 0x1 0xd131 0x060b +phy raw c45 0xc9 0x1 0xd134 1 +phy raw c45 0xc9 0x1 0xffde 1 +phy raw c45 0xc9 0x1 0xd130 0x53 +phy raw c45 0xc9 0x1 0xd131 0x060b +phy raw c45 0xc9 0x1 0xd134 1 +phy raw c45 0xc9 0x1 0xffde 2 +phy raw c45 0xc9 0x1 0xd130 0x53 +phy raw c45 0xc9 0x1 0xd131 0x060b +phy raw c45 0xc9 0x1 0xd134 1 +phy raw c45 0xc9 0x1 0xffde 3 +phy raw c45 0xc9 0x1 0xd130 0x53 +phy raw c45 0xc9 0x1 0xd131 0x060b +phy raw c45 0xc9 0x1 0xd134 1 + +phy raw c45 0xcd 0x1 0xffde 0 +phy raw c45 0xcd 0x1 0xd130 0x54 +phy raw c45 0xcd 0x1 0xd131 0x060a +phy raw c45 0xcd 0x1 0xd134 1 +phy raw c45 0xcd 0x1 0xffde 1 +phy raw c45 0xcd 0x1 0xd130 0x54 +phy raw c45 0xcd 0x1 0xd131 0x060a +phy raw c45 0xcd 0x1 0xd134 1 +phy raw c45 0xcd 0x1 0xffde 2 +phy raw c45 0xcd 0x1 0xd130 0x54 +phy raw c45 0xcd 0x1 0xd131 0x060a +phy raw c45 0xcd 0x1 0xd134 1 +phy raw c45 0xcd 0x1 0xffde 3 +phy raw c45 0xcd 0x1 0xd130 0x54 +phy raw c45 0xcd 0x1 0xd131 0x060a +phy raw c45 0xcd 0x1 0xd134 1 + +phy raw c45 0xd1 0x1 0xffde 0 +phy raw c45 0xd1 0x1 0xd130 0x56 +phy raw c45 0xd1 0x1 0xd131 0x0608 +phy raw c45 0xd1 0x1 0xd134 1 +phy raw c45 0xd1 0x1 0xffde 1 +phy raw c45 0xd1 0x1 0xd130 0x56 +phy raw c45 0xd1 0x1 0xd131 0x0608 +phy raw c45 0xd1 0x1 0xd134 1 +phy raw c45 0xd1 0x1 0xffde 2 +phy raw c45 0xd1 0x1 0xd130 0x56 +phy raw c45 0xd1 0x1 0xd131 0x0608 +phy raw c45 0xd1 0x1 0xd134 1 +phy raw c45 0xd1 0x1 0xffde 3 +phy raw c45 0xd1 0x1 0xd130 0x56 +phy raw c45 0xd1 0x1 0xd131 0x0608 +phy raw c45 0xd1 0x1 0xd134 1 + +phy raw c45 0xd5 0x1 0xffde 0 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x0609 +phy raw c45 0xd5 0x1 0xd134 1 +phy raw c45 0xd5 0x1 0xffde 1 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x0609 +phy raw c45 0xd5 0x1 0xd134 1 +phy raw c45 0xd5 0x1 0xffde 2 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x0609 +phy raw c45 0xd5 0x1 0xd134 1 +phy raw c45 0xd5 0x1 0xffde 3 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x0609 +phy raw c45 0xd5 0x1 0xd134 1 + +phy raw c45 0xe1 0x1 0xffde 0 +phy raw c45 0xe1 0x1 0xd130 0x56 +phy raw c45 0xe1 0x1 0xd131 0x0608 +phy raw c45 0xe1 0x1 0xd134 1 +phy raw c45 0xe1 0x1 0xffde 1 +phy raw c45 0xe1 0x1 0xd130 0x56 +phy raw c45 0xe1 0x1 0xd131 0x0608 +phy raw c45 0xe1 0x1 0xd134 1 +phy raw c45 0xe1 0x1 0xffde 2 +phy raw c45 0xe1 0x1 0xd130 0x56 +phy raw c45 0xe1 0x1 0xd131 0x0608 +phy raw c45 0xe1 0x1 0xd134 1 +phy raw c45 0xe1 0x1 0xffde 3 +phy raw c45 0xe1 0x1 0xd130 0x56 +phy raw c45 0xe1 0x1 0xd131 0x0608 +phy raw c45 0xe1 0x1 0xd134 1 + +phy raw c45 0xe5 0x1 0xffde 0 +phy raw c45 0xe5 0x1 0xd130 0x55 +phy raw c45 0xe5 0x1 0xd131 0x0609 +phy raw c45 0xe5 0x1 0xd134 1 +phy raw c45 0xe5 0x1 0xffde 1 +phy raw c45 0xe5 0x1 0xd130 0x55 +phy raw c45 0xe5 0x1 0xd131 0x0609 +phy raw c45 0xe5 0x1 0xd134 1 +phy raw c45 0xe5 0x1 0xffde 2 +phy raw c45 0xe5 0x1 0xd130 0x55 +phy raw c45 0xe5 0x1 0xd131 0x0609 +phy raw c45 0xe5 0x1 0xd134 1 +phy raw c45 0xe5 0x1 0xffde 3 +phy raw c45 0xe5 0x1 0xd130 0x55 +phy raw c45 0xe5 0x1 0xd131 0x0609 +phy raw c45 0xe5 0x1 0xd134 1 + +phy raw c45 0xe9 0x1 0xffde 0 +phy raw c45 0xe9 0x1 0xd130 0x56 +phy raw c45 0xe9 0x1 0xd131 0x0608 +phy raw c45 0xe9 0x1 0xd134 1 +phy raw c45 0xe9 0x1 0xffde 1 +phy raw c45 0xe9 0x1 0xd130 0x56 +phy raw c45 0xe9 0x1 0xd131 0x0608 +phy raw c45 0xe9 0x1 0xd134 1 +phy raw c45 0xe9 0x1 0xffde 2 +phy raw c45 0xe9 0x1 0xd130 0x56 +phy raw c45 0xe9 0x1 0xd131 0x0608 +phy raw c45 0xe9 0x1 0xd134 1 +phy raw c45 0xe9 0x1 0xffde 3 +phy raw c45 0xe9 0x1 0xd130 0x56 +phy raw c45 0xe9 0x1 0xd131 0x0608 +phy raw c45 0xe9 0x1 0xd134 1 + +phy raw c45 0xed 0x1 0xffde 0 +phy raw c45 0xed 0x1 0xd130 0x55 +phy raw c45 0xed 0x1 0xd131 0x0609 +phy raw c45 0xed 0x1 0xd134 1 +phy raw c45 0xed 0x1 0xffde 1 +phy raw c45 0xed 0x1 0xd130 0x53 +phy raw c45 0xed 0x1 0xd131 0x060b +phy raw c45 0xed 0x1 0xd134 1 +phy raw c45 0xed 0x1 0xffde 2 +phy raw c45 0xed 0x1 0xd130 0x54 +phy raw c45 0xed 0x1 0xd131 0x060a +phy raw c45 0xed 0x1 0xd134 1 +phy raw c45 0xed 0x1 0xffde 3 +phy raw c45 0xed 0x1 0xd130 0x54 +phy raw c45 0xed 0x1 0xd131 0x060a +phy raw c45 0xed 0x1 0xd134 1 + +phy raw c45 0x185 0x1 0xffde 0 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x0609 +phy raw c45 0x185 0x1 0xd134 1 +phy raw c45 0x185 0x1 0xffde 1 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x0609 +phy raw c45 0x185 0x1 0xd134 1 +phy raw c45 0x185 0x1 0xffde 2 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x0609 +phy raw c45 0x185 0x1 0xd134 1 +phy raw c45 0x185 0x1 0xffde 3 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x0609 +phy raw c45 0x185 0x1 0xd134 1 + +phy raw c45 0x18d 0x1 0xffde 0 +phy raw c45 0x18d 0x1 0xd130 0x54 +phy raw c45 0x18d 0x1 0xd131 0x060a +phy raw c45 0x18d 0x1 0xd134 1 +phy raw c45 0x18d 0x1 0xffde 1 +phy raw c45 0x18d 0x1 0xd130 0x53 +phy raw c45 0x18d 0x1 0xd131 0x060b +phy raw c45 0x18d 0x1 0xd134 1 +phy raw c45 0x18d 0x1 0xffde 2 +phy raw c45 0x18d 0x1 0xd130 0x53 +phy raw c45 0x18d 0x1 0xd131 0x060b +phy raw c45 0x18d 0x1 0xd134 1 +phy raw c45 0x18d 0x1 0xffde 3 +phy raw c45 0x18d 0x1 0xd130 0x53 +phy raw c45 0x18d 0x1 0xd131 0x060b +phy raw c45 0x18d 0x1 0xd134 1 + +phy raw c45 0x1a1 0x1 0xffde 0 +phy raw c45 0x1a1 0x1 0xd130 0x55 +phy raw c45 0x1a1 0x1 0xd131 0x0609 +phy raw c45 0x1a1 0x1 0xd134 1 +phy raw c45 0x1a1 0x1 0xffde 1 +phy raw c45 0x1a1 0x1 0xd130 0x54 +phy raw c45 0x1a1 0x1 0xd131 0x060a +phy raw c45 0x1a1 0x1 0xd134 1 +phy raw c45 0x1a1 0x1 0xffde 2 +phy raw c45 0x1a1 0x1 0xd130 0x55 +phy raw c45 0x1a1 0x1 0xd131 0x0609 +phy raw c45 0x1a1 0x1 0xd134 1 +phy raw c45 0x1a1 0x1 0xffde 3 +phy raw c45 0x1a1 0x1 0xd130 0x53 +phy raw c45 0x1a1 0x1 0xd131 0x060b +phy raw c45 0x1a1 0x1 0xd134 1 + +phy raw c45 0x1a5 0x1 0xffde 0 +phy raw c45 0x1a5 0x1 0xd130 0x54 +phy raw c45 0x1a5 0x1 0xd131 0x060a +phy raw c45 0x1a5 0x1 0xd134 1 +phy raw c45 0x1a5 0x1 0xffde 1 +phy raw c45 0x1a5 0x1 0xd130 0x53 +phy raw c45 0x1a5 0x1 0xd131 0x060b +phy raw c45 0x1a5 0x1 0xd134 1 +phy raw c45 0x1a5 0x1 0xffde 2 +phy raw c45 0x1a5 0x1 0xd130 0x53 +phy raw c45 0x1a5 0x1 0xd131 0x060b +phy raw c45 0x1a5 0x1 0xd134 1 +phy raw c45 0x1a5 0x1 0xffde 3 +phy raw c45 0x1a5 0x1 0xd130 0x53 +phy raw c45 0x1a5 0x1 0xd131 0x060b +phy raw c45 0x1a5 0x1 0xd134 1 + +phy raw c45 0x1a9 0x1 0xffde 0 +phy raw c45 0x1a9 0x1 0xd130 0x54 +phy raw c45 0x1a9 0x1 0xd131 0x060a +phy raw c45 0x1a9 0x1 0xd134 1 +phy raw c45 0x1a9 0x1 0xffde 1 +phy raw c45 0x1a9 0x1 0xd130 0x51 +phy raw c45 0x1a9 0x1 0xd131 0x060d +phy raw c45 0x1a9 0x1 0xd134 1 +phy raw c45 0x1a9 0x1 0xffde 2 +phy raw c45 0x1a9 0x1 0xd130 0x52 +phy raw c45 0x1a9 0x1 0xd131 0x060c +phy raw c45 0x1a9 0x1 0xd134 1 +phy raw c45 0x1a9 0x1 0xffde 3 +phy raw c45 0x1a9 0x1 0xd130 0x52 +phy raw c45 0x1a9 0x1 0xd131 0x060c +phy raw c45 0x1a9 0x1 0xd134 1 + +phy raw c45 0x1ad 0x1 0xffde 0 +phy raw c45 0x1ad 0x1 0xd130 0x51 +phy raw c45 0x1ad 0x1 0xd131 0x060d +phy raw c45 0x1ad 0x1 0xd134 1 +phy raw c45 0x1ad 0x1 0xffde 1 +phy raw c45 0x1ad 0x1 0xd130 0x4f +phy raw c45 0x1ad 0x1 0xd131 0x060f +phy raw c45 0x1ad 0x1 0xd134 1 +phy raw c45 0x1ad 0x1 0xffde 2 +phy raw c45 0x1ad 0x1 0xd130 0x4f +phy raw c45 0x1ad 0x1 0xd131 0x060f +phy raw c45 0x1ad 0x1 0xd134 1 +phy raw c45 0x1ad 0x1 0xffde 3 +phy raw c45 0x1ad 0x1 0xd130 0x4f +phy raw c45 0x1ad 0x1 0xd131 0x060f +phy raw c45 0x1ad 0x1 0xd134 1 + +phy raw c45 0x1b1 0x1 0xffde 0 +phy raw c45 0x1b1 0x1 0xd130 0x4f +phy raw c45 0x1b1 0x1 0xd131 0x060f +phy raw c45 0x1b1 0x1 0xd134 1 +phy raw c45 0x1b1 0x1 0xffde 1 +phy raw c45 0x1b1 0x1 0xd130 0x4f +phy raw c45 0x1b1 0x1 0xd131 0x060f +phy raw c45 0x1b1 0x1 0xd134 1 +phy raw c45 0x1b1 0x1 0xffde 2 +phy raw c45 0x1b1 0x1 0xd130 0x4f +phy raw c45 0x1b1 0x1 0xd131 0x060f +phy raw c45 0x1b1 0x1 0xd134 1 +phy raw c45 0x1b1 0x1 0xffde 3 +phy raw c45 0x1b1 0x1 0xd130 0x4f +phy raw c45 0x1b1 0x1 0xd131 0x060f +phy raw c45 0x1b1 0x1 0xd134 1 + +phy raw c45 0x1b5 0x1 0xffde 0 +phy raw c45 0x1b5 0x1 0xd130 0x4e +phy raw c45 0x1b5 0x1 0xd131 0x0610 +phy raw c45 0x1b5 0x1 0xd134 1 +phy raw c45 0x1b5 0x1 0xffde 1 +phy raw c45 0x1b5 0x1 0xd130 0x4d +phy raw c45 0x1b5 0x1 0xd131 0x0611 +phy raw c45 0x1b5 0x1 0xd134 1 +phy raw c45 0x1b5 0x1 0xffde 2 +phy raw c45 0x1b5 0x1 0xd130 0x4d +phy raw c45 0x1b5 0x1 0xd131 0x0611 +phy raw c45 0x1b5 0x1 0xd134 1 +phy raw c45 0x1b5 0x1 0xffde 3 +phy raw c45 0x1b5 0x1 0xd130 0x4d +phy raw c45 0x1b5 0x1 0xd131 0x0611 +phy raw c45 0x1b5 0x1 0xd134 1 + +phy raw c45 0xf1 0x1 0xffde 0 +phy raw c45 0xf1 0x1 0xd130 0x4f +phy raw c45 0xf1 0x1 0xd131 0x060f +phy raw c45 0xf1 0x1 0xd134 1 +phy raw c45 0xf1 0x1 0xffde 1 +phy raw c45 0xf1 0x1 0xd130 0x4f +phy raw c45 0xf1 0x1 0xd131 0x060f +phy raw c45 0xf1 0x1 0xd134 1 +phy raw c45 0xf1 0x1 0xffde 2 +phy raw c45 0xf1 0x1 0xd130 0x4f +phy raw c45 0xf1 0x1 0xd131 0x060f +phy raw c45 0xf1 0x1 0xd134 1 +phy raw c45 0xf1 0x1 0xffde 3 +phy raw c45 0xf1 0x1 0xd130 0x4f +phy raw c45 0xf1 0x1 0xd131 0x060f +phy raw c45 0xf1 0x1 0xd134 1 + +phy raw c45 0xf5 0x1 0xffde 0 +phy raw c45 0xf5 0x1 0xd130 0x4d +phy raw c45 0xf5 0x1 0xd131 0x0611 +phy raw c45 0xf5 0x1 0xd134 1 +phy raw c45 0xf5 0x1 0xffde 1 +phy raw c45 0xf5 0x1 0xd130 0x4d +phy raw c45 0xf5 0x1 0xd131 0x0611 +phy raw c45 0xf5 0x1 0xd134 1 +phy raw c45 0xf5 0x1 0xffde 2 +phy raw c45 0xf5 0x1 0xd130 0x4d +phy raw c45 0xf5 0x1 0xd131 0x0611 +phy raw c45 0xf5 0x1 0xd134 1 +phy raw c45 0xf5 0x1 0xffde 3 +phy raw c45 0xf5 0x1 0xd130 0x4d +phy raw c45 0xf5 0x1 0xd131 0x0611 +phy raw c45 0xf5 0x1 0xd134 1 + +phy raw c45 0x181 0x1 0xffde 0 +phy raw c45 0x181 0x1 0xd130 0x4e +phy raw c45 0x181 0x1 0xd131 0x0610 +phy raw c45 0x181 0x1 0xd134 1 +phy raw c45 0x181 0x1 0xffde 1 +phy raw c45 0x181 0x1 0xd130 0x4e +phy raw c45 0x181 0x1 0xd131 0x0610 +phy raw c45 0x181 0x1 0xd134 1 +phy raw c45 0x181 0x1 0xffde 2 +phy raw c45 0x181 0x1 0xd130 0x4e +phy raw c45 0x181 0x1 0xd131 0x0610 +phy raw c45 0x181 0x1 0xd134 1 +phy raw c45 0x181 0x1 0xffde 3 +phy raw c45 0x181 0x1 0xd130 0x4e +phy raw c45 0x181 0x1 0xd131 0x0610 +phy raw c45 0x181 0x1 0xd134 1 + +phy raw c45 0x189 0x1 0xffde 0 +phy raw c45 0x189 0x1 0xd130 0x4d +phy raw c45 0x189 0x1 0xd131 0x0611 +phy raw c45 0x189 0x1 0xd134 1 +phy raw c45 0x189 0x1 0xffde 1 +phy raw c45 0x189 0x1 0xd130 0x4d +phy raw c45 0x189 0x1 0xd131 0x0611 +phy raw c45 0x189 0x1 0xd134 1 +phy raw c45 0x189 0x1 0xffde 2 +phy raw c45 0x189 0x1 0xd130 0x4d +phy raw c45 0x189 0x1 0xd131 0x0611 +phy raw c45 0x189 0x1 0xd134 1 +phy raw c45 0x189 0x1 0xffde 3 +phy raw c45 0x189 0x1 0xd130 0x4d +phy raw c45 0x189 0x1 0xd131 0x0611 +phy raw c45 0x189 0x1 0xd134 1 + diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers.json.j2 b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_def.j2 b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_def.j2 new file mode 100644 index 0000000000..740cfdf79e --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_def.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "4625920", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_t0.j2 b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..44fcf21887 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_t0.j2 @@ -0,0 +1,45 @@ +{%- 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": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_t1.j2 b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..5fe9cabcfd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "196608", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "33004032", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "12766208", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"33004032" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/l2/config b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/l2/config new file mode 100644 index 0000000000..b2d4a1e805 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/l2/config @@ -0,0 +1,3 @@ +l2_mem_entries=294912 +l3_mem_entries=16384 +l3_alpm_enable=0 diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/l3/config b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/l3/config new file mode 100644 index 0000000000..fff0cf54b0 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/l3/config @@ -0,0 +1,5 @@ +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 +sai_tunnel_support=1 diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/pg_profile_lookup.ini b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/pg_profile_lookup.ini new file mode 100644 index 0000000000..6d91d03ae6 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/pg_profile_lookup.ini @@ -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 diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/platform-def.json b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/platform-def.json new file mode 100644 index 0000000000..ed3f9fcbf2 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/platform-def.json @@ -0,0 +1,32 @@ +{ + "fec-mode": { + "Ethernet0-127": { + "1": { + "10000": [ "none", "fc" ], + "25000": [ "none", "rs" ] + }, + "2": { + "20000": [ "none", "fc" ], + "50000": [ "none", "rs" ] + }, + "4": { + "40000": [ "none", "fc" ], + "100000": [ "none", "rs" ] + } + } + }, + "default-fec-mode": { + "Ethernet0-127": { + "4": { + "40000": "none", + "100000": "rs" + } + } + }, + "native-port-supported-speeds": { + "Ethernet0-127": { + "4": ["100000","40000"] + } + } +} + diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/qos.json.j2 b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/qos.json.j2 new file mode 100644 index 0000000000..ee67c6e262 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config_t1.j2' %} diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/qos_config_t1.j2 b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/qos_config_t1.j2 new file mode 100644 index 0000000000..5fe5324a85 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/qos_config_t1.j2 @@ -0,0 +1,175 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "AZURE": { + "0" : "1", + "1" : "1", + "2" : "1", + "3" : "3", + "4" : "4", + "5" : "2", + "6" : "1", + "7" : "1", + "8" : "0", + "9" : "1", + "10": "1", + "11": "1", + "12": "1", + "13": "1", + "14": "1", + "15": "1", + "16": "1", + "17": "1", + "18": "1", + "19": "1", + "20": "1", + "21": "1", + "22": "1", + "23": "1", + "24": "1", + "25": "1", + "26": "1", + "27": "1", + "28": "1", + "29": "1", + "30": "1", + "31": "1", + "32": "1", + "33": "1", + "34": "1", + "35": "1", + "36": "1", + "37": "1", + "38": "1", + "39": "1", + "40": "1", + "41": "1", + "42": "1", + "43": "1", + "44": "1", + "45": "1", + "46": "5", + "47": "1", + "48": "6", + "49": "1", + "50": "1", + "51": "1", + "52": "1", + "53": "1", + "54": "1", + "55": "1", + "56": "1", + "57": "1", + "58": "1", + "59": "1", + "60": "1", + "61": "1", + "62": "1", + "63": "1" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "14" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "15" + } + }, +{% if asic_type in pfc_to_pg_map_supported_asics %} + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "3": "3", + "4": "4" + } + }, +{% endif %} + "PORT_QOS_MAP": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]", +{% if asic_type in pfc_to_pg_map_supported_asics %} + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]", +{% endif %} + "pfc_enable" : "3,4" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/td3-ix7-32x100G.config.bcm b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/td3-ix7-32x100G.config.bcm index 7361ad2f57..43ccba2a49 100644 --- a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/td3-ix7-32x100G.config.bcm +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/Quanta-IX7-32X/td3-ix7-32x100G.config.bcm @@ -1,37 +1,45 @@ sai_load_hw_config=/etc/bcm/flex/bcm56870_a0_issu/b870.6.4.1/ -bcm_tunnel_term_compatible_mode=1 +#polarity/lanemap is using TH2 style. core_clock_frequency=1525 dpp_clock_ratio=2:3 -parity_enable=0 -mem_cache_enable=0 -l2_mem_entries=40960 -l3_mem_entries=40960 -fpem_mem_entries=16384 -l2xmsg_mode=1 -bcm_num_cos=10 -bcm_stat_interval=2000000 -cdma_timeout_usec=3000000 - -ifp_inports_support_enable=1 -ipv6_lpm_128b_enable=0x1 -l3_max_ecmp_mode=1 -l3_alpm_enable=2 -lpm_scaling_enable=0 - -miim_intr_enable=0 -module_64ports=1 - -schan_intr_enable=0 -skip_L2_USER_ENTRY=0 -stable_size=0x5500000 -tdma_timeout_usec=3000000 - -# portmap settings oversubscribe_mode=1 -pbmp_xport_xe=0x4888888888888888c2222222222222222 + +#RIOT Enable +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=32768 +l3_ecmp_levels=2 +riot_overlay_ecmp_resilient_hash_size=16384 + +pbmp_xport_xe=0x3ffffffffffffffffffffffffffffffffe port_flex_enable=1 +mem_cache_enable=0 + +l3_alpm_ipv6_128b_bkt_rsvd=1 +fpem_mem_entries=0 +ifp_inports_support_enable=1 +l2xmsg_mode=1 + +# Platform specfic +bcm_num_cos=10 +default_cpu_tx_queue=9 +bcm_stat_interval=2000000 +cdma_timeout_usec=3000000 +ipv6_lpm_128b_enable=0x1 +l3_max_ecmp_mode=1 +lpm_scaling_enable=0 +max_vp_lags=0 +miim_intr_enable=0 +module_64ports=1 +schan_intr_enable=0 +stable_size=0x5500000 +tdma_timeout_usec=3000000 +skip_L2_USER_ENTRY=0 +bcm_tunnel_term_compatible_mode=1 +phy_an_c73=1 +# portmap settings portmap_1=1:100 portmap_5=5:100 @@ -69,9 +77,11 @@ portmap_119=117:100 portmap_123=121:100 portmap_127=125:100 -# datapath port -- merlin core -portmap_66=129:10:m -portmap_130=128:10:m +# datapath port -- MerlinCore +#Hide these to prevent SAI from initializing them...they are physically not on system +#front panel +#portmap_66=129:10:m +#portmap_130=128:10:m # loopback port portmap_65=130:10 @@ -79,41 +89,167 @@ portmap_131=131:10 # port order remap dport_map_port_29=1 -dport_map_port_33=2 -dport_map_port_41=3 -dport_map_port_45=4 -dport_map_port_1=5 -dport_map_port_5=6 -dport_map_port_9=7 -dport_map_port_13=8 -dport_map_port_17=9 -dport_map_port_21=10 -dport_map_port_25=11 -dport_map_port_37=12 -dport_map_port_49=13 -dport_map_port_53=14 -dport_map_port_57=15 -dport_map_port_61=16 +dport_map_port_30=2 +dport_map_port_31=3 +dport_map_port_32=4 -dport_map_port_67=17 -dport_map_port_71=18 -dport_map_port_75=19 -dport_map_port_79=20 -dport_map_port_95=21 -dport_map_port_103=22 -dport_map_port_107=23 -dport_map_port_111=24 -dport_map_port_115=25 -dport_map_port_119=26 -dport_map_port_123=27 -dport_map_port_127=28 -dport_map_port_83=29 -dport_map_port_87=30 -dport_map_port_91=31 -dport_map_port_99=32 +dport_map_port_33=5 +dport_map_port_34=6 +dport_map_port_35=7 +dport_map_port_36=8 -dport_map_port_66=33 -dport_map_port_130=34 +dport_map_port_41=9 +dport_map_port_42=10 +dport_map_port_43=11 +dport_map_port_44=12 + +dport_map_port_45=13 +dport_map_port_46=14 +dport_map_port_47=15 +dport_map_port_48=16 + +dport_map_port_1=17 +dport_map_port_2=18 +dport_map_port_3=19 +dport_map_port_4=20 + +dport_map_port_5=21 +dport_map_port_6=22 +dport_map_port_7=23 +dport_map_port_8=24 + +dport_map_port_9=25 +dport_map_port_10=26 +dport_map_port_11=27 +dport_map_port_12=28 + +dport_map_port_13=29 +dport_map_port_14=30 +dport_map_port_15=31 +dport_map_port_16=32 + +dport_map_port_17=33 +dport_map_port_18=34 +dport_map_port_19=35 +dport_map_port_20=36 + +dport_map_port_21=37 +dport_map_port_22=38 +dport_map_port_23=39 +dport_map_port_24=40 + +dport_map_port_25=41 +dport_map_port_26=42 +dport_map_port_27=43 +dport_map_port_28=44 + +dport_map_port_37=45 +dport_map_port_38=46 +dport_map_port_39=47 +dport_map_port_40=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 + +dport_map_port_61=61 +dport_map_port_62=62 +dport_map_port_63=63 +dport_map_port_64=64 + +dport_map_port_67=65 +dport_map_port_68=66 +dport_map_port_69=67 +dport_map_port_70=68 + +dport_map_port_71=69 +dport_map_port_72=70 +dport_map_port_73=71 +dport_map_port_74=72 + +dport_map_port_75=73 +dport_map_port_76=74 +dport_map_port_77=75 +dport_map_port_78=76 + +dport_map_port_79=77 +dport_map_port_80=78 +dport_map_port_81=79 +dport_map_port_82=80 + +dport_map_port_95=81 +dport_map_port_96=82 +dport_map_port_97=83 +dport_map_port_98=84 + +dport_map_port_103=85 +dport_map_port_104=86 +dport_map_port_105=87 +dport_map_port_106=88 + +dport_map_port_107=89 +dport_map_port_108=90 +dport_map_port_109=91 +dport_map_port_110=92 + +dport_map_port_111=93 +dport_map_port_112=94 +dport_map_port_113=95 +dport_map_port_114=96 + +dport_map_port_115=97 +dport_map_port_116=98 +dport_map_port_117=99 +dport_map_port_118=100 + +dport_map_port_119=101 +dport_map_port_120=102 +dport_map_port_121=103 +dport_map_port_122=104 + +dport_map_port_123=105 +dport_map_port_124=106 +dport_map_port_125=107 +dport_map_port_126=108 + +dport_map_port_127=109 +dport_map_port_128=110 +dport_map_port_129=111 +dport_map_port_130=112 + +dport_map_port_83=113 +dport_map_port_84=114 +dport_map_port_85=115 +dport_map_port_86=116 + +dport_map_port_87=117 +dport_map_port_88=118 +dport_map_port_89=119 +dport_map_port_90=120 + +dport_map_port_91=121 +dport_map_port_92=122 +dport_map_port_93=123 +dport_map_port_94=124 + +dport_map_port_99=125 +dport_map_port_100=126 +dport_map_port_101=127 +dport_map_port_102=128 + +dport_map_port_66=129 +dport_map_port_130=130 ### interface setting # TSCF / TSCE interface definition @@ -533,3 +669,8 @@ phy_chain_rx_polarity_flip_physical{98.0}=0x0 phy_chain_rx_polarity_flip_physical{99.0}=0x1 phy_chain_rx_polarity_flip_physical{100.0}=0x0 + +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/custom_led.bin b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/custom_led.bin new file mode 100644 index 0000000000..813addd1ac Binary files /dev/null and b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/custom_led.bin differ diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/led_proc_init.soc b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/led_proc_init.soc old mode 100755 new mode 100644 index 0861486660..f82bbc8e33 --- a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/led_proc_init.soc +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/led_proc_init.soc @@ -1,6 +1,4 @@ -sleep 10 -led stop -sleep 3 +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin led start -sleep 3 -led auto on \ No newline at end of file + +rcload /usr/share/sonic/platform/preemphasis-32x100G.soc diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/eeprom.py b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/eeprom.py index fa34110c04..3752a919cb 100644 --- a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/eeprom.py +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/eeprom.py @@ -16,5 +16,5 @@ class board(eeprom_tlvinfo.TlvInfoDecoder): _TLV_INFO_MAX_LEN = 256 def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/sys/bus/i2c/devices/18-0054/eeprom" + self.eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/fanutil.py b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/fanutil.py new file mode 100644 index 0000000000..dad8dcfedd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/fanutil.py @@ -0,0 +1,110 @@ +# +# fanutil.py +# Platform-specific Fan status interface for SONiC +# + +import logging +import os.path + +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""" + + SYS_FAN_NUM = 6 + NUM_FANS_PERTRAY = 2 + HWMON_PATH = '/sys/class/hwmon/hwmon1/' + FAN_INDEX_START = 21 + + logger = logging.getLogger(__name__) + + def __init__(self, log_level=logging.DEBUG): + FanBase.__init__(self) + self.num_fans = (self.SYS_FAN_NUM * self.NUM_FANS_PERTRAY) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def check_fan_index(self, index): + if index is None: + return False + + if index < 1 or index > self.num_fans: + logging.error("Invalid Fan index:", index) + return False + + return True + + def get_num_fans(self): + return self.num_fans + + def get_status(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + if fantray_speed == '0.0' : + return False + + return True + + def get_presence(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_present_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_present' + fantray_present = self.get_attr_value(self.HWMON_PATH + fantray_present_file) + + if fantray_present == '1' : + return True + + return False + + def get_direction(self, index): + if self.check_fan_index(index) == False: + return None + + fantray_direction_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_direction' + fantray_direction = self.get_attr_value(self.HWMON_PATH + fantray_direction_file) + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if fantray_direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_speed(self, index): + if self.check_fan_index(index) == False: + return 0 + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + return int(float(fantray_speed)) + + + def set_speed(self, val): + logging.error("Not allowed to set fan speed!") + + return False diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/psuutil.py b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/psuutil.py index 5cf06fb5d6..3b07edcda0 100644 --- a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/psuutil.py +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/psuutil.py @@ -1,50 +1,251 @@ -# -# psuutil.py -# Platform-specific PSU status interface for SONiC -# - -import os.path - -try: - from sonic_psu.psu_base import PsuBase -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - - -class PsuUtil(PsuBase): - """Platform-specific PSUutil class""" - - def __init__(self): - PsuBase.__init__(self) - - 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 - """ - MAX_PSUS = 2 - - return MAX_PSUS - - def get_psu_status(self, index): - """ - Retrieves the oprational status of power supply unit (PSU) defined - by 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 = 1 - - return status - - def get_psu_presence(self, index): - """ - Retrieves the presence status of power supply unit (PSU) defined - by 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 = 1 - - return status +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + +import logging +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + HWMON_PATH = '/sys/class/hwmon/hwmon1/' + PSU1_PREFIX = 'power42_' + PSU2_PREFIX = 'power52_' + MAX_PSUS = 2 + def __init__(self): + PsuBase.__init__(self) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def get_attr_filename(self, index, attr): + if (index == 1): + attr_file = self.PSU1_PREFIX + attr + elif (index == 2): + attr_file = self.PSU2_PREFIX + attr + else: + logging.error("Invalid PSU number:", index) + return '' + + return attr_file + + 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 + """ + + return self.MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'present') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check PSU status + if (attr_value == 1): + status = True + return status + + def get_powergood_status(self, index): + status = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_model(self, index): + attr_filename = self.get_attr_filename(index, 'model') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_mfr_id(self, index): + attr_filename = self.get_attr_filename(index, 'mfrid') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_serial(self, index): + attr_filename = self.get_attr_filename(index, 'sn') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_direction(self, index): + if (index == 1): + direction_file = 'fan40_direction' + elif (index == 2): + direction_file = 'fan50_direction' + else: + logging.error("Invalid PSU number:", index) + return None + + direction = self.get_attr_value(self.HWMON_PATH + direction_file) + direction = direction.rstrip() + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_output_voltage(self, index): + if (index == 1): + attr_file = 'in47_input' + elif (index == 2): + attr_file = 'in57_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + voltage = self.get_attr_value(self.HWMON_PATH + attr_file) + voltage = voltage.rstrip() + + if (voltage != 'ERR'): + voltage, dummy = voltage.split('.', 1) + else: + return 0.0 + + return float(voltage)/1000 + + def get_output_current(self, index): + if (index == 1): + attr_file = 'curr39_input' + elif (index == 2): + attr_file = 'curr49_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + current = self.get_attr_value(self.HWMON_PATH + attr_file) + current = current.rstrip() + + if (current != 'ERR'): + current, dummy = current.split('.',1) + else: + return 0.0 + + return float(current)/1000 + + def get_output_power(self, index): + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return 0.0 + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + else: + return 0.0 + + return float(attr_value/1000) + + def get_fan_rpm(self, index, fan_idx): + if (index == 1): + rpm_file = 'fan40_input' + elif (index == 2): + rpm_file = 'fan50_input' + else: + logging.error("Invalid PSU number:", index) + return 0 + + rpm = self.get_attr_value(self.HWMON_PATH + rpm_file) + rpm = rpm.rstrip() + if (rpm != 'ERR'): + rpm = float(rpm) + else: + return 0 + + return int(rpm) diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/sfputil.py b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/sfputil.py index 14b0ef6674..e0302e620f 100644 --- a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/sfputil.py +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/plugins/sfputil.py @@ -21,38 +21,38 @@ class SfpUtil(SfpUtilBase): _port_to_eeprom_mapping = {} _port_to_i2c_mapping = { - 1: 32, - 2: 33, - 3: 34, - 4: 35, - 5: 36, - 6: 37, - 7: 38, - 8: 39, - 9: 40, - 10: 41, - 11: 42, - 12: 43, - 13: 44, - 14: 45, - 15: 46, - 16: 47, - 17: 48, - 18: 49, - 19: 50, - 20: 51, - 21: 52, - 22: 53, - 23: 54, - 24: 55, - 25: 56, - 26: 57, - 27: 58, - 28: 59, - 29: 60, - 30: 61, - 31: 62, - 32: 63, + 1 : 17, + 2 : 18, + 3 : 19, + 4 : 20, + 5 : 21, + 6 : 22, + 7 : 23, + 8 : 24, + 9 : 25, + 10 : 26, + 11 : 27, + 12 : 28, + 13 : 29, + 14 : 30, + 15 : 31, + 16 : 32, + 17 : 33, + 18 : 34, + 19 : 35, + 20 : 36, + 21 : 37, + 22 : 38, + 23 : 39, + 24 : 40, + 25 : 41, + 26 : 42, + 27 : 43, + 28 : 44, + 29 : 45, + 30 : 46, + 31 : 47, + 32 : 48 } @property diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/pmon_daemon_control.json b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..94592fa8ce --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/quanta/x86_64-quanta_ix7_rglbmc-r0/preemphasis-32x100G.soc b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/preemphasis-32x100G.soc new file mode 100644 index 0000000000..5837a6fdce --- /dev/null +++ b/device/quanta/x86_64-quanta_ix7_rglbmc-r0/preemphasis-32x100G.soc @@ -0,0 +1,546 @@ +# Pre-emphasis + +phy raw c45 0xa5 0x1 0xffde 0 +phy raw c45 0xa5 0x1 0xd130 0x41 +phy raw c45 0xa5 0x1 0xd131 0xd +phy raw c45 0xa5 0x1 0xd134 1 +phy raw c45 0xa5 0x1 0xffde 1 +phy raw c45 0xa5 0x1 0xd130 0x41 +phy raw c45 0xa5 0x1 0xd131 0xd +phy raw c45 0xa5 0x1 0xd134 1 +phy raw c45 0xa5 0x1 0xffde 2 +phy raw c45 0xa5 0x1 0xd130 0x41 +phy raw c45 0xa5 0x1 0xd131 0xd +phy raw c45 0xa5 0x1 0xd134 1 +phy raw c45 0xa5 0x1 0xffde 3 +phy raw c45 0xa5 0x1 0xd130 0x41 +phy raw c45 0xa5 0x1 0xd131 0xd +phy raw c45 0xa5 0x1 0xd134 1 + +phy raw c45 0xa9 0x1 0xffde 0 +phy raw c45 0xa9 0x1 0xd130 0x41 +phy raw c45 0xa9 0x1 0xd131 0xd +phy raw c45 0xa9 0x1 0xd134 1 +phy raw c45 0xa9 0x1 0xffde 1 +phy raw c45 0xa9 0x1 0xd130 0x41 +phy raw c45 0xa9 0x1 0xd131 0xd +phy raw c45 0xa9 0x1 0xd134 1 +phy raw c45 0xa9 0x1 0xffde 2 +phy raw c45 0xa9 0x1 0xd130 0x41 +phy raw c45 0xa9 0x1 0xd131 0xd +phy raw c45 0xa9 0x1 0xd134 1 +phy raw c45 0xa9 0x1 0xffde 3 +phy raw c45 0xa9 0x1 0xd130 0x41 +phy raw c45 0xa9 0x1 0xd131 0xd +phy raw c45 0xa9 0x1 0xd134 1 + +phy raw c45 0xc1 0x1 0xffde 0 +phy raw c45 0xc1 0x1 0xd130 0x41 +phy raw c45 0xc1 0x1 0xd131 0xd +phy raw c45 0xc1 0x1 0xd134 1 +phy raw c45 0xc1 0x1 0xffde 1 +phy raw c45 0xc1 0x1 0xd130 0x41 +phy raw c45 0xc1 0x1 0xd131 0xd +phy raw c45 0xc1 0x1 0xd134 1 +phy raw c45 0xc1 0x1 0xffde 2 +phy raw c45 0xc1 0x1 0xd130 0x41 +phy raw c45 0xc1 0x1 0xd131 0xd +phy raw c45 0xc1 0x1 0xd134 1 +phy raw c45 0xc1 0x1 0xffde 3 +phy raw c45 0xc1 0x1 0xd130 0x41 +phy raw c45 0xc1 0x1 0xd131 0xd +phy raw c45 0xc1 0x1 0xd134 1 + +phy raw c45 0xc5 0x1 0xffde 0 +phy raw c45 0xc5 0x1 0xd130 0x41 +phy raw c45 0xc5 0x1 0xd131 0xd +phy raw c45 0xc5 0x1 0xd134 1 +phy raw c45 0xc5 0x1 0xffde 1 +phy raw c45 0xc5 0x1 0xd130 0x41 +phy raw c45 0xc5 0x1 0xd131 0xd +phy raw c45 0xc5 0x1 0xd134 1 +phy raw c45 0xc5 0x1 0xffde 2 +phy raw c45 0xc5 0x1 0xd130 0x41 +phy raw c45 0xc5 0x1 0xd131 0xd +phy raw c45 0xc5 0x1 0xd134 1 +phy raw c45 0xc5 0x1 0xffde 3 +phy raw c45 0xc5 0x1 0xd130 0x41 +phy raw c45 0xc5 0x1 0xd131 0xd +phy raw c45 0xc5 0x1 0xd134 1 + +phy raw c45 0x81 0x1 0xffde 0 +phy raw c45 0x81 0x1 0xd130 0x41 +phy raw c45 0x81 0x1 0xd131 0xd +phy raw c45 0x81 0x1 0xd134 1 +phy raw c45 0x81 0x1 0xffde 1 +phy raw c45 0x81 0x1 0xd130 0x41 +phy raw c45 0x81 0x1 0xd131 0xd +phy raw c45 0x81 0x1 0xd134 1 +phy raw c45 0x81 0x1 0xffde 2 +phy raw c45 0x81 0x1 0xd130 0x41 +phy raw c45 0x81 0x1 0xd131 0xd +phy raw c45 0x81 0x1 0xd134 1 +phy raw c45 0x81 0x1 0xffde 3 +phy raw c45 0x81 0x1 0xd130 0x41 +phy raw c45 0x81 0x1 0xd131 0xd +phy raw c45 0x81 0x1 0xd134 1 + +phy raw c45 0x85 0x1 0xffde 0 +phy raw c45 0x85 0x1 0xd130 0x41 +phy raw c45 0x85 0x1 0xd131 0xd +phy raw c45 0x85 0x1 0xd134 1 +phy raw c45 0x85 0x1 0xffde 1 +phy raw c45 0x85 0x1 0xd130 0x41 +phy raw c45 0x85 0x1 0xd131 0xd +phy raw c45 0x85 0x1 0xd134 1 +phy raw c45 0x85 0x1 0xffde 2 +phy raw c45 0x85 0x1 0xd130 0x41 +phy raw c45 0x85 0x1 0xd131 0xd +phy raw c45 0x85 0x1 0xd134 1 +phy raw c45 0x85 0x1 0xffde 3 +phy raw c45 0x85 0x1 0xd130 0x41 +phy raw c45 0x85 0x1 0xd131 0xd +phy raw c45 0x85 0x1 0xd134 1 + +phy raw c45 0x89 0x1 0xffde 0 +phy raw c45 0x89 0x1 0xd130 0x41 +phy raw c45 0x89 0x1 0xd131 0xd +phy raw c45 0x89 0x1 0xd134 1 +phy raw c45 0x89 0x1 0xffde 1 +phy raw c45 0x89 0x1 0xd130 0x41 +phy raw c45 0x89 0x1 0xd131 0xd +phy raw c45 0x89 0x1 0xd134 1 +phy raw c45 0x89 0x1 0xffde 2 +phy raw c45 0x89 0x1 0xd130 0x41 +phy raw c45 0x89 0x1 0xd131 0xd +phy raw c45 0x89 0x1 0xd134 1 +phy raw c45 0x89 0x1 0xffde 3 +phy raw c45 0x89 0x1 0xd130 0x41 +phy raw c45 0x89 0x1 0xd131 0xd +phy raw c45 0x89 0x1 0xd134 1 + +phy raw c45 0x8d 0x1 0xffde 0 +phy raw c45 0x8d 0x1 0xd130 0x41 +phy raw c45 0x8d 0x1 0xd131 0xd +phy raw c45 0x8d 0x1 0xd134 1 +phy raw c45 0x8d 0x1 0xffde 1 +phy raw c45 0x8d 0x1 0xd130 0x41 +phy raw c45 0x8d 0x1 0xd131 0xd +phy raw c45 0x8d 0x1 0xd134 1 +phy raw c45 0x8d 0x1 0xffde 2 +phy raw c45 0x8d 0x1 0xd130 0x41 +phy raw c45 0x8d 0x1 0xd131 0xd +phy raw c45 0x8d 0x1 0xd134 1 +phy raw c45 0x8d 0x1 0xffde 3 +phy raw c45 0x8d 0x1 0xd130 0x41 +phy raw c45 0x8d 0x1 0xd131 0xd +phy raw c45 0x8d 0x1 0xd134 1 + +phy raw c45 0x91 0x1 0xffde 0 +phy raw c45 0x91 0x1 0xd130 0x41 +phy raw c45 0x91 0x1 0xd131 0x0408 +phy raw c45 0x91 0x1 0xd134 1 +phy raw c45 0x91 0x1 0xffde 1 +phy raw c45 0x91 0x1 0xd130 0x41 +phy raw c45 0x91 0x1 0xd131 0x0408 +phy raw c45 0x91 0x1 0xd134 1 +phy raw c45 0x91 0x1 0xffde 2 +phy raw c45 0x91 0x1 0xd130 0x41 +phy raw c45 0x91 0x1 0xd131 0x0408 +phy raw c45 0x91 0x1 0xd134 1 +phy raw c45 0x91 0x1 0xffde 3 +phy raw c45 0x91 0x1 0xd130 0x41 +phy raw c45 0x91 0x1 0xd131 0x0408 +phy raw c45 0x91 0x1 0xd134 1 + +phy raw c45 0x95 0x1 0xffde 0 +phy raw c45 0x95 0x1 0xd130 0x41 +phy raw c45 0x95 0x1 0xd131 0x0307 +phy raw c45 0x95 0x1 0xd134 1 +phy raw c45 0x95 0x1 0xffde 1 +phy raw c45 0x95 0x1 0xd130 0x41 +phy raw c45 0x95 0x1 0xd131 0x0307 +phy raw c45 0x95 0x1 0xd134 1 +phy raw c45 0x95 0x1 0xffde 2 +phy raw c45 0x95 0x1 0xd130 0x41 +phy raw c45 0x95 0x1 0xd131 0x0307 +phy raw c45 0x95 0x1 0xd134 1 +phy raw c45 0x95 0x1 0xffde 3 +phy raw c45 0x95 0x1 0xd130 0x41 +phy raw c45 0x95 0x1 0xd131 0x0307 +phy raw c45 0x95 0x1 0xd134 1 + +phy raw c45 0xa1 0x1 0xffde 0 +phy raw c45 0xa1 0x1 0xd130 0x41 +phy raw c45 0xa1 0x1 0xd131 0x0307 +phy raw c45 0xa1 0x1 0xd134 1 +phy raw c45 0xa1 0x1 0xffde 1 +phy raw c45 0xa1 0x1 0xd130 0x41 +phy raw c45 0xa1 0x1 0xd131 0x0307 +phy raw c45 0xa1 0x1 0xd134 1 +phy raw c45 0xa1 0x1 0xffde 2 +phy raw c45 0xa1 0x1 0xd130 0x41 +phy raw c45 0xa1 0x1 0xd131 0x0307 +phy raw c45 0xa1 0x1 0xd134 1 +phy raw c45 0xa1 0x1 0xffde 3 +phy raw c45 0xa1 0x1 0xd130 0x41 +phy raw c45 0xa1 0x1 0xd131 0x0307 +phy raw c45 0xa1 0x1 0xd134 1 + +phy raw c45 0xad 0x1 0xffde 0 +phy raw c45 0xad 0x1 0xd130 0x41 +phy raw c45 0xad 0x1 0xd131 0x0307 +phy raw c45 0xad 0x1 0xd134 1 +phy raw c45 0xad 0x1 0xffde 1 +phy raw c45 0xad 0x1 0xd130 0x41 +phy raw c45 0xad 0x1 0xd131 0x0307 +phy raw c45 0xad 0x1 0xd134 1 +phy raw c45 0xad 0x1 0xffde 2 +phy raw c45 0xad 0x1 0xd130 0x41 +phy raw c45 0xad 0x1 0xd131 0x0307 +phy raw c45 0xad 0x1 0xd134 1 +phy raw c45 0xad 0x1 0xffde 3 +phy raw c45 0xad 0x1 0xd130 0x41 +phy raw c45 0xad 0x1 0xd131 0x0307 +phy raw c45 0xad 0x1 0xd134 1 + +phy raw c45 0xc9 0x1 0xffde 0 +phy raw c45 0xc9 0x1 0xd130 0x41 +phy raw c45 0xc9 0x1 0xd131 0x0307 +phy raw c45 0xc9 0x1 0xd134 1 +phy raw c45 0xc9 0x1 0xffde 1 +phy raw c45 0xc9 0x1 0xd130 0x41 +phy raw c45 0xc9 0x1 0xd131 0x0307 +phy raw c45 0xc9 0x1 0xd134 1 +phy raw c45 0xc9 0x1 0xffde 2 +phy raw c45 0xc9 0x1 0xd130 0x41 +phy raw c45 0xc9 0x1 0xd131 0x0307 +phy raw c45 0xc9 0x1 0xd134 1 +phy raw c45 0xc9 0x1 0xffde 3 +phy raw c45 0xc9 0x1 0xd130 0x41 +phy raw c45 0xc9 0x1 0xd131 0x0307 +phy raw c45 0xc9 0x1 0xd134 1 + +phy raw c45 0xcd 0x1 0xffde 0 +phy raw c45 0xcd 0x1 0xd130 0x41 +phy raw c45 0xcd 0x1 0xd131 0x0307 +phy raw c45 0xcd 0x1 0xd134 1 +phy raw c45 0xcd 0x1 0xffde 1 +phy raw c45 0xcd 0x1 0xd130 0x41 +phy raw c45 0xcd 0x1 0xd131 0x0307 +phy raw c45 0xcd 0x1 0xd134 1 +phy raw c45 0xcd 0x1 0xffde 2 +phy raw c45 0xcd 0x1 0xd130 0x41 +phy raw c45 0xcd 0x1 0xd131 0x0307 +phy raw c45 0xcd 0x1 0xd134 1 +phy raw c45 0xcd 0x1 0xffde 3 +phy raw c45 0xcd 0x1 0xd130 0x41 +phy raw c45 0xcd 0x1 0xd131 0x0307 +phy raw c45 0xcd 0x1 0xd134 1 + +phy raw c45 0xd1 0x1 0xffde 0 +phy raw c45 0xd1 0x1 0xd130 0x41 +phy raw c45 0xd1 0x1 0xd131 0x0307 +phy raw c45 0xd1 0x1 0xd134 1 +phy raw c45 0xd1 0x1 0xffde 1 +phy raw c45 0xd1 0x1 0xd130 0x41 +phy raw c45 0xd1 0x1 0xd131 0x0307 +phy raw c45 0xd1 0x1 0xd134 1 +phy raw c45 0xd1 0x1 0xffde 2 +phy raw c45 0xd1 0x1 0xd130 0x41 +phy raw c45 0xd1 0x1 0xd131 0x0307 +phy raw c45 0xd1 0x1 0xd134 1 +phy raw c45 0xd1 0x1 0xffde 3 +phy raw c45 0xd1 0x1 0xd130 0x41 +phy raw c45 0xd1 0x1 0xd131 0x0307 +phy raw c45 0xd1 0x1 0xd134 1 + +phy raw c45 0xd5 0x1 0xffde 0 +phy raw c45 0xd5 0x1 0xd130 0x41 +phy raw c45 0xd5 0x1 0xd131 0x0307 +phy raw c45 0xd5 0x1 0xd134 1 +phy raw c45 0xd5 0x1 0xffde 1 +phy raw c45 0xd5 0x1 0xd130 0x41 +phy raw c45 0xd5 0x1 0xd131 0x0307 +phy raw c45 0xd5 0x1 0xd134 1 +phy raw c45 0xd5 0x1 0xffde 2 +phy raw c45 0xd5 0x1 0xd130 0x41 +phy raw c45 0xd5 0x1 0xd131 0x0307 +phy raw c45 0xd5 0x1 0xd134 1 +phy raw c45 0xd5 0x1 0xffde 3 +phy raw c45 0xd5 0x1 0xd130 0x41 +phy raw c45 0xd5 0x1 0xd131 0x0307 +phy raw c45 0xd5 0x1 0xd134 1 + +phy raw c45 0xe1 0x1 0xffde 0 +phy raw c45 0xe1 0x1 0xd130 0x41 +phy raw c45 0xe1 0x1 0xd131 0x0307 +phy raw c45 0xe1 0x1 0xd134 1 +phy raw c45 0xe1 0x1 0xffde 1 +phy raw c45 0xe1 0x1 0xd130 0x41 +phy raw c45 0xe1 0x1 0xd131 0x0307 +phy raw c45 0xe1 0x1 0xd134 1 +phy raw c45 0xe1 0x1 0xffde 2 +phy raw c45 0xe1 0x1 0xd130 0x41 +phy raw c45 0xe1 0x1 0xd131 0x0307 +phy raw c45 0xe1 0x1 0xd134 1 +phy raw c45 0xe1 0x1 0xffde 3 +phy raw c45 0xe1 0x1 0xd130 0x41 +phy raw c45 0xe1 0x1 0xd131 0x0307 +phy raw c45 0xe1 0x1 0xd134 1 + +phy raw c45 0xe5 0x1 0xffde 0 +phy raw c45 0xe5 0x1 0xd130 0x41 +phy raw c45 0xe5 0x1 0xd131 0x0307 +phy raw c45 0xe5 0x1 0xd134 1 +phy raw c45 0xe5 0x1 0xffde 1 +phy raw c45 0xe5 0x1 0xd130 0x41 +phy raw c45 0xe5 0x1 0xd131 0x0307 +phy raw c45 0xe5 0x1 0xd134 1 +phy raw c45 0xe5 0x1 0xffde 2 +phy raw c45 0xe5 0x1 0xd130 0x41 +phy raw c45 0xe5 0x1 0xd131 0x0307 +phy raw c45 0xe5 0x1 0xd134 1 +phy raw c45 0xe5 0x1 0xffde 3 +phy raw c45 0xe5 0x1 0xd130 0x41 +phy raw c45 0xe5 0x1 0xd131 0x0307 +phy raw c45 0xe5 0x1 0xd134 1 + +phy raw c45 0xe9 0x1 0xffde 0 +phy raw c45 0xe9 0x1 0xd130 0x41 +phy raw c45 0xe9 0x1 0xd131 0x0307 +phy raw c45 0xe9 0x1 0xd134 1 +phy raw c45 0xe9 0x1 0xffde 1 +phy raw c45 0xe9 0x1 0xd130 0x41 +phy raw c45 0xe9 0x1 0xd131 0x0307 +phy raw c45 0xe9 0x1 0xd134 1 +phy raw c45 0xe9 0x1 0xffde 2 +phy raw c45 0xe9 0x1 0xd130 0x41 +phy raw c45 0xe9 0x1 0xd131 0x0307 +phy raw c45 0xe9 0x1 0xd134 1 +phy raw c45 0xe9 0x1 0xffde 3 +phy raw c45 0xe9 0x1 0xd130 0x41 +phy raw c45 0xe9 0x1 0xd131 0x0307 +phy raw c45 0xe9 0x1 0xd134 1 + +phy raw c45 0xed 0x1 0xffde 0 +phy raw c45 0xed 0x1 0xd130 0x41 +phy raw c45 0xed 0x1 0xd131 0xb +phy raw c45 0xed 0x1 0xd134 1 +phy raw c45 0xed 0x1 0xffde 1 +phy raw c45 0xed 0x1 0xd130 0x41 +phy raw c45 0xed 0x1 0xd131 0xb +phy raw c45 0xed 0x1 0xd134 1 +phy raw c45 0xed 0x1 0xffde 2 +phy raw c45 0xed 0x1 0xd130 0x41 +phy raw c45 0xed 0x1 0xd131 0xb +phy raw c45 0xed 0x1 0xd134 1 +phy raw c45 0xed 0x1 0xffde 3 +phy raw c45 0xed 0x1 0xd130 0x41 +phy raw c45 0xed 0x1 0xd131 0xb +phy raw c45 0xed 0x1 0xd134 1 + +phy raw c45 0x185 0x1 0xffde 0 +phy raw c45 0x185 0x1 0xd130 0x41 +phy raw c45 0x185 0x1 0xd131 0x0307 +phy raw c45 0x185 0x1 0xd134 1 +phy raw c45 0x185 0x1 0xffde 1 +phy raw c45 0x185 0x1 0xd130 0x41 +phy raw c45 0x185 0x1 0xd131 0x0307 +phy raw c45 0x185 0x1 0xd134 1 +phy raw c45 0x185 0x1 0xffde 2 +phy raw c45 0x185 0x1 0xd130 0x41 +phy raw c45 0x185 0x1 0xd131 0x0307 +phy raw c45 0x185 0x1 0xd134 1 +phy raw c45 0x185 0x1 0xffde 3 +phy raw c45 0x185 0x1 0xd130 0x41 +phy raw c45 0x185 0x1 0xd131 0x0307 +phy raw c45 0x185 0x1 0xd134 1 + +phy raw c45 0x18d 0x1 0xffde 0 +phy raw c45 0x18d 0x1 0xd130 0x41 +phy raw c45 0x18d 0x1 0xd131 0x0307 +phy raw c45 0x18d 0x1 0xd134 1 +phy raw c45 0x18d 0x1 0xffde 1 +phy raw c45 0x18d 0x1 0xd130 0x41 +phy raw c45 0x18d 0x1 0xd131 0x0307 +phy raw c45 0x18d 0x1 0xd134 1 +phy raw c45 0x18d 0x1 0xffde 2 +phy raw c45 0x18d 0x1 0xd130 0x41 +phy raw c45 0x18d 0x1 0xd131 0x0307 +phy raw c45 0x18d 0x1 0xd134 1 +phy raw c45 0x18d 0x1 0xffde 3 +phy raw c45 0x18d 0x1 0xd130 0x41 +phy raw c45 0x18d 0x1 0xd131 0x0307 +phy raw c45 0x18d 0x1 0xd134 1 + +phy raw c45 0x1a1 0x1 0xffde 0 +phy raw c45 0x1a1 0x1 0xd130 0x41 +phy raw c45 0x1a1 0x1 0xd131 0x0408 +phy raw c45 0x1a1 0x1 0xd134 1 +phy raw c45 0x1a1 0x1 0xffde 1 +phy raw c45 0x1a1 0x1 0xd130 0x41 +phy raw c45 0x1a1 0x1 0xd131 0x0408 +phy raw c45 0x1a1 0x1 0xd134 1 +phy raw c45 0x1a1 0x1 0xffde 2 +phy raw c45 0x1a1 0x1 0xd130 0x41 +phy raw c45 0x1a1 0x1 0xd131 0x0408 +phy raw c45 0x1a1 0x1 0xd134 1 +phy raw c45 0x1a1 0x1 0xffde 3 +phy raw c45 0x1a1 0x1 0xd130 0x41 +phy raw c45 0x1a1 0x1 0xd131 0x0408 +phy raw c45 0x1a1 0x1 0xd134 1 + +phy raw c45 0x1a5 0x1 0xffde 0 +phy raw c45 0x1a5 0x1 0xd130 0x41 +phy raw c45 0x1a5 0x1 0xd131 0x0408 +phy raw c45 0x1a5 0x1 0xd134 1 +phy raw c45 0x1a5 0x1 0xffde 1 +phy raw c45 0x1a5 0x1 0xd130 0x41 +phy raw c45 0x1a5 0x1 0xd131 0x0408 +phy raw c45 0x1a5 0x1 0xd134 1 +phy raw c45 0x1a5 0x1 0xffde 2 +phy raw c45 0x1a5 0x1 0xd130 0x41 +phy raw c45 0x1a5 0x1 0xd131 0x0408 +phy raw c45 0x1a5 0x1 0xd134 1 +phy raw c45 0x1a5 0x1 0xffde 3 +phy raw c45 0x1a5 0x1 0xd130 0x41 +phy raw c45 0x1a5 0x1 0xd131 0x0408 +phy raw c45 0x1a5 0x1 0xd134 1 + +phy raw c45 0x1a9 0x1 0xffde 0 +phy raw c45 0x1a9 0x1 0xd130 0x41 +phy raw c45 0x1a9 0x1 0xd131 0xb +phy raw c45 0x1a9 0x1 0xd134 1 +phy raw c45 0x1a9 0x1 0xffde 1 +phy raw c45 0x1a9 0x1 0xd130 0x41 +phy raw c45 0x1a9 0x1 0xd131 0xb +phy raw c45 0x1a9 0x1 0xd134 1 +phy raw c45 0x1a9 0x1 0xffde 2 +phy raw c45 0x1a9 0x1 0xd130 0x41 +phy raw c45 0x1a9 0x1 0xd131 0xb +phy raw c45 0x1a9 0x1 0xd134 1 +phy raw c45 0x1a9 0x1 0xffde 3 +phy raw c45 0x1a9 0x1 0xd130 0x41 +phy raw c45 0x1a9 0x1 0xd131 0xb +phy raw c45 0x1a9 0x1 0xd134 1 + +phy raw c45 0x1ad 0x1 0xffde 0 +phy raw c45 0x1ad 0x1 0xd130 0x41 +phy raw c45 0x1ad 0x1 0xd131 0xc +phy raw c45 0x1ad 0x1 0xd134 1 +phy raw c45 0x1ad 0x1 0xffde 1 +phy raw c45 0x1ad 0x1 0xd130 0x41 +phy raw c45 0x1ad 0x1 0xd131 0xc +phy raw c45 0x1ad 0x1 0xd134 1 +phy raw c45 0x1ad 0x1 0xffde 2 +phy raw c45 0x1ad 0x1 0xd130 0x41 +phy raw c45 0x1ad 0x1 0xd131 0xc +phy raw c45 0x1ad 0x1 0xd134 1 +phy raw c45 0x1ad 0x1 0xffde 3 +phy raw c45 0x1ad 0x1 0xd130 0x41 +phy raw c45 0x1ad 0x1 0xd131 0xc +phy raw c45 0x1ad 0x1 0xd134 1 + +phy raw c45 0x1b1 0x1 0xffde 0 +phy raw c45 0x1b1 0x1 0xd130 0x41 +phy raw c45 0x1b1 0x1 0xd131 0xd +phy raw c45 0x1b1 0x1 0xd134 1 +phy raw c45 0x1b1 0x1 0xffde 1 +phy raw c45 0x1b1 0x1 0xd130 0x41 +phy raw c45 0x1b1 0x1 0xd131 0xd +phy raw c45 0x1b1 0x1 0xd134 1 +phy raw c45 0x1b1 0x1 0xffde 2 +phy raw c45 0x1b1 0x1 0xd130 0x41 +phy raw c45 0x1b1 0x1 0xd131 0xd +phy raw c45 0x1b1 0x1 0xd134 1 +phy raw c45 0x1b1 0x1 0xffde 3 +phy raw c45 0x1b1 0x1 0xd130 0x41 +phy raw c45 0x1b1 0x1 0xd131 0xd +phy raw c45 0x1b1 0x1 0xd134 1 + +phy raw c45 0x1b5 0x1 0xffde 0 +phy raw c45 0x1b5 0x1 0xd130 0x41 +phy raw c45 0x1b5 0x1 0xd131 0xf +phy raw c45 0x1b5 0x1 0xd134 1 +phy raw c45 0x1b5 0x1 0xffde 1 +phy raw c45 0x1b5 0x1 0xd130 0x41 +phy raw c45 0x1b5 0x1 0xd131 0xf +phy raw c45 0x1b5 0x1 0xd134 1 +phy raw c45 0x1b5 0x1 0xffde 2 +phy raw c45 0x1b5 0x1 0xd130 0x41 +phy raw c45 0x1b5 0x1 0xd131 0xf +phy raw c45 0x1b5 0x1 0xd134 1 +phy raw c45 0x1b5 0x1 0xffde 3 +phy raw c45 0x1b5 0x1 0xd130 0x41 +phy raw c45 0x1b5 0x1 0xd131 0xf +phy raw c45 0x1b5 0x1 0xd134 1 + +phy raw c45 0xf1 0x1 0xffde 0 +phy raw c45 0xf1 0x1 0xd130 0x41 +phy raw c45 0xf1 0x1 0xd131 0xd +phy raw c45 0xf1 0x1 0xd134 1 +phy raw c45 0xf1 0x1 0xffde 1 +phy raw c45 0xf1 0x1 0xd130 0x41 +phy raw c45 0xf1 0x1 0xd131 0xd +phy raw c45 0xf1 0x1 0xd134 1 +phy raw c45 0xf1 0x1 0xffde 2 +phy raw c45 0xf1 0x1 0xd130 0x41 +phy raw c45 0xf1 0x1 0xd131 0xd +phy raw c45 0xf1 0x1 0xd134 1 +phy raw c45 0xf1 0x1 0xffde 3 +phy raw c45 0xf1 0x1 0xd130 0x41 +phy raw c45 0xf1 0x1 0xd131 0xd +phy raw c45 0xf1 0x1 0xd134 1 + +phy raw c45 0xf5 0x1 0xffde 0 +phy raw c45 0xf5 0x1 0xd130 0x41 +phy raw c45 0xf5 0x1 0xd131 0xf +phy raw c45 0xf5 0x1 0xd134 1 +phy raw c45 0xf5 0x1 0xffde 1 +phy raw c45 0xf5 0x1 0xd130 0x41 +phy raw c45 0xf5 0x1 0xd131 0xf +phy raw c45 0xf5 0x1 0xd134 1 +phy raw c45 0xf5 0x1 0xffde 2 +phy raw c45 0xf5 0x1 0xd130 0x41 +phy raw c45 0xf5 0x1 0xd131 0xf +phy raw c45 0xf5 0x1 0xd134 1 +phy raw c45 0xf5 0x1 0xffde 3 +phy raw c45 0xf5 0x1 0xd130 0x41 +phy raw c45 0xf5 0x1 0xd131 0xf +phy raw c45 0xf5 0x1 0xd134 1 + +phy raw c45 0x181 0x1 0xffde 0 +phy raw c45 0x181 0x1 0xd130 0x41 +phy raw c45 0x181 0x1 0xd131 0xd +phy raw c45 0x181 0x1 0xd134 1 +phy raw c45 0x181 0x1 0xffde 1 +phy raw c45 0x181 0x1 0xd130 0x41 +phy raw c45 0x181 0x1 0xd131 0xd +phy raw c45 0x181 0x1 0xd134 1 +phy raw c45 0x181 0x1 0xffde 2 +phy raw c45 0x181 0x1 0xd130 0x41 +phy raw c45 0x181 0x1 0xd131 0xd +phy raw c45 0x181 0x1 0xd134 1 +phy raw c45 0x181 0x1 0xffde 3 +phy raw c45 0x181 0x1 0xd130 0x41 +phy raw c45 0x181 0x1 0xd131 0xd +phy raw c45 0x181 0x1 0xd134 1 + +phy raw c45 0x189 0x1 0xffde 0 +phy raw c45 0x189 0x1 0xd130 0x41 +phy raw c45 0x189 0x1 0xd131 0xe +phy raw c45 0x189 0x1 0xd134 1 +phy raw c45 0x189 0x1 0xffde 1 +phy raw c45 0x189 0x1 0xd130 0x41 +phy raw c45 0x189 0x1 0xd131 0xe +phy raw c45 0x189 0x1 0xd134 1 +phy raw c45 0x189 0x1 0xffde 2 +phy raw c45 0x189 0x1 0xd130 0x41 +phy raw c45 0x189 0x1 0xd131 0xe +phy raw c45 0x189 0x1 0xd134 1 +phy raw c45 0x189 0x1 0xffde 3 +phy raw c45 0x189 0x1 0xd130 0x41 +phy raw c45 0x189 0x1 0xd131 0xe +phy raw c45 0x189 0x1 0xd134 1 + diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers.json.j2 b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_def.j2 b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_def.j2 new file mode 100644 index 0000000000..740cfdf79e --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_def.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "4625920", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_t0.j2 b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..44fcf21887 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_t0.j2 @@ -0,0 +1,45 @@ +{%- 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": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_t1.j2 b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..5fe9cabcfd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "196608", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "33004032", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "12766208", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"33004032" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/l2/config b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/l2/config new file mode 100644 index 0000000000..b2d4a1e805 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/l2/config @@ -0,0 +1,3 @@ +l2_mem_entries=294912 +l3_mem_entries=16384 +l3_alpm_enable=0 diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/l3/config b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/l3/config new file mode 100644 index 0000000000..fff0cf54b0 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/l3/config @@ -0,0 +1,5 @@ +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 +sai_tunnel_support=1 diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/pg_profile_lookup.ini b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/pg_profile_lookup.ini new file mode 100644 index 0000000000..6d91d03ae6 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/pg_profile_lookup.ini @@ -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 diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/platform-def.json b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/platform-def.json new file mode 100644 index 0000000000..f052663135 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/platform-def.json @@ -0,0 +1,84 @@ +{ + "port-group": { + "1": { + "members": "Ethernet0-3", + "valid_speeds": ["25000",["10000","1000"]] + }, + "2": { + "members": "Ethernet4-7", + "valid_speeds": ["25000",["10000","1000"]] + }, + "3": { + "members": "Ethernet8-11", + "valid_speeds": ["25000",["10000","1000"]] + }, + "4": { + "members": "Ethernet12-15", + "valid_speeds": ["25000",["10000","1000"]] + }, + "5": { + "members": "Ethernet16-19", + "valid_speeds": ["25000",["10000","1000"]] + }, + "6": { + "members": "Ethernet20-23", + "valid_speeds": ["25000",["10000","1000"]] + }, + "7": { + "members": "Ethernet24-27", + "valid_speeds": ["25000",["10000","1000"]] + }, + "8": { + "members": "Ethernet28-31", + "valid_speeds": ["25000",["10000","1000"]] + }, + "9": { + "members": "Ethernet32-35", + "valid_speeds": ["25000",["10000","1000"]] + }, + "10": { + "members": "Ethernet36-39", + "valid_speeds": ["25000",["10000","1000"]] + }, + "11": { + "members": "Ethernet40-43", + "valid_speeds": ["25000",["10000","1000"]] + }, + "12": { + "members": "Ethernet44-47", + "valid_speeds": ["25000",["10000","1000"]] + } + }, + "fec-mode": { + "Ethernet0-47": { + "1": { + "1000": [ "none" ], + "10000": [ "none", "fc" ], + "25000": [ "none", "rs" ] + } + }, + "Ethernet48-79": { + "1": { + "10000": [ "none", "fc" ], + "25000": [ "none", "rs" ] + }, + "2": { + "20000": [ "none", "fc" ], + "50000": [ "none", "rs" ] + }, + "4": { + "40000": [ "none", "fc" ], + "100000": [ "none", "rs" ] + } + } + }, + "native-port-supported-speeds": { + "Ethernet0-47": { + "1": ["25000","10000","1000"] + }, + "Ethernet48-79": { + "4": ["100000","40000"] + } + } +} + diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/port_config.ini b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/port_config.ini index c9dd2fb999..c2808b2a5e 100644 --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/port_config.ini +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/port_config.ini @@ -1,57 +1,57 @@ -# name lanes alias index speed -Ethernet0 60 twentyfiveGigE1 1 25000 -Ethernet1 59 twentyfiveGigE2 2 25000 -Ethernet2 58 twentyfiveGigE3 3 25000 -Ethernet3 57 twentyfiveGigE4 4 25000 -Ethernet4 64 twentyfiveGigE5 5 25000 -Ethernet5 63 twentyfiveGigE6 6 25000 -Ethernet6 62 twentyfiveGigE7 7 25000 -Ethernet7 61 twentyfiveGigE8 8 25000 -Ethernet8 49 twentyfiveGigE9 9 25000 -Ethernet9 50 twentyfiveGigE10 10 25000 -Ethernet10 51 twentyfiveGigE11 11 25000 -Ethernet11 52 twentyfiveGigE12 12 25000 -Ethernet12 4 twentyfiveGigE13 13 25000 -Ethernet13 3 twentyfiveGigE14 14 25000 -Ethernet14 2 twentyfiveGigE15 15 25000 -Ethernet15 1 twentyfiveGigE16 16 25000 -Ethernet16 8 twentyfiveGigE17 17 25000 -Ethernet17 7 twentyfiveGigE18 18 25000 -Ethernet18 6 twentyfiveGigE19 19 25000 -Ethernet19 5 twentyfiveGigE20 20 25000 -Ethernet20 16 twentyfiveGigE21 21 25000 -Ethernet21 15 twentyfiveGigE22 22 25000 -Ethernet22 14 twentyfiveGigE23 23 25000 -Ethernet23 13 twentyfiveGigE24 24 25000 -Ethernet24 24 twentyfiveGigE25 25 25000 -Ethernet25 23 twentyfiveGigE26 26 25000 -Ethernet26 22 twentyfiveGigE27 27 25000 -Ethernet27 21 twentyfiveGigE28 28 25000 -Ethernet28 32 twentyfiveGigE29 29 25000 -Ethernet29 31 twentyfiveGigE30 30 25000 -Ethernet30 30 twentyfiveGigE31 31 25000 -Ethernet31 29 twentyfiveGigE32 32 25000 -Ethernet32 36 twentyfiveGigE33 33 25000 -Ethernet33 35 twentyfiveGigE34 34 25000 -Ethernet34 34 twentyfiveGigE35 35 25000 -Ethernet35 33 twentyfiveGigE36 36 25000 -Ethernet36 44 twentyfiveGigE37 37 25000 -Ethernet37 43 twentyfiveGigE38 38 25000 -Ethernet38 42 twentyfiveGigE39 39 25000 -Ethernet39 41 twentyfiveGigE40 40 25000 -Ethernet40 86 twentyfiveGigE41 41 25000 -Ethernet41 85 twentyfiveGigE42 42 25000 -Ethernet42 88 twentyfiveGigE43 43 25000 -Ethernet43 87 twentyfiveGigE44 44 25000 -Ethernet44 94 twentyfiveGigE45 45 25000 -Ethernet45 93 twentyfiveGigE46 46 25000 -Ethernet46 96 twentyfiveGigE47 47 25000 -Ethernet47 95 twentyfiveGigE48 48 25000 -Ethernet48 97,98,99,100 hundredGigE49 49 100000 -Ethernet52 105,106,107,108 hundredGigE50 50 100000 -Ethernet56 113,114,115,116 hundredGigE51 51 100000 -Ethernet60 121,122,123,124 hundredGigE52 52 100000 -Ethernet64 77,78,79,80 hundredGigE53 53 100000 -Ethernet68 65,66,67,68 hundredGigE54 54 100000 -Ethernet72 69,70,71,72 hundredGigE55 55 100000 -Ethernet76 125,126,127,128 hundredGigE56 56 100000 +# name lanes alias index speed +Ethernet0 60 twentyfiveGigE1 1 25000 +Ethernet1 59 twentyfiveGigE2 2 25000 +Ethernet2 58 twentyfiveGigE3 3 25000 +Ethernet3 57 twentyfiveGigE4 4 25000 +Ethernet4 64 twentyfiveGigE5 5 25000 +Ethernet5 63 twentyfiveGigE6 6 25000 +Ethernet6 62 twentyfiveGigE7 7 25000 +Ethernet7 61 twentyfiveGigE8 8 25000 +Ethernet8 49 twentyfiveGigE9 9 25000 +Ethernet9 50 twentyfiveGigE10 10 25000 +Ethernet10 51 twentyfiveGigE11 11 25000 +Ethernet11 52 twentyfiveGigE12 12 25000 +Ethernet12 4 twentyfiveGigE13 13 25000 +Ethernet13 3 twentyfiveGigE14 14 25000 +Ethernet14 2 twentyfiveGigE15 15 25000 +Ethernet15 1 twentyfiveGigE16 16 25000 +Ethernet16 8 twentyfiveGigE17 17 25000 +Ethernet17 7 twentyfiveGigE18 18 25000 +Ethernet18 6 twentyfiveGigE19 19 25000 +Ethernet19 5 twentyfiveGigE20 20 25000 +Ethernet20 16 twentyfiveGigE21 21 25000 +Ethernet21 15 twentyfiveGigE22 22 25000 +Ethernet22 14 twentyfiveGigE23 23 25000 +Ethernet23 13 twentyfiveGigE24 24 25000 +Ethernet24 24 twentyfiveGigE25 25 25000 +Ethernet25 23 twentyfiveGigE26 26 25000 +Ethernet26 22 twentyfiveGigE27 27 25000 +Ethernet27 21 twentyfiveGigE28 28 25000 +Ethernet28 32 twentyfiveGigE29 29 25000 +Ethernet29 31 twentyfiveGigE30 30 25000 +Ethernet30 30 twentyfiveGigE31 31 25000 +Ethernet31 29 twentyfiveGigE32 32 25000 +Ethernet32 36 twentyfiveGigE33 33 25000 +Ethernet33 35 twentyfiveGigE34 34 25000 +Ethernet34 34 twentyfiveGigE35 35 25000 +Ethernet35 33 twentyfiveGigE36 36 25000 +Ethernet36 44 twentyfiveGigE37 37 25000 +Ethernet37 43 twentyfiveGigE38 38 25000 +Ethernet38 42 twentyfiveGigE39 39 25000 +Ethernet39 41 twentyfiveGigE40 40 25000 +Ethernet40 86 twentyfiveGigE41 41 25000 +Ethernet41 85 twentyfiveGigE42 42 25000 +Ethernet42 88 twentyfiveGigE43 43 25000 +Ethernet43 87 twentyfiveGigE44 44 25000 +Ethernet44 94 twentyfiveGigE45 45 25000 +Ethernet45 93 twentyfiveGigE46 46 25000 +Ethernet46 96 twentyfiveGigE47 47 25000 +Ethernet47 95 twentyfiveGigE48 48 25000 +Ethernet48 97,98,99,100 hundredGigE49 49 100000 +Ethernet52 105,106,107,108 hundredGigE50 50 100000 +Ethernet56 113,114,115,116 hundredGigE51 51 100000 +Ethernet60 121,122,123,124 hundredGigE52 52 100000 +Ethernet64 77,78,79,80 hundredGigE53 53 100000 +Ethernet68 65,66,67,68 hundredGigE54 54 100000 +Ethernet72 69,70,71,72 hundredGigE55 55 100000 +Ethernet76 125,126,127,128 hundredGigE56 56 100000 diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/qos.json.j2 b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/qos.json.j2 new file mode 100644 index 0000000000..ee67c6e262 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config_t1.j2' %} diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/qos_config_t1.j2 b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/qos_config_t1.j2 new file mode 100644 index 0000000000..5fe5324a85 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/qos_config_t1.j2 @@ -0,0 +1,175 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "AZURE": { + "0" : "1", + "1" : "1", + "2" : "1", + "3" : "3", + "4" : "4", + "5" : "2", + "6" : "1", + "7" : "1", + "8" : "0", + "9" : "1", + "10": "1", + "11": "1", + "12": "1", + "13": "1", + "14": "1", + "15": "1", + "16": "1", + "17": "1", + "18": "1", + "19": "1", + "20": "1", + "21": "1", + "22": "1", + "23": "1", + "24": "1", + "25": "1", + "26": "1", + "27": "1", + "28": "1", + "29": "1", + "30": "1", + "31": "1", + "32": "1", + "33": "1", + "34": "1", + "35": "1", + "36": "1", + "37": "1", + "38": "1", + "39": "1", + "40": "1", + "41": "1", + "42": "1", + "43": "1", + "44": "1", + "45": "1", + "46": "5", + "47": "1", + "48": "6", + "49": "1", + "50": "1", + "51": "1", + "52": "1", + "53": "1", + "54": "1", + "55": "1", + "56": "1", + "57": "1", + "58": "1", + "59": "1", + "60": "1", + "61": "1", + "62": "1", + "63": "1" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "14" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "15" + } + }, +{% if asic_type in pfc_to_pg_map_supported_asics %} + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "3": "3", + "4": "4" + } + }, +{% endif %} + "PORT_QOS_MAP": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]", +{% if asic_type in pfc_to_pg_map_supported_asics %} + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]", +{% endif %} + "pfc_enable" : "3,4" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/td3-ix8-48x25G+8x100G.config.bcm b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/td3-ix8-48x25G+8x100G.config.bcm index 94560fb7e8..06ff6dc800 100644 --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/td3-ix8-48x25G+8x100G.config.bcm +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/Quanta-IX8-56X/td3-ix8-48x25G+8x100G.config.bcm @@ -1,15 +1,22 @@ sai_load_hw_config=/etc/bcm/flex/bcm56870_a0_issu/b870.6.4.1/ -bcm_tunnel_term_compatible_mode=1 core_clock_frequency=1525 dpp_clock_ratio=2:3 -parity_enable=0 mem_cache_enable=0 l2_mem_entries=40960 l3_mem_entries=40960 -fpem_mem_entries=16384 +fpem_mem_entries=0 l2xmsg_mode=1 +l3_alpm_ipv6_128b_bkt_rsvd=1 + +#RIOT Enable +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=32768 +l3_ecmp_levels=2 +riot_overlay_ecmp_resilient_hash_size=16384 bcm_num_cos=10 +default_cpu_tx_queue=9 bcm_stat_interval=2000000 cdma_timeout_usec=3000000 @@ -29,7 +36,8 @@ tdma_timeout_usec=3000000 # portmap settings oversubscribe_mode=1 -pbmp_xport_xe=0x48808080f8780808dfe1e1e1fe1e1e1fe +#pbmp_xport_xe=0x48808080f8780808dfe1e1e1fe1e1e1fe +pbmp_xport_xe=0x7F878787F878787FDFE1E1E1FE1E1E1FE port_flex_enable=1 @@ -73,9 +81,6 @@ portmap_61=61:25 portmap_62=62:25 portmap_63=63:25 portmap_64=64:25 -portmap_67=65:100 -portmap_71=69:100 -portmap_79=77:100 portmap_87=85:25 portmap_88=86:25 portmap_89=87:25 @@ -84,6 +89,10 @@ portmap_95=93:25 portmap_96=94:25 portmap_97=95:25 portmap_98=96:25 + +portmap_67=65:100 +portmap_71=69:100 +portmap_79=77:100 portmap_99=97:100 portmap_107=105:100 portmap_115=113:100 @@ -91,8 +100,10 @@ portmap_123=121:100 portmap_127=125:100 # datapath port -- MerlinCore -portmap_66=129:10:m -portmap_130=128:10:m +#Hide these to prevent SAI from initializing them...they are physically not on system +#front panel +#portmap_66=129:10:m +#portmap_130=128:10:m # loopback port portmap_65=130:10 @@ -166,9 +177,6 @@ serdes_if_type_61=13 serdes_if_type_62=13 serdes_if_type_63=13 serdes_if_type_64=13 -serdes_if_type_67=14 -serdes_if_type_71=14 -serdes_if_type_79=14 serdes_if_type_87=13 serdes_if_type_88=13 serdes_if_type_89=13 @@ -177,11 +185,16 @@ serdes_if_type_95=13 serdes_if_type_96=13 serdes_if_type_97=13 serdes_if_type_98=13 + +serdes_if_type_67=14 +serdes_if_type_71=14 +serdes_if_type_79=14 serdes_if_type_99=14 serdes_if_type_107=14 serdes_if_type_115=14 serdes_if_type_123=14 serdes_if_type_127=14 + serdes_if_type_66=11 serdes_if_type_130=11 @@ -234,17 +247,48 @@ dport_map_port_96=45 dport_map_port_95=46 dport_map_port_98=47 dport_map_port_97=48 -dport_map_port_99=49 -dport_map_port_107=50 -dport_map_port_115=51 -dport_map_port_123=52 -dport_map_port_79=53 -dport_map_port_67=54 -dport_map_port_71=55 -dport_map_port_127=56 -dport_map_port_66=57 -dport_map_port_130=58 +dport_map_port_67=49 +dport_map_port_68=50 +dport_map_port_69=51 +dport_map_port_70=52 + +dport_map_port_71=53 +dport_map_port_72=54 +dport_map_port_73=55 +dport_map_port_74=56 + +dport_map_port_79=57 +dport_map_port_80=58 +dport_map_port_81=59 +dport_map_port_82=60 + +dport_map_port_99=61 +dport_map_port_100=62 +dport_map_port_101=63 +dport_map_port_102=64 + +dport_map_port_107=65 +dport_map_port_108=66 +dport_map_port_109=67 +dport_map_port_110=68 + +dport_map_port_115=69 +dport_map_port_116=70 +dport_map_port_117=71 +dport_map_port_118=72 + +dport_map_port_123=73 +dport_map_port_124=74 +dport_map_port_125=75 +dport_map_port_126=76 + +# Not able to breakout, Since overlap with mgmt port +dport_map_port_127=77 + +# mgmt ports +dport_map_port_66=81 +dport_map_port_130=82 phy_chain_tx_lane_map_physical{1.0}=0x3210 @@ -479,3 +523,8 @@ phy_chain_rx_polarity_flip_physical{130.0}=0x0 phy_chain_rx_polarity_flip_physical{131.0}=0x0 phy_chain_rx_polarity_flip_physical{132.0}=0x0 +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 + diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/custom_led.bin b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/custom_led.bin new file mode 100644 index 0000000000..7f3ff6a684 Binary files /dev/null and b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/custom_led.bin differ diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/installer.conf b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/installer.conf index 14404194ef..8b2b94dfeb 100644 --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/installer.conf +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/installer.conf @@ -1,3 +1,4 @@ CONSOLE_PORT=0x2f8 CONSOLE_DEV=1 CONSOLE_SPEED=115200 +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX="modprobe.blacklist=i2c-ismt,i2c_ismt,ixgbe" diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/led_proc_init.soc b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/led_proc_init.soc old mode 100755 new mode 100644 index 0861486660..bf9f29924d --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/led_proc_init.soc +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/led_proc_init.soc @@ -1,6 +1,4 @@ -sleep 10 -led stop -sleep 3 +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin led start -sleep 3 -led auto on \ No newline at end of file +rcload /usr/share/sonic/platform/preemphasis-48x25_8x100.soc + diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/eeprom.py b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/eeprom.py index fa34110c04..3752a919cb 100644 --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/eeprom.py +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/eeprom.py @@ -16,5 +16,5 @@ class board(eeprom_tlvinfo.TlvInfoDecoder): _TLV_INFO_MAX_LEN = 256 def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/sys/bus/i2c/devices/18-0054/eeprom" + self.eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/fanutil.py b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/fanutil.py new file mode 100644 index 0000000000..dad8dcfedd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/fanutil.py @@ -0,0 +1,110 @@ +# +# fanutil.py +# Platform-specific Fan status interface for SONiC +# + +import logging +import os.path + +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""" + + SYS_FAN_NUM = 6 + NUM_FANS_PERTRAY = 2 + HWMON_PATH = '/sys/class/hwmon/hwmon1/' + FAN_INDEX_START = 21 + + logger = logging.getLogger(__name__) + + def __init__(self, log_level=logging.DEBUG): + FanBase.__init__(self) + self.num_fans = (self.SYS_FAN_NUM * self.NUM_FANS_PERTRAY) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def check_fan_index(self, index): + if index is None: + return False + + if index < 1 or index > self.num_fans: + logging.error("Invalid Fan index:", index) + return False + + return True + + def get_num_fans(self): + return self.num_fans + + def get_status(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + if fantray_speed == '0.0' : + return False + + return True + + def get_presence(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_present_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_present' + fantray_present = self.get_attr_value(self.HWMON_PATH + fantray_present_file) + + if fantray_present == '1' : + return True + + return False + + def get_direction(self, index): + if self.check_fan_index(index) == False: + return None + + fantray_direction_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_direction' + fantray_direction = self.get_attr_value(self.HWMON_PATH + fantray_direction_file) + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if fantray_direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_speed(self, index): + if self.check_fan_index(index) == False: + return 0 + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + return int(float(fantray_speed)) + + + def set_speed(self, val): + logging.error("Not allowed to set fan speed!") + + return False diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/psuutil.py b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/psuutil.py index 5cf06fb5d6..b2753d1759 100644 --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/psuutil.py +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/psuutil.py @@ -1,50 +1,251 @@ -# -# psuutil.py -# Platform-specific PSU status interface for SONiC -# - -import os.path - -try: - from sonic_psu.psu_base import PsuBase -except ImportError as e: - raise ImportError(str(e) + "- required module not found") - - -class PsuUtil(PsuBase): - """Platform-specific PSUutil class""" - - def __init__(self): - PsuBase.__init__(self) - - 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 - """ - MAX_PSUS = 2 - - return MAX_PSUS - - def get_psu_status(self, index): - """ - Retrieves the oprational status of power supply unit (PSU) defined - by 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 = 1 - - return status - - def get_psu_presence(self, index): - """ - Retrieves the presence status of power supply unit (PSU) defined - by 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 = 1 - - return status +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + +import logging +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + HWMON_PATH = '/sys/class/hwmon/hwmon1/' + PSU1_PREFIX = 'power43_' + PSU2_PREFIX = 'power54_' + MAX_PSUS = 2 + def __init__(self): + PsuBase.__init__(self) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def get_attr_filename(self, index, attr): + if (index == 1): + attr_file = self.PSU1_PREFIX + attr + elif (index == 2): + attr_file = self.PSU2_PREFIX + attr + else: + logging.error("Invalid PSU number:", index) + return '' + + return attr_file + + 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 + """ + + return self.MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'present') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check PSU status + if (attr_value == 1): + status = True + return status + + def get_powergood_status(self, index): + status = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_model(self, index): + attr_filename = self.get_attr_filename(index, 'model') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_mfr_id(self, index): + attr_filename = self.get_attr_filename(index, 'mfrid') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_serial(self, index): + attr_filename = self.get_attr_filename(index, 'sn') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_direction(self, index): + if (index == 1): + direction_file = 'fan41_direction' + elif (index == 2): + direction_file = 'fan52_direction' + else: + logging.error("Invalid PSU number:", index) + return None + + direction = self.get_attr_value(self.HWMON_PATH + direction_file) + direction = direction.rstrip() + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_output_voltage(self, index): + if (index == 1): + attr_file = 'in48_input' + elif (index == 2): + attr_file = 'in59_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + voltage = self.get_attr_value(self.HWMON_PATH + attr_file) + voltage = voltage.rstrip() + + if (voltage != 'ERR'): + voltage, dummy = voltage.split('.', 1) + else: + return 0.0 + + return float(voltage)/1000 + + def get_output_current(self, index): + if (index == 1): + attr_file = 'curr40_input' + elif (index == 2): + attr_file = 'curr51_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + current = self.get_attr_value(self.HWMON_PATH + attr_file) + current = current.rstrip() + + if (current != 'ERR'): + current, dummy = current.split('.',1) + else: + return 0.0 + + return float(current)/1000 + + def get_output_power(self, index): + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return 0.0 + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + else: + return 0.0 + + return float(attr_value/1000) + + def get_fan_rpm(self, index, fan_idx): + if (index == 1): + rpm_file = 'fan41_input' + elif (index == 2): + rpm_file = 'fan52_input' + else: + logging.error("Invalid PSU number:", index) + return 0 + + rpm = self.get_attr_value(self.HWMON_PATH + rpm_file) + rpm = rpm.rstrip() + if (rpm != 'ERR'): + rpm = float(rpm) + else: + return 0 + + return int(rpm) diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/sfputil.py b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/sfputil.py index 3067919795..4dc269829c 100644 --- a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/sfputil.py +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/plugins/sfputil.py @@ -23,62 +23,62 @@ class SfpUtil(SfpUtilBase): _port_to_eeprom_mapping = {} _port_to_i2c_mapping = { - 1: 32, - 2: 33, - 3: 34, - 4: 35, - 5: 36, - 6: 37, - 7: 38, - 8: 39, - 9: 40, - 10: 41, - 11: 42, - 12: 43, - 13: 44, - 14: 45, - 15: 46, - 16: 47, - 17: 48, - 18: 49, - 19: 50, - 20: 51, - 21: 52, - 22: 53, - 23: 54, - 24: 55, - 25: 56, - 26: 57, - 27: 58, - 28: 59, - 29: 60, - 30: 61, - 31: 62, - 32: 63, - 33: 64, - 34: 65, - 35: 66, - 36: 67, - 37: 68, - 38: 69, - 39: 70, - 40: 71, - 41: 72, - 42: 73, - 43: 74, - 44: 75, - 45: 76, - 46: 77, - 47: 78, - 48: 79, - 49: 80, # QSFP49 - 50: 81, # QSFP50 - 51: 82, # QSFP51 - 52: 83, # QSFP52 - 53: 84, # QSFP53 - 54: 85, # QSFP54 - 55: 86, # QSFP55 - 56: 87, # QSFP56 + 1 : 17, + 2 : 18, + 3 : 19, + 4 : 20, + 5 : 21, + 6 : 22, + 7 : 23, + 8 : 24, + 9 : 25, + 10 : 26, + 11 : 27, + 12 : 28, + 13 : 29, + 14 : 30, + 15 : 31, + 16 : 32, + 17 : 33, + 18 : 34, + 19 : 35, + 20 : 36, + 21 : 37, + 22 : 38, + 23 : 39, + 24 : 40, + 25 : 41, + 26 : 42, + 27 : 43, + 28 : 44, + 29 : 45, + 30 : 46, + 31 : 47, + 32 : 48, + 33 : 49, + 34 : 50, + 35 : 51, + 36 : 52, + 37 : 53, + 38 : 54, + 39 : 55, + 40 : 56, + 41 : 57, + 42 : 58, + 43 : 59, + 44 : 60, + 45 : 61, + 46 : 62, + 47 : 63, + 48 : 64, + 49 : 65,#QSFP49 + 50 : 66,#QSFP50 + 51 : 67,#QSFP51 + 52 : 68,#QSFP52 + 53 : 69,#QSFP53 + 54 : 70,#QSFP54 + 55 : 71,#QSFP55 + 56 : 72,#QSFP56 } @property diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/pmon_daemon_control.json b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..98506b4614 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} \ No newline at end of file diff --git a/device/quanta/x86_64-quanta_ix8_rglbmc-r0/preemphasis-48x25_8x100.soc b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/preemphasis-48x25_8x100.soc new file mode 100644 index 0000000000..3a0193b73d --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8_rglbmc-r0/preemphasis-48x25_8x100.soc @@ -0,0 +1,325 @@ +# 48x25G 8x100G pre-emphasis setting for Quanta IX8 +echo "Set tx pre-emphasis and idriver values" +linkscan off + +# Start of 48x25G + +phy raw c45 0xd1 0x1 0xffde 0 +phy raw c45 0xd1 0x1 0xd130 0x55 +phy raw c45 0xd1 0x1 0xd131 0x303 +phy raw c45 0xd1 0x1 0xd134 0x1 +phy raw c45 0xd1 0x1 0xffde 1 +phy raw c45 0xd1 0x1 0xd130 0x55 +phy raw c45 0xd1 0x1 0xd131 0x303 +phy raw c45 0xd1 0x1 0xd134 0x1 +phy raw c45 0xd1 0x1 0xffde 2 +phy raw c45 0xd1 0x1 0xd130 0x55 +phy raw c45 0xd1 0x1 0xd131 0x303 +phy raw c45 0xd1 0x1 0xd134 0x1 +phy raw c45 0xd1 0x1 0xffde 3 +phy raw c45 0xd1 0x1 0xd130 0x55 +phy raw c45 0xd1 0x1 0xd131 0x303 +phy raw c45 0xd1 0x1 0xd134 0x1 + +phy raw c45 0xd5 0x1 0xffde 0 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x303 +phy raw c45 0xd5 0x1 0xd134 0x1 +phy raw c45 0xd5 0x1 0xffde 1 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x303 +phy raw c45 0xd5 0x1 0xd134 0x1 +phy raw c45 0xd5 0x1 0xffde 2 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x303 +phy raw c45 0xd5 0x1 0xd134 0x1 +phy raw c45 0xd5 0x1 0xffde 3 +phy raw c45 0xd5 0x1 0xd130 0x55 +phy raw c45 0xd5 0x1 0xd131 0x303 +phy raw c45 0xd5 0x1 0xd134 0x1 + +phy raw c45 0xc9 0x1 0xffde 0 +phy raw c45 0xc9 0x1 0xd130 0x55 +phy raw c45 0xc9 0x1 0xd131 0x303 +phy raw c45 0xc9 0x1 0xd134 0x1 +phy raw c45 0xc9 0x1 0xffde 1 +phy raw c45 0xc9 0x1 0xd130 0x55 +phy raw c45 0xc9 0x1 0xd131 0x303 +phy raw c45 0xc9 0x1 0xd134 0x1 +phy raw c45 0xc9 0x1 0xffde 2 +phy raw c45 0xc9 0x1 0xd130 0x55 +phy raw c45 0xc9 0x1 0xd131 0x303 +phy raw c45 0xc9 0x1 0xd134 0x1 +phy raw c45 0xc9 0x1 0xffde 3 +phy raw c45 0xc9 0x1 0xd130 0x55 +phy raw c45 0xc9 0x1 0xd131 0x303 +phy raw c45 0xc9 0x1 0xd134 0x1 + +phy raw c45 0x81 0x1 0xffde 0 +phy raw c45 0x81 0x1 0xd130 0x55 +phy raw c45 0x81 0x1 0xd131 0x303 +phy raw c45 0x81 0x1 0xd134 0x1 +phy raw c45 0x81 0x1 0xffde 1 +phy raw c45 0x81 0x1 0xd130 0x55 +phy raw c45 0x81 0x1 0xd131 0x303 +phy raw c45 0x81 0x1 0xd134 0x1 +phy raw c45 0x81 0x1 0xffde 2 +phy raw c45 0x81 0x1 0xd130 0x55 +phy raw c45 0x81 0x1 0xd131 0x303 +phy raw c45 0x81 0x1 0xd134 0x1 +phy raw c45 0x81 0x1 0xffde 3 +phy raw c45 0x81 0x1 0xd130 0x55 +phy raw c45 0x81 0x1 0xd131 0x303 +phy raw c45 0x81 0x1 0xd134 0x1 + +phy raw c45 0x85 0x1 0xffde 0 +phy raw c45 0x85 0x1 0xd130 0x55 +phy raw c45 0x85 0x1 0xd131 0x303 +phy raw c45 0x85 0x1 0xd134 0x1 +phy raw c45 0x85 0x1 0xffde 1 +phy raw c45 0x85 0x1 0xd130 0x55 +phy raw c45 0x85 0x1 0xd131 0x303 +phy raw c45 0x85 0x1 0xd134 0x1 +phy raw c45 0x85 0x1 0xffde 2 +phy raw c45 0x85 0x1 0xd130 0x55 +phy raw c45 0x85 0x1 0xd131 0x303 +phy raw c45 0x85 0x1 0xd134 0x1 +phy raw c45 0x85 0x1 0xffde 3 +phy raw c45 0x85 0x1 0xd130 0x55 +phy raw c45 0x85 0x1 0xd131 0x303 +phy raw c45 0x85 0x1 0xd134 0x1 + +phy raw c45 0x8d 0x1 0xffde 0 +phy raw c45 0x8d 0x1 0xd130 0x55 +phy raw c45 0x8d 0x1 0xd131 0x303 +phy raw c45 0x8d 0x1 0xd134 0x1 +phy raw c45 0x8d 0x1 0xffde 1 +phy raw c45 0x8d 0x1 0xd130 0x55 +phy raw c45 0x8d 0x1 0xd131 0x303 +phy raw c45 0x8d 0x1 0xd134 0x1 +phy raw c45 0x8d 0x1 0xffde 2 +phy raw c45 0x8d 0x1 0xd130 0x55 +phy raw c45 0x8d 0x1 0xd131 0x303 +phy raw c45 0x8d 0x1 0xd134 0x1 +phy raw c45 0x8d 0x1 0xffde 3 +phy raw c45 0x8d 0x1 0xd130 0x55 +phy raw c45 0x8d 0x1 0xd131 0x303 +phy raw c45 0x8d 0x1 0xd134 0x1 + +phy raw c45 0x95 0x1 0xffde 0 +phy raw c45 0x95 0x1 0xd130 0x55 +phy raw c45 0x95 0x1 0xd131 0x303 +phy raw c45 0x95 0x1 0xd134 0x1 +phy raw c45 0x95 0x1 0xffde 1 +phy raw c45 0x95 0x1 0xd130 0x55 +phy raw c45 0x95 0x1 0xd131 0x303 +phy raw c45 0x95 0x1 0xd134 0x1 +phy raw c45 0x95 0x1 0xffde 2 +phy raw c45 0x95 0x1 0xd130 0x55 +phy raw c45 0x95 0x1 0xd131 0x303 +phy raw c45 0x95 0x1 0xd134 0x1 +phy raw c45 0x95 0x1 0xffde 3 +phy raw c45 0x95 0x1 0xd130 0x55 +phy raw c45 0x95 0x1 0xd131 0x303 +phy raw c45 0x95 0x1 0xd134 0x1 + +phy raw c45 0xa5 0x1 0xffde 0 +phy raw c45 0xa5 0x1 0xd130 0x55 +phy raw c45 0xa5 0x1 0xd131 0x303 +phy raw c45 0xa5 0x1 0xd134 0x1 +phy raw c45 0xa5 0x1 0xffde 1 +phy raw c45 0xa5 0x1 0xd130 0x55 +phy raw c45 0xa5 0x1 0xd131 0x303 +phy raw c45 0xa5 0x1 0xd134 0x1 +phy raw c45 0xa5 0x1 0xffde 2 +phy raw c45 0xa5 0x1 0xd130 0x55 +phy raw c45 0xa5 0x1 0xd131 0x303 +phy raw c45 0xa5 0x1 0xd134 0x1 +phy raw c45 0xa5 0x1 0xffde 3 +phy raw c45 0xa5 0x1 0xd130 0x55 +phy raw c45 0xa5 0x1 0xd131 0x303 +phy raw c45 0xa5 0x1 0xd134 0x1 + +phy raw c45 0xa9 0x1 0xffde 0 +phy raw c45 0xa9 0x1 0xd130 0x55 +phy raw c45 0xa9 0x1 0xd131 0x303 +phy raw c45 0xa9 0x1 0xd134 0x1 +phy raw c45 0xa9 0x1 0xffde 1 +phy raw c45 0xa9 0x1 0xd130 0x55 +phy raw c45 0xa9 0x1 0xd131 0x303 +phy raw c45 0xa9 0x1 0xd134 0x1 +phy raw c45 0xa9 0x1 0xffde 2 +phy raw c45 0xa9 0x1 0xd130 0x55 +phy raw c45 0xa9 0x1 0xd131 0x303 +phy raw c45 0xa9 0x1 0xd134 0x1 +phy raw c45 0xa9 0x1 0xffde 3 +phy raw c45 0xa9 0x1 0xd130 0x55 +phy raw c45 0xa9 0x1 0xd131 0x303 +phy raw c45 0xa9 0x1 0xd134 0x1 + +phy raw c45 0xc1 0x1 0xffde 0 +phy raw c45 0xc1 0x1 0xd130 0x55 +phy raw c45 0xc1 0x1 0xd131 0x303 +phy raw c45 0xc1 0x1 0xd134 0x1 +phy raw c45 0xc1 0x1 0xffde 1 +phy raw c45 0xc1 0x1 0xd130 0x55 +phy raw c45 0xc1 0x1 0xd131 0x303 +phy raw c45 0xc1 0x1 0xd134 0x1 +phy raw c45 0xc1 0x1 0xffde 2 +phy raw c45 0xc1 0x1 0xd130 0x55 +phy raw c45 0xc1 0x1 0xd131 0x303 +phy raw c45 0xc1 0x1 0xd134 0x1 +phy raw c45 0xc1 0x1 0xffde 3 +phy raw c45 0xc1 0x1 0xd130 0x55 +phy raw c45 0xc1 0x1 0xd131 0x303 +phy raw c45 0xc1 0x1 0xd134 0x1 + +phy raw c45 0xf5 0x1 0xffde 0 +phy raw c45 0xf5 0x1 0xd130 0x55 +phy raw c45 0xf5 0x1 0xd131 0x303 +phy raw c45 0xf5 0x1 0xd134 0x1 +phy raw c45 0xf5 0x1 0xffde 1 +phy raw c45 0xf5 0x1 0xd130 0x55 +phy raw c45 0xf5 0x1 0xd131 0x303 +phy raw c45 0xf5 0x1 0xd134 0x1 +phy raw c45 0xf5 0x1 0xffde 2 +phy raw c45 0xf5 0x1 0xd130 0x55 +phy raw c45 0xf5 0x1 0xd131 0x303 +phy raw c45 0xf5 0x1 0xd134 0x1 +phy raw c45 0xf5 0x1 0xffde 3 +phy raw c45 0xf5 0x1 0xd130 0x55 +phy raw c45 0xf5 0x1 0xd131 0x303 +phy raw c45 0xf5 0x1 0xd134 0x1 + +phy raw c45 0x185 0x1 0xffde 0 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x303 +phy raw c45 0x185 0x1 0xd134 0x1 +phy raw c45 0x185 0x1 0xffde 1 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x303 +phy raw c45 0x185 0x1 0xd134 0x1 +phy raw c45 0x185 0x1 0xffde 2 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x303 +phy raw c45 0x185 0x1 0xd134 0x1 +phy raw c45 0x185 0x1 0xffde 3 +phy raw c45 0x185 0x1 0xd130 0x55 +phy raw c45 0x185 0x1 0xd131 0x303 +phy raw c45 0x185 0x1 0xd134 0x1 + +# Start of 8x100G + +phy raw c45 0xe1 0x1 0xffde 0 +phy raw c45 0xe1 0x1 0xd130 0x55 +phy raw c45 0xe1 0x1 0xd131 0x303 +phy raw c45 0xe1 0x1 0xffde 1 +phy raw c45 0xe1 0x1 0xd130 0x55 +phy raw c45 0xe1 0x1 0xd131 0x303 +phy raw c45 0xe1 0x1 0xffde 2 +phy raw c45 0xe1 0x1 0xd130 0x55 +phy raw c45 0xe1 0x1 0xd131 0x303 +phy raw c45 0xe1 0x1 0xffde 3 +phy raw c45 0xe1 0x1 0xd130 0x59 +phy raw c45 0xe1 0x1 0xd131 0x505 +phy raw c45 0xe1 0x1 0xd134 0x1 + +phy raw c45 0xe5 0x1 0xffde 0 +phy raw c45 0xe5 0x1 0xd130 0x59 +phy raw c45 0xe5 0x1 0xd131 0x502 +phy raw c45 0xe5 0x1 0xffde 1 +phy raw c45 0xe5 0x1 0xd130 0x59 +phy raw c45 0xe5 0x1 0xd131 0x502 +phy raw c45 0xe5 0x1 0xffde 2 +phy raw c45 0xe5 0x1 0xd130 0x59 +phy raw c45 0xe5 0x1 0xd131 0x502 +phy raw c45 0xe5 0x1 0xffde 3 +phy raw c45 0xe5 0x1 0xd130 0x59 +phy raw c45 0xe5 0x1 0xd131 0x502 +phy raw c45 0xe5 0x1 0xd134 0x1 + +phy raw c45 0xed 0x1 0xffde 0 +phy raw c45 0xed 0x1 0xd130 0x59 +phy raw c45 0xed 0x1 0xd131 0x502 +phy raw c45 0xed 0x1 0xffde 1 +phy raw c45 0xed 0x1 0xd130 0x59 +phy raw c45 0xed 0x1 0xd131 0x502 +phy raw c45 0xed 0x1 0xffde 2 +phy raw c45 0xed 0x1 0xd130 0x59 +phy raw c45 0xed 0x1 0xd131 0x502 +phy raw c45 0xed 0x1 0xffde 3 +phy raw c45 0xed 0x1 0xd130 0x59 +phy raw c45 0xed 0x1 0xd131 0x502 +phy raw c45 0xed 0x1 0xd134 0x1 + +phy raw c45 0x189 0x1 0xffde 0 +phy raw c45 0x189 0x1 0xd130 0x59 +phy raw c45 0x189 0x1 0xd131 0x502 +phy raw c45 0x189 0x1 0xffde 1 +phy raw c45 0x189 0x1 0xd130 0x59 +phy raw c45 0x189 0x1 0xd131 0x502 +phy raw c45 0x189 0x1 0xffde 2 +phy raw c45 0x189 0x1 0xd130 0x59 +phy raw c45 0x189 0x1 0xd131 0x502 +phy raw c45 0x189 0x1 0xffde 3 +phy raw c45 0x189 0x1 0xd130 0x59 +phy raw c45 0x189 0x1 0xd131 0x502 +phy raw c45 0x189 0x1 0xd134 0x1 + +phy raw c45 0x1a1 0x1 0xffde 0 +phy raw c45 0x1a1 0x1 0xd130 0x59 +phy raw c45 0x1a1 0x1 0xd131 0x502 +phy raw c45 0x1a1 0x1 0xffde 1 +phy raw c45 0x1a1 0x1 0xd130 0x59 +phy raw c45 0x1a1 0x1 0xd131 0x502 +phy raw c45 0x1a1 0x1 0xffde 2 +phy raw c45 0x1a1 0x1 0xd130 0x59 +phy raw c45 0x1a1 0x1 0xd131 0x502 +phy raw c45 0x1a1 0x1 0xffde 3 +phy raw c45 0x1a1 0x1 0xd130 0x59 +phy raw c45 0x1a1 0x1 0xd131 0x502 +phy raw c45 0x1a1 0x1 0xd134 0x1 + +phy raw c45 0x1a9 0x1 0xffde 0 +phy raw c45 0x1a9 0x1 0xd130 0x59 +phy raw c45 0x1a9 0x1 0xd131 0x502 +phy raw c45 0x1a9 0x1 0xffde 1 +phy raw c45 0x1a9 0x1 0xd130 0x59 +phy raw c45 0x1a9 0x1 0xd131 0x502 +phy raw c45 0x1a9 0x1 0xffde 2 +phy raw c45 0x1a9 0x1 0xd130 0x59 +phy raw c45 0x1a9 0x1 0xd131 0x502 +phy raw c45 0x1a9 0x1 0xffde 3 +phy raw c45 0x1a9 0x1 0xd130 0x59 +phy raw c45 0x1a9 0x1 0xd131 0x502 +phy raw c45 0x1a9 0x1 0xd134 0x1 + +phy raw c45 0x1b1 0x1 0xffde 0 +phy raw c45 0x1b1 0x1 0xd130 0x59 +phy raw c45 0x1b1 0x1 0xd131 0x502 +phy raw c45 0x1b1 0x1 0xffde 1 +phy raw c45 0x1b1 0x1 0xd130 0x59 +phy raw c45 0x1b1 0x1 0xd131 0x502 +phy raw c45 0x1b1 0x1 0xffde 2 +phy raw c45 0x1b1 0x1 0xd130 0x59 +phy raw c45 0x1b1 0x1 0xd131 0x502 +phy raw c45 0x1b1 0x1 0xffde 3 +phy raw c45 0x1b1 0x1 0xd130 0x59 +phy raw c45 0x1b1 0x1 0xd131 0x502 +phy raw c45 0x1b1 0x1 0xd134 0x1 + +phy raw c45 0x1b5 0x1 0xffde 0 +phy raw c45 0x1b5 0x1 0xd130 0x59 +phy raw c45 0x1b5 0x1 0xd131 0x502 +phy raw c45 0x1b5 0x1 0xffde 1 +phy raw c45 0x1b5 0x1 0xd130 0x59 +phy raw c45 0x1b5 0x1 0xd131 0x502 +phy raw c45 0x1b5 0x1 0xffde 2 +phy raw c45 0x1b5 0x1 0xd130 0x59 +phy raw c45 0x1b5 0x1 0xd131 0x502 +phy raw c45 0x1b5 0x1 0xffde 3 +phy raw c45 0x1b5 0x1 0xd130 0x59 +phy raw c45 0x1b5 0x1 0xd131 0x502 +phy raw c45 0x1b5 0x1 0xd134 0x1 + +linkscan on \ No newline at end of file diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers.json.j2 b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_def.j2 b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_def.j2 new file mode 100644 index 0000000000..740cfdf79e --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_def.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "4625920", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_t0.j2 b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..44fcf21887 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_t0.j2 @@ -0,0 +1,45 @@ +{%- 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": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "12766208", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "7326924", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"12766208" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_t1.j2 b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..5fe9cabcfd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/buffers_defaults_t1.j2 @@ -0,0 +1,46 @@ +{%- 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": { + "xoff": "196608", + "size": "12766208", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "33004032", + "type": "egress", + "mode": "static" + }, + "egress_lossy_pool": { + "size": "12766208", + "type": "egress", + "mode": "dynamic" + } + }, + "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":"33004032" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"1518", + "dynamic_th":"3" + } + }, +{%- endmacro %} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/l2/config b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/l2/config new file mode 100644 index 0000000000..b2d4a1e805 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/l2/config @@ -0,0 +1,3 @@ +l2_mem_entries=294912 +l3_mem_entries=16384 +l3_alpm_enable=0 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/l3/config b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/l3/config new file mode 100644 index 0000000000..fff0cf54b0 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/l3/config @@ -0,0 +1,5 @@ +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 +sai_tunnel_support=1 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/pg_profile_lookup.ini b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/pg_profile_lookup.ini new file mode 100644 index 0000000000..6d91d03ae6 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/pg_profile_lookup.ini @@ -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 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/platform-def.json b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/platform-def.json new file mode 100644 index 0000000000..4758d031e6 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/platform-def.json @@ -0,0 +1,48 @@ +{ + "fec-mode": { + "Ethernet0-47": { + "1": { + "1000": [ "none" ], + "10000": [ "none", "fc" ], + "25000": [ "none", "rs" ] + } + }, + "Ethernet48-79": { + "1": { + "10000": [ "none", "fc" ], + "25000": [ "none", "rs" ] + }, + "2": { + "20000": [ "none", "fc" ], + "50000": [ "none", "rs" ] + }, + "4": { + "40000": [ "none", "fc" ], + "100000": [ "none", "rs" ] + } + } + }, + "default-fec-mode": { + "Ethernet0-47": { + "1": { + "1000": "none", + "10000": "none", + "25000": "rs" + } + }, + "Ethernet48-79": { + "4": { + "40000": "none", + "100000": "rs" + } + } + }, + "native-port-supported-speeds": { + "Ethernet0-47": { + "1": ["25000","10000","1000"] + }, + "Ethernet48-79": { + "4": ["100000","40000"] + } + } +} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/port_config.ini b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/port_config.ini new file mode 100644 index 0000000000..d499031fee --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias index speed +Ethernet0 1 twentyfiveGigE1 1 25000 +Ethernet1 2 twentyfiveGigE2 2 25000 +Ethernet2 3 twentyfiveGigE3 3 25000 +Ethernet3 4 twentyfiveGigE4 4 25000 +Ethernet4 5 twentyfiveGigE5 5 25000 +Ethernet5 6 twentyfiveGigE6 6 25000 +Ethernet6 7 twentyfiveGigE7 7 25000 +Ethernet7 8 twentyfiveGigE8 8 25000 +Ethernet8 9 twentyfiveGigE9 9 25000 +Ethernet9 10 twentyfiveGigE10 10 25000 +Ethernet10 11 twentyfiveGigE11 11 25000 +Ethernet11 12 twentyfiveGigE12 12 25000 +Ethernet12 13 twentyfiveGigE13 13 25000 +Ethernet13 14 twentyfiveGigE14 14 25000 +Ethernet14 15 twentyfiveGigE15 15 25000 +Ethernet15 16 twentyfiveGigE16 16 25000 +Ethernet16 17 twentyfiveGigE17 17 25000 +Ethernet17 18 twentyfiveGigE18 18 25000 +Ethernet18 19 twentyfiveGigE19 19 25000 +Ethernet19 20 twentyfiveGigE20 20 25000 +Ethernet20 21 twentyfiveGigE21 21 25000 +Ethernet21 22 twentyfiveGigE22 22 25000 +Ethernet22 23 twentyfiveGigE23 23 25000 +Ethernet23 24 twentyfiveGigE24 24 25000 +Ethernet24 57 twentyfiveGigE25 25 25000 +Ethernet25 58 twentyfiveGigE26 26 25000 +Ethernet26 59 twentyfiveGigE27 27 25000 +Ethernet27 60 twentyfiveGigE28 28 25000 +Ethernet28 61 twentyfiveGigE29 29 25000 +Ethernet29 62 twentyfiveGigE30 30 25000 +Ethernet30 63 twentyfiveGigE31 31 25000 +Ethernet31 64 twentyfiveGigE32 32 25000 +Ethernet32 65 twentyfiveGigE33 33 25000 +Ethernet33 66 twentyfiveGigE34 34 25000 +Ethernet34 67 twentyfiveGigE35 35 25000 +Ethernet35 68 twentyfiveGigE36 36 25000 +Ethernet36 69 twentyfiveGigE37 37 25000 +Ethernet37 70 twentyfiveGigE38 38 25000 +Ethernet38 71 twentyfiveGigE39 39 25000 +Ethernet39 72 twentyfiveGigE40 40 25000 +Ethernet40 73 twentyfiveGigE41 41 25000 +Ethernet41 74 twentyfiveGigE42 42 25000 +Ethernet42 75 twentyfiveGigE43 43 25000 +Ethernet43 76 twentyfiveGigE44 44 25000 +Ethernet44 77 twentyfiveGigE45 45 25000 +Ethernet45 78 twentyfiveGigE46 46 25000 +Ethernet46 79 twentyfiveGigE47 47 25000 +Ethernet47 80 twentyfiveGigE48 48 25000 +Ethernet48 41,42,43,44 hundredGigE49 49 100000 +Ethernet52 45,46,47,48 hundredGigE50 50 100000 +Ethernet56 49,50,51,52 hundredGigE51 51 100000 +Ethernet60 53,54,55,56 hundredGigE52 52 100000 +Ethernet64 33,34,35,36 hundredGigE53 53 100000 +Ethernet68 37,38,39,40 hundredGigE54 54 100000 +Ethernet72 25,26,27,28 hundredGigE55 55 100000 +Ethernet76 29,30,31,32 hundredGigE56 56 100000 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/qos.json.j2 b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/qos.json.j2 new file mode 100644 index 0000000000..ee67c6e262 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/qos.json.j2 @@ -0,0 +1 @@ +{%- include 'qos_config_t1.j2' %} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/qos_config_t1.j2 b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/qos_config_t1.j2 new file mode 100644 index 0000000000..5fe5324a85 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/qos_config_t1.j2 @@ -0,0 +1,175 @@ +{%- set PORT_ALL = [] %} +{%- for port in PORT %} + {%- if PORT_ALL.append(port) %}{% endif %} +{%- endfor %} +{%- if PORT_ALL | sort_by_port_index %}{% endif %} + +{%- set port_names_list_all = [] %} +{%- for port in PORT_ALL %} + {%- if port_names_list_all.append(port) %}{% endif %} +{%- endfor %} +{%- set port_names_all = port_names_list_all | join(',') -%} + + +{%- set PORT_ACTIVE = [] %} +{%- if DEVICE_NEIGHBOR is not defined %} + {%- set PORT_ACTIVE = PORT_ALL %} +{%- else %} + {%- for port in DEVICE_NEIGHBOR.keys() %} + {%- if PORT_ACTIVE.append(port) %}{%- endif %} + {%- endfor %} +{%- endif %} +{%- if PORT_ACTIVE | sort_by_port_index %}{% endif %} + +{%- set port_names_list_active = [] %} +{%- for port in PORT_ACTIVE %} + {%- if port_names_list_active.append(port) %}{%- endif %} +{%- endfor %} +{%- set port_names_active = port_names_list_active | join(',') -%} + + +{%- set pfc_to_pg_map_supported_asics = ['mellanox', 'barefoot', 'marvell'] -%} + + +{ +{% if generate_tc_to_pg_map is defined %} + {{- generate_tc_to_pg_map() }} +{% else %} + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "AZURE": { + "0" : "1", + "1" : "1", + "2" : "1", + "3" : "3", + "4" : "4", + "5" : "2", + "6" : "1", + "7" : "1", + "8" : "0", + "9" : "1", + "10": "1", + "11": "1", + "12": "1", + "13": "1", + "14": "1", + "15": "1", + "16": "1", + "17": "1", + "18": "1", + "19": "1", + "20": "1", + "21": "1", + "22": "1", + "23": "1", + "24": "1", + "25": "1", + "26": "1", + "27": "1", + "28": "1", + "29": "1", + "30": "1", + "31": "1", + "32": "1", + "33": "1", + "34": "1", + "35": "1", + "36": "1", + "37": "1", + "38": "1", + "39": "1", + "40": "1", + "41": "1", + "42": "1", + "43": "1", + "44": "1", + "45": "1", + "46": "5", + "47": "1", + "48": "6", + "49": "1", + "50": "1", + "51": "1", + "52": "1", + "53": "1", + "54": "1", + "55": "1", + "56": "1", + "57": "1", + "58": "1", + "59": "1", + "60": "1", + "61": "1", + "62": "1", + "63": "1" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "14" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "15" + } + }, +{% if asic_type in pfc_to_pg_map_supported_asics %} + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "3": "3", + "4": "4" + } + }, +{% endif %} + "PORT_QOS_MAP": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]", +{% if asic_type in pfc_to_pg_map_supported_asics %} + "pfc_to_pg_map" : "[PFC_PRIORITY_TO_PRIORITY_GROUP_MAP|AZURE]", +{% endif %} + "pfc_enable" : "3,4" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/sai.profile b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/sai.profile new file mode 100644 index 0000000000..fc6a62e31f --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/td3-ix8a-bwde-48x25G+8x100G.config.bcm +SAI_NUM_ECMP_MEMBERS=64 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/td3-ix8a-bwde-48x25G+8x100G.config.bcm b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/td3-ix8a-bwde-48x25G+8x100G.config.bcm new file mode 100644 index 0000000000..6baa313b25 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/Quanta-IX8A-BWDE-56X/td3-ix8a-bwde-48x25G+8x100G.config.bcm @@ -0,0 +1,475 @@ +core_clock_frequency=1525 +dpp_clock_ratio=2:3 +parity_enable=1 +mem_cache_enable=0 +l2_mem_entries=40960 +l3_mem_entries=40960 +fpem_mem_entries=0 +l2xmsg_mode=1 +bcm_stat_flags=0 +l3_alpm_ipv6_128b_bkt_rsvd=1 + +#RIOT Enable +riot_enable=1 +riot_overlay_l3_intf_mem_size=4096 +riot_overlay_l3_egress_mem_size=32768 +l3_ecmp_levels=2 +riot_overlay_ecmp_resilient_hash_size=16384 + +bcm_num_cos=10 +default_cpu_tx_queue=9 +bcm_stat_interval=2000000 +cdma_timeout_usec=3000000 + +ifp_inports_support_enable=1 +ipv6_lpm_128b_enable=0x1 +l3_max_ecmp_mode=1 +l3_alpm_enable=2 +lpm_scaling_enable=0 + +miim_intr_enable=0 +module_64ports=1 + +schan_intr_enable=0 +skip_L2_USER_ENTRY=0 +stable_size=0x5500000 +tdma_timeout_usec=3000000 + +# portmap settings +oversubscribe_mode=1 +pbmp_xport_xe=0x3ffffffffffffffffffffffffffffffffe +port_flex_enable=1 +stable_size=0x5500000 + +#falcon core 0 flex [1:32] +portmap_1=1:25 +portmap_2=2:25 +portmap_3=3:25 +portmap_4=4:25 + +#falcon core 1 +portmap_5=5:25 +portmap_6=6:25 +portmap_7=7:25 +portmap_8=8:25 + +#falcon core 2 +portmap_9=9:25 +portmap_10=10:25 +portmap_11=11:25 +portmap_12=12:25 + +#falcon core 3 +portmap_13=13:25 +portmap_14=14:25 +portmap_15=15:25 +portmap_16=16:25 + +#falcon core 4 +portmap_17=17:25 +portmap_18=18:25 +portmap_19=19:25 +portmap_20=20:25 + +#falcon core 5 +portmap_21=21:25 +portmap_22=22:25 +portmap_23=23:25 +portmap_24=24:25 + +#falcon core 6 +portmap_25=25:100 + +#falcon core 7, port 56 supports breakout +portmap_26=29:100 + +#falcon core 8 +portmap_30=33:100 + +#falcon core 9 +portmap_31=37:100 + +#falcon core 10 flex [33:64], port 49 supports breakout +portmap_33=41:100 + +#falcon core 11 +portmap_37=45:100 + +#falcon core 12 +portmap_38=49:100 + +#falcon core 13 +portmap_39=53:100 + +#falcon core 14 +portmap_40=57:25 +portmap_41=58:25 +portmap_42=59:25 +portmap_43=60:25 + +#falcon core 15 +portmap_44=61:25 +portmap_45=62:25 +portmap_46=63:25 +portmap_47=64:25 + +#falcon core 16 +portmap_48=65:25 +portmap_49=66:25 +portmap_50=67:25 +portmap_51=68:25 + +#falcon core 17 +portmap_52=69:25 +portmap_53=70:25 +portmap_54=71:25 +portmap_55=72:25 + +#falcon core 18 +portmap_56=73:25 +portmap_57=74:25 +portmap_58=75:25 +portmap_59=76:25 + +#falcon core 19 +portmap_60=77:25 +portmap_61=78:25 +portmap_62=79:25 +portmap_63=80:25 + +# datapath port -- MerlinCore +#Hide these to prevent SAI from initializing them...they are physically not on system +#portmap_64=81:10:m + +### port remap + +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_40=25 +dport_map_port_41=26 +dport_map_port_42=27 +dport_map_port_43=28 + +dport_map_port_44=29 +dport_map_port_45=30 +dport_map_port_46=31 +dport_map_port_47=32 + +dport_map_port_48=33 +dport_map_port_49=34 +dport_map_port_50=35 +dport_map_port_51=36 + +dport_map_port_52=37 +dport_map_port_53=38 +dport_map_port_54=39 +dport_map_port_55=40 + +dport_map_port_56=41 +dport_map_port_57=42 +dport_map_port_58=43 +dport_map_port_59=44 + +dport_map_port_60=45 +dport_map_port_61=46 +dport_map_port_62=47 +dport_map_port_63=48 + +dport_map_port_33=49 +dport_map_port_34=50 +dport_map_port_35=51 +dport_map_port_36=52 +dport_map_port_37=53 +dport_map_port_38=54 +dport_map_port_39=55 + +dport_map_port_30=56 +dport_map_port_31=57 +dport_map_port_25=58 +dport_map_port_26=59 +dport_map_port_27=60 +dport_map_port_28=61 +dport_map_port_29=62 + +#dport_map_port_64=63 + +### lane swap and polarity follow physical port + +### FC0 +phy_chain_tx_lane_map_physical{1.0}=0x3210 +phy_chain_tx_polarity_flip_physical{1.0}=0x0 +phy_chain_tx_polarity_flip_physical{2.0}=0x0 +phy_chain_tx_polarity_flip_physical{3.0}=0x0 +phy_chain_tx_polarity_flip_physical{4.0}=0x0 +phy_chain_rx_lane_map_physical{1.0}=0x1320 +phy_chain_rx_polarity_flip_physical{1.0}=0x0 +phy_chain_rx_polarity_flip_physical{2.0}=0x1 +phy_chain_rx_polarity_flip_physical{3.0}=0x1 +phy_chain_rx_polarity_flip_physical{4.0}=0x0 + +### FC1 +phy_chain_tx_lane_map_physical{5.0}=0x0132 +phy_chain_tx_polarity_flip_physical{5.0}=0x0 +phy_chain_tx_polarity_flip_physical{6.0}=0x0 +phy_chain_tx_polarity_flip_physical{7.0}=0x1 +phy_chain_tx_polarity_flip_physical{8.0}=0x1 +phy_chain_rx_lane_map_physical{5.0}=0x1032 +phy_chain_rx_polarity_flip_physical{5.0}=0x1 +phy_chain_rx_polarity_flip_physical{6.0}=0x1 +phy_chain_rx_polarity_flip_physical{7.0}=0x1 +phy_chain_rx_polarity_flip_physical{8.0}=0x1 + +### FC2 +phy_chain_tx_lane_map_physical{9.0}=0x0123 +phy_chain_tx_polarity_flip_physical{9.0}=0x1 +phy_chain_tx_polarity_flip_physical{10.0}=0x1 +phy_chain_tx_polarity_flip_physical{11.0}=0x1 +phy_chain_tx_polarity_flip_physical{12.0}=0x1 +phy_chain_rx_lane_map_physical{9.0}=0x1032 +phy_chain_rx_polarity_flip_physical{9.0}=0x1 +phy_chain_rx_polarity_flip_physical{10.0}=0x1 +phy_chain_rx_polarity_flip_physical{11.0}=0x1 +phy_chain_rx_polarity_flip_physical{12.0}=0x1 + +### FC3 +phy_chain_tx_lane_map_physical{13.0}=0x0123 +phy_chain_tx_polarity_flip_physical{13.0}=0x1 +phy_chain_tx_polarity_flip_physical{14.0}=0x1 +phy_chain_tx_polarity_flip_physical{15.0}=0x1 +phy_chain_tx_polarity_flip_physical{16.0}=0x1 +phy_chain_rx_lane_map_physical{13.0}=0x1032 +phy_chain_rx_polarity_flip_physical{13.0}=0x1 +phy_chain_rx_polarity_flip_physical{14.0}=0x1 +phy_chain_rx_polarity_flip_physical{15.0}=0x1 +phy_chain_rx_polarity_flip_physical{16.0}=0x1 + +### FC4 +phy_chain_tx_lane_map_physical{17.0}=0x0123 +phy_chain_tx_polarity_flip_physical{17.0}=0x1 +phy_chain_tx_polarity_flip_physical{18.0}=0x0 +phy_chain_tx_polarity_flip_physical{19.0}=0x0 +phy_chain_tx_polarity_flip_physical{20.0}=0x0 +phy_chain_rx_lane_map_physical{17.0}=0x1032 +phy_chain_rx_polarity_flip_physical{17.0}=0x1 +phy_chain_rx_polarity_flip_physical{18.0}=0x0 +phy_chain_rx_polarity_flip_physical{19.0}=0x1 +phy_chain_rx_polarity_flip_physical{20.0}=0x1 + +### FC5 +phy_chain_tx_lane_map_physical{21.0}=0x0123 +phy_chain_tx_polarity_flip_physical{21.0}=0x0 +phy_chain_tx_polarity_flip_physical{22.0}=0x0 +phy_chain_tx_polarity_flip_physical{23.0}=0x0 +phy_chain_tx_polarity_flip_physical{24.0}=0x0 +phy_chain_rx_lane_map_physical{21.0}=0x1032 +phy_chain_rx_polarity_flip_physical{21.0}=0x0 +phy_chain_rx_polarity_flip_physical{22.0}=0x0 +phy_chain_rx_polarity_flip_physical{23.0}=0x0 +phy_chain_rx_polarity_flip_physical{24.0}=0x0 + +### FC6 +phy_chain_tx_lane_map_physical{25.0}=0x3021 +phy_chain_tx_polarity_flip_physical{25.0}=0x1 +phy_chain_tx_polarity_flip_physical{26.0}=0x1 +phy_chain_tx_polarity_flip_physical{27.0}=0x0 +phy_chain_tx_polarity_flip_physical{28.0}=0x0 +phy_chain_rx_lane_map_physical{25.0}=0x1032 +phy_chain_rx_polarity_flip_physical{25.0}=0x0 +phy_chain_rx_polarity_flip_physical{26.0}=0x0 +phy_chain_rx_polarity_flip_physical{27.0}=0x1 +phy_chain_rx_polarity_flip_physical{28.0}=0x0 + +### FC7 +phy_chain_tx_lane_map_physical{29.0}=0x0213 +phy_chain_tx_polarity_flip_physical{29.0}=0x1 +phy_chain_tx_polarity_flip_physical{30.0}=0x0 +phy_chain_tx_polarity_flip_physical{31.0}=0x0 +phy_chain_tx_polarity_flip_physical{32.0}=0x1 +phy_chain_rx_lane_map_physical{29.0}=0x1203 +phy_chain_rx_polarity_flip_physical{29.0}=0x0 +phy_chain_rx_polarity_flip_physical{30.0}=0x0 +phy_chain_rx_polarity_flip_physical{31.0}=0x0 +phy_chain_rx_polarity_flip_physical{32.0}=0x1 + +### FC8 +phy_chain_tx_lane_map_physical{33.0}=0x0213 +phy_chain_tx_polarity_flip_physical{33.0}=0x1 +phy_chain_tx_polarity_flip_physical{34.0}=0x0 +phy_chain_tx_polarity_flip_physical{35.0}=0x0 +phy_chain_tx_polarity_flip_physical{36.0}=0x0 +phy_chain_rx_lane_map_physical{33.0}=0x1302 +phy_chain_rx_polarity_flip_physical{33.0}=0x0 +phy_chain_rx_polarity_flip_physical{34.0}=0x1 +phy_chain_rx_polarity_flip_physical{35.0}=0x0 +phy_chain_rx_polarity_flip_physical{36.0}=0x0 + +### FC9 +phy_chain_tx_lane_map_physical{37.0}=0x3120 +phy_chain_tx_polarity_flip_physical{37.0}=0x1 +phy_chain_tx_polarity_flip_physical{38.0}=0x0 +phy_chain_tx_polarity_flip_physical{39.0}=0x0 +phy_chain_tx_polarity_flip_physical{40.0}=0x1 +phy_chain_rx_lane_map_physical{37.0}=0x2031 +phy_chain_rx_polarity_flip_physical{37.0}=0x0 +phy_chain_rx_polarity_flip_physical{38.0}=0x1 +phy_chain_rx_polarity_flip_physical{39.0}=0x0 +phy_chain_rx_polarity_flip_physical{40.0}=0x0 + +### FC10 +phy_chain_tx_lane_map_physical{41.0}=0x0213 +phy_chain_tx_polarity_flip_physical{41.0}=0x0 +phy_chain_tx_polarity_flip_physical{42.0}=0x0 +phy_chain_tx_polarity_flip_physical{43.0}=0x0 +phy_chain_tx_polarity_flip_physical{44.0}=0x1 +phy_chain_rx_lane_map_physical{41.0}=0x2013 +phy_chain_rx_polarity_flip_physical{41.0}=0x1 +phy_chain_rx_polarity_flip_physical{42.0}=0x0 +phy_chain_rx_polarity_flip_physical{43.0}=0x1 +phy_chain_rx_polarity_flip_physical{44.0}=0x1 + +### FC11 +phy_chain_tx_lane_map_physical{45.0}=0x2031 +phy_chain_tx_polarity_flip_physical{45.0}=0x1 +phy_chain_tx_polarity_flip_physical{46.0}=0x0 +phy_chain_tx_polarity_flip_physical{47.0}=0x0 +phy_chain_tx_polarity_flip_physical{48.0}=0x1 +phy_chain_rx_lane_map_physical{45.0}=0x2031 +phy_chain_rx_polarity_flip_physical{45.0}=0x1 +phy_chain_rx_polarity_flip_physical{46.0}=0x1 +phy_chain_rx_polarity_flip_physical{47.0}=0x0 +phy_chain_rx_polarity_flip_physical{48.0}=0x1 + +### FC12 +phy_chain_tx_lane_map_physical{49.0}=0x3120 +phy_chain_tx_polarity_flip_physical{49.0}=0x1 +phy_chain_tx_polarity_flip_physical{50.0}=0x0 +phy_chain_tx_polarity_flip_physical{51.0}=0x0 +phy_chain_tx_polarity_flip_physical{52.0}=0x1 +phy_chain_rx_lane_map_physical{49.0}=0x0123 +phy_chain_rx_polarity_flip_physical{49.0}=0x1 +phy_chain_rx_polarity_flip_physical{50.0}=0x1 +phy_chain_rx_polarity_flip_physical{51.0}=0x1 +phy_chain_rx_polarity_flip_physical{52.0}=0x0 + +### FC13 +phy_chain_tx_lane_map_physical{53.0}=0x0123 +phy_chain_tx_polarity_flip_physical{53.0}=0x1 +phy_chain_tx_polarity_flip_physical{54.0}=0x1 +phy_chain_tx_polarity_flip_physical{55.0}=0x1 +phy_chain_tx_polarity_flip_physical{56.0}=0x1 +phy_chain_rx_lane_map_physical{53.0}=0x0312 +phy_chain_rx_polarity_flip_physical{53.0}=0x1 +phy_chain_rx_polarity_flip_physical{54.0}=0x0 +phy_chain_rx_polarity_flip_physical{55.0}=0x0 +## This polarity filp is due to the reverse RX connection in HW +phy_chain_rx_polarity_flip_physical{56.0}=0x1 + +### FC14 +phy_chain_tx_lane_map_physical{57.0}=0x3210 +phy_chain_tx_polarity_flip_physical{57.0}=0x0 +phy_chain_tx_polarity_flip_physical{58.0}=0x0 +phy_chain_tx_polarity_flip_physical{59.0}=0x0 +phy_chain_tx_polarity_flip_physical{60.0}=0x0 +phy_chain_rx_lane_map_physical{57.0}=0x2301 +phy_chain_rx_polarity_flip_physical{57.0}=0x0 +phy_chain_rx_polarity_flip_physical{58.0}=0x0 +phy_chain_rx_polarity_flip_physical{59.0}=0x0 +phy_chain_rx_polarity_flip_physical{60.0}=0x0 + +### FC15 +phy_chain_tx_lane_map_physical{61.0}=0x3210 +phy_chain_tx_polarity_flip_physical{61.0}=0x0 +phy_chain_tx_polarity_flip_physical{62.0}=0x0 +phy_chain_tx_polarity_flip_physical{63.0}=0x0 +phy_chain_tx_polarity_flip_physical{64.0}=0x1 +phy_chain_rx_lane_map_physical{61.0}=0x2301 +phy_chain_rx_polarity_flip_physical{61.0}=0x1 +phy_chain_rx_polarity_flip_physical{62.0}=0x1 +phy_chain_rx_polarity_flip_physical{63.0}=0x0 +phy_chain_rx_polarity_flip_physical{64.0}=0x1 + +### FC16 +phy_chain_tx_lane_map_physical{65.0}=0x3210 +phy_chain_tx_polarity_flip_physical{65.0}=0x1 +phy_chain_tx_polarity_flip_physical{66.0}=0x1 +phy_chain_tx_polarity_flip_physical{67.0}=0x1 +phy_chain_tx_polarity_flip_physical{68.0}=0x1 +phy_chain_rx_lane_map_physical{65.0}=0x2301 +phy_chain_rx_polarity_flip_physical{65.0}=0x1 +phy_chain_rx_polarity_flip_physical{66.0}=0x1 +phy_chain_rx_polarity_flip_physical{67.0}=0x1 +phy_chain_rx_polarity_flip_physical{68.0}=0x1 + +### FC17 +phy_chain_tx_lane_map_physical{69.0}=0x3210 +phy_chain_tx_polarity_flip_physical{69.0}=0x1 +phy_chain_tx_polarity_flip_physical{70.0}=0x1 +phy_chain_tx_polarity_flip_physical{71.0}=0x1 +phy_chain_tx_polarity_flip_physical{72.0}=0x1 +phy_chain_rx_lane_map_physical{69.0}=0x2301 +phy_chain_rx_polarity_flip_physical{69.0}=0x1 +phy_chain_rx_polarity_flip_physical{70.0}=0x1 +phy_chain_rx_polarity_flip_physical{71.0}=0x1 +phy_chain_rx_polarity_flip_physical{72.0}=0x1 + +### FC18 +phy_chain_tx_lane_map_physical{73.0}=0x3210 +phy_chain_tx_polarity_flip_physical{73.0}=0x1 +phy_chain_tx_polarity_flip_physical{74.0}=0x1 +phy_chain_tx_polarity_flip_physical{75.0}=0x1 +phy_chain_tx_polarity_flip_physical{76.0}=0x1 +phy_chain_rx_lane_map_physical{73.0}=0x2301 +phy_chain_rx_polarity_flip_physical{73.0}=0x1 +phy_chain_rx_polarity_flip_physical{74.0}=0x1 +phy_chain_rx_polarity_flip_physical{75.0}=0x1 +phy_chain_rx_polarity_flip_physical{76.0}=0x1 + +### FC19 +phy_chain_tx_lane_map_physical{77.0}=0x0213 +phy_chain_tx_polarity_flip_physical{77.0}=0x0 +phy_chain_tx_polarity_flip_physical{78.0}=0x1 +phy_chain_tx_polarity_flip_physical{79.0}=0x1 +phy_chain_tx_polarity_flip_physical{80.0}=0x0 +phy_chain_rx_lane_map_physical{77.0}=0x0213 +phy_chain_rx_polarity_flip_physical{77.0}=0x0 +phy_chain_rx_polarity_flip_physical{78.0}=0x1 +phy_chain_rx_polarity_flip_physical{79.0}=0x1 +phy_chain_rx_polarity_flip_physical{80.0}=0x0 + +### MerlinCore +#phy_chain_tx_polarity_flip_physical{81.0}=0x0 +#phy_chain_rx_polarity_flip_physical{81.0}=0x0 + +l2_mem_entries=40960 +l3_mem_entries=40960 +l3_alpm_enable=2 +use_all_splithorizon_groups=1 + diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/custom_led.bin b/device/quanta/x86_64-quanta_ix8a_bwde-r0/custom_led.bin new file mode 100644 index 0000000000..4902628c7f Binary files /dev/null and b/device/quanta/x86_64-quanta_ix8a_bwde-r0/custom_led.bin differ diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/default_sku b/device/quanta/x86_64-quanta_ix8a_bwde-r0/default_sku new file mode 100644 index 0000000000..377de21e65 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/default_sku @@ -0,0 +1 @@ +Quanta-IX8A-BWDE-56X t1 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/installer.conf b/device/quanta/x86_64-quanta_ix8a_bwde-r0/installer.conf new file mode 100644 index 0000000000..925a32fc0c --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/installer.conf @@ -0,0 +1,3 @@ +CONSOLE_PORT=0x3f8 +CONSOLE_DEV=0 +CONSOLE_SPEED=115200 diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/led_proc_init.soc b/device/quanta/x86_64-quanta_ix8a_bwde-r0/led_proc_init.soc new file mode 100644 index 0000000000..dac21e51e4 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/led_proc_init.soc @@ -0,0 +1,3 @@ +m0 load 0 0x3800 /usr/share/sonic/platform/custom_led.bin +led start +rcload /usr/share/sonic/platform/preemphasis-48x25_8x100.soc diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/eeprom.py b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/eeprom.py new file mode 100644 index 0000000000..0a6121c3cd --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/eeprom.py @@ -0,0 +1,12 @@ +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/fanutil.py b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/fanutil.py new file mode 100644 index 0000000000..2cf72ddf7e --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/fanutil.py @@ -0,0 +1,110 @@ +# +# fanutil.py +# Platform-specific Fan status interface for SONiC +# + +import logging +import os.path + +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""" + + SYS_FAN_NUM = 6 + NUM_FANS_PERTRAY = 2 + HWMON_PATH = '/sys/class/hwmon/hwmon2/' + FAN_INDEX_START = 18 + + logger = logging.getLogger(__name__) + + def __init__(self, log_level=logging.DEBUG): + FanBase.__init__(self) + self.num_fans = (self.SYS_FAN_NUM * self.NUM_FANS_PERTRAY) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def check_fan_index(self, index): + if index is None: + return False + + if index < 1 or index > self.num_fans: + logging.error("Invalid Fan index:", index) + return False + + return True + + def get_num_fans(self): + return self.num_fans + + def get_status(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + if fantray_speed == '0.0' : + return False + + return True + + def get_presence(self, index): + if self.check_fan_index(index) == False: + return False + + fantray_present_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_present' + fantray_present = self.get_attr_value(self.HWMON_PATH + fantray_present_file) + + if fantray_present == '1' : + return True + + return False + + def get_direction(self, index): + if self.check_fan_index(index) == False: + return None + + fantray_direction_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_direction' + fantray_direction = self.get_attr_value(self.HWMON_PATH + fantray_direction_file) + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if fantray_direction == '2': + return "INTAKE" + else: + return "EXHAUST" + + def get_speed(self, index): + if self.check_fan_index(index) == False: + return 0 + + fantray_speed_file = 'fan' + str(self.FAN_INDEX_START+(index-1)) + '_input' + fantray_speed = self.get_attr_value(self.HWMON_PATH + fantray_speed_file) + + return int(float(fantray_speed)) + + + def set_speed(self, val): + logging.error("Not allowed to set fan speed!") + + return False diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/psuutil.py b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/psuutil.py new file mode 100644 index 0000000000..2394ad0ea0 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/psuutil.py @@ -0,0 +1,250 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + +import logging +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + HWMON_PATH = '/sys/class/hwmon/hwmon1/' + PSU1_PREFIX = 'power114_' + PSU2_PREFIX = 'power126_' + MAX_PSUS = 2 + def __init__(self): + PsuBase.__init__(self) + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + return retval + + def get_attr_filename(self, index, attr): + if (index == 1): + attr_file = self.PSU1_PREFIX + attr + elif (index == 2): + attr_file = self.PSU2_PREFIX + attr + else: + logging.error("Invalid PSU number:", index) + return '' + + return attr_file + + 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 + """ + + return self.MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by 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 = False + + attr_filename = self.get_attr_filename(index, 'present') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check PSU status + if (attr_value == 1): + status = True + return status + + def get_powergood_status(self, index): + status = False + + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return status + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + + # Check PSU status + if (attr_value != 0.0): + status = True + + return status + + def get_model(self, index): + attr_filename = self.get_attr_filename(index, 'model') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_mfr_id(self, index): + attr_filename = self.get_attr_filename(index, 'mfrid') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_serial(self, index): + attr_filename = self.get_attr_filename(index, 'sn') + if attr_filename == '': + return None + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + return attr_value.rstrip() + + def get_direction(self, index): + if (index == 1): + direction_file = 'fan120_direction' + elif (index == 2): + direction_file = 'fan132_direction' + else: + logging.error("Invalid PSU number:", index) + return None + + direction = self.get_attr_value(self.HWMON_PATH + direction_file) + direction = direction.rstrip() + + """ + 1: FB 2: BF + Since the fan is at rear of the switch, FB means Exhaust; BF means Intake + """ + if direction == '"\"': + return "INTAKE" + else: + return "EXHAUST" + + def get_output_voltage(self, index): + if (index == 1): + attr_file = 'in129_input' + elif (index == 2): + attr_file = 'in124_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + voltage = self.get_attr_value(self.HWMON_PATH + attr_file) + voltage = voltage.rstrip() + + if (voltage != 'ERR'): + voltage, dummy = voltage.split('.', 1) + else: + return 0.0 + + return float(voltage)/1000 + + def get_output_current(self, index): + if (index == 1): + attr_file = 'curr130_input' + elif (index == 2): + attr_file = 'curr115_input' + else: + logging.error("Invalid PSU number:", index) + return 0.0 + + current = self.get_attr_value(self.HWMON_PATH + attr_file) + current = current.rstrip() + + if (current != 'ERR'): + current, dummy = current.split('.',1) + else: + return 0.0 + + return float(current)/1000 + + def get_output_power(self, index): + attr_filename = self.get_attr_filename(index, 'input') + if attr_filename == '': + return 0.0 + + attr_path = self.HWMON_PATH + attr_filename + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = float(attr_value) + else: + return 0.0 + + return float(attr_value/1000) + + def get_fan_rpm(self, index, fan_idx): + if (index == 1): + rpm_file = 'fan120_input' + elif (index == 2): + rpm_file = 'fan132_input' + else: + logging.error("Invalid PSU number:", index) + return 0 + + rpm = self.get_attr_value(self.HWMON_PATH + rpm_file) + rpm = rpm.rstrip() + if (rpm != 'ERR'): + rpm = float(rpm) + else: + return 0 + + return int(rpm) diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/sfputil.py b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/sfputil.py new file mode 100644 index 0000000000..3479e46f1f --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/plugins/sfputil.py @@ -0,0 +1,213 @@ +# sfputil.py +# +# Platform-specific SFP transceiver interface for SONiC +# + +try: + import time + 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 = 56 + PORTS_IN_BLOCK = 56 + QSFP_PORT_START = 49 + QSFP_PORT_END = 56 + + _port_to_eeprom_mapping = {} + _port_to_i2c_mapping = { + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44, + 33 : 45, + 34 : 46, + 35 : 47, + 36 : 48, + 37 : 49, + 38 : 50, + 39 : 51, + 40 : 52, + 41 : 53, + 42 : 54, + 43 : 55, + 44 : 56, + 45 : 57, + 46 : 58, + 47 : 59, + 48 : 60, + 49 : 61,#QSFP49 + 50 : 62,#QSFP50 + 51 : 63,#QSFP51 + 52 : 64,#QSFP52 + 53 : 65,#QSFP53 + 54 : 66,#QSFP54 + 55 : 67,#QSFP55 + 56 : 68,#QSFP56 + } + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + def __init__(self): + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + for x in range(self.port_start, self.port_end+1): + self.port_to_eeprom_mapping[x] = eeprom_path.format(self._port_to_i2c_mapping[x]) + SfpUtilBase.__init__(self) + + 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 + + try: + if port_num < self.qsfp_port_start: + reg_file = open("/sys/class/cpld-sfp28/port-"+str(port_num)+"/pre_n") + else: + reg_file = open("/sys/class/gpio/gpio"+str((port_num-self.qsfp_port_start)*4+34)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + if port_num < self.qsfp_port_start: + if reg_value == '1': + return True + else: + if reg_value == '0': + return True + + return False + + def get_low_power_mode(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + reg_file = open("/sys/class/gpio/gpio"+str((port_num-self.qsfp_port_start)*4+35)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = int(reg_file.readline().rstrip()) + + if reg_value == 0: + return False + + return True + + def set_low_power_mode(self, port_num, lpmode): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.qsfp_port_end: + return False + + try: + reg_file = open("/sys/class/gpio/gpio"+str((port_num-self.qsfp_port_start)*4+35)+"/value", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def reset(self, port_num): + # Check for invalid port_num + if port_num < self.qsfp_port_start or port_num > self.port_end: + return False + + try: + reg_file = open("/sys/class/gpio/gpio"+str((port_num-self.qsfp_port_start)*4+32)+"/value", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open("/sys/class/gpio/gpio"+str((port_num-self.qsfp_port_start)*4+32)+"/value", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def get_transceiver_change_event(self): + """ + TODO: This function need to be implemented + when decide to support monitoring SFP(Xcvrd) + on this platform. + """ + raise NotImplementedError diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/pmon_daemon_control.json b/device/quanta/x86_64-quanta_ix8a_bwde-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..94592fa8ce --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/pmon_daemon_control.json @@ -0,0 +1,3 @@ +{ + "skip_ledd": true +} diff --git a/device/quanta/x86_64-quanta_ix8a_bwde-r0/preemphasis-48x25_8x100.soc b/device/quanta/x86_64-quanta_ix8a_bwde-r0/preemphasis-48x25_8x100.soc new file mode 100644 index 0000000000..00192697ff --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8a_bwde-r0/preemphasis-48x25_8x100.soc @@ -0,0 +1,349 @@ +# 48x25G 8x100G pre-emphasis setting for Quanta IX8A-BWDE +echo "Set tx pre-emphasis and idriver values" +linkscan off + +# Start of 48x25G + +phy raw c45 0x81 0x1 0xffde 0 +phy raw c45 0x81 0x1 0xd130 0x32 +phy raw c45 0x81 0x1 0xd131 0x306 +phy raw c45 0x81 0x1 0xd134 0x1 +phy raw c45 0x81 0x1 0xffde 1 +phy raw c45 0x81 0x1 0xd130 0x32 +phy raw c45 0x81 0x1 0xd131 0x306 +phy raw c45 0x81 0x1 0xd134 0x1 +phy raw c45 0x81 0x1 0xffde 2 +phy raw c45 0x81 0x1 0xd130 0x32 +phy raw c45 0x81 0x1 0xd131 0x306 +phy raw c45 0x81 0x1 0xd134 0x1 +phy raw c45 0x81 0x1 0xffde 3 +phy raw c45 0x81 0x1 0xd130 0x32 +phy raw c45 0x81 0x1 0xd131 0x306 +phy raw c45 0x81 0x1 0xd134 0x1 + +phy raw c45 0x85 0x1 0xffde 0 +phy raw c45 0x85 0x1 0xd130 0x32 +phy raw c45 0x85 0x1 0xd131 0x306 +phy raw c45 0x85 0x1 0xd134 0x1 +phy raw c45 0x85 0x1 0xffde 1 +phy raw c45 0x85 0x1 0xd130 0x32 +phy raw c45 0x85 0x1 0xd131 0x306 +phy raw c45 0x85 0x1 0xd134 0x1 +phy raw c45 0x85 0x1 0xffde 2 +phy raw c45 0x85 0x1 0xd130 0x32 +phy raw c45 0x85 0x1 0xd131 0x306 +phy raw c45 0x85 0x1 0xd134 0x1 +phy raw c45 0x85 0x1 0xffde 3 +phy raw c45 0x85 0x1 0xd130 0x32 +phy raw c45 0x85 0x1 0xd131 0x306 +phy raw c45 0x85 0x1 0xd134 0x1 + +phy raw c45 0x89 0x1 0xffde 0 +phy raw c45 0x89 0x1 0xd130 0x32 +phy raw c45 0x89 0x1 0xd131 0x306 +phy raw c45 0x89 0x1 0xd134 0x1 +phy raw c45 0x89 0x1 0xffde 1 +phy raw c45 0x89 0x1 0xd130 0x32 +phy raw c45 0x89 0x1 0xd131 0x306 +phy raw c45 0x89 0x1 0xd134 0x1 +phy raw c45 0x89 0x1 0xffde 2 +phy raw c45 0x89 0x1 0xd130 0x32 +phy raw c45 0x89 0x1 0xd131 0x306 +phy raw c45 0x89 0x1 0xd134 0x1 +phy raw c45 0x89 0x1 0xffde 3 +phy raw c45 0x89 0x1 0xd130 0x32 +phy raw c45 0x89 0x1 0xd131 0x306 +phy raw c45 0x89 0x1 0xd134 0x1 + +phy raw c45 0x8d 0x1 0xffde 0 +phy raw c45 0x8d 0x1 0xd130 0x32 +phy raw c45 0x8d 0x1 0xd131 0x306 +phy raw c45 0x8d 0x1 0xd134 0x1 +phy raw c45 0x8d 0x1 0xffde 1 +phy raw c45 0x8d 0x1 0xd130 0x32 +phy raw c45 0x8d 0x1 0xd131 0x306 +phy raw c45 0x8d 0x1 0xd134 0x1 +phy raw c45 0x8d 0x1 0xffde 2 +phy raw c45 0x8d 0x1 0xd130 0x32 +phy raw c45 0x8d 0x1 0xd131 0x306 +phy raw c45 0x8d 0x1 0xd134 0x1 +phy raw c45 0x8d 0x1 0xffde 3 +phy raw c45 0x8d 0x1 0xd130 0x32 +phy raw c45 0x8d 0x1 0xd131 0x306 +phy raw c45 0x8d 0x1 0xd134 0x1 + +phy raw c45 0x91 0x1 0xffde 0 +phy raw c45 0x91 0x1 0xd130 0x32 +phy raw c45 0x91 0x1 0xd131 0x306 +phy raw c45 0x91 0x1 0xd134 0x1 +phy raw c45 0x91 0x1 0xffde 1 +phy raw c45 0x91 0x1 0xd130 0x32 +phy raw c45 0x91 0x1 0xd131 0x306 +phy raw c45 0x91 0x1 0xd134 0x1 +phy raw c45 0x91 0x1 0xffde 2 +phy raw c45 0x91 0x1 0xd130 0x32 +phy raw c45 0x91 0x1 0xd131 0x306 +phy raw c45 0x91 0x1 0xd134 0x1 +phy raw c45 0x91 0x1 0xffde 3 +phy raw c45 0x91 0x1 0xd130 0x32 +phy raw c45 0x91 0x1 0xd131 0x306 +phy raw c45 0x91 0x1 0xd134 0x1 + +phy raw c45 0xa1 0x1 0xffde 0 +phy raw c45 0xa1 0x1 0xd130 0x32 +phy raw c45 0xa1 0x1 0xd131 0x306 +phy raw c45 0xa1 0x1 0xd134 0x1 +phy raw c45 0xa1 0x1 0xffde 1 +phy raw c45 0xa1 0x1 0xd130 0x32 +phy raw c45 0xa1 0x1 0xd131 0x306 +phy raw c45 0xa1 0x1 0xd134 0x1 +phy raw c45 0xa1 0x1 0xffde 2 +phy raw c45 0xa1 0x1 0xd130 0x32 +phy raw c45 0xa1 0x1 0xd131 0x306 +phy raw c45 0xa1 0x1 0xd134 0x1 +phy raw c45 0xa1 0x1 0xffde 3 +phy raw c45 0xa1 0x1 0xd130 0x32 +phy raw c45 0xa1 0x1 0xd131 0x306 +phy raw c45 0xa1 0x1 0xd134 0x1 + +phy raw c45 0xd1 0x1 0xffde 0 +phy raw c45 0xd1 0x1 0xd130 0x32 +phy raw c45 0xd1 0x1 0xd131 0x306 +phy raw c45 0xd1 0x1 0xd134 0x1 +phy raw c45 0xd1 0x1 0xffde 1 +phy raw c45 0xd1 0x1 0xd130 0x32 +phy raw c45 0xd1 0x1 0xd131 0x306 +phy raw c45 0xd1 0x1 0xd134 0x1 +phy raw c45 0xd1 0x1 0xffde 2 +phy raw c45 0xd1 0x1 0xd130 0x32 +phy raw c45 0xd1 0x1 0xd131 0x306 +phy raw c45 0xd1 0x1 0xd134 0x1 +phy raw c45 0xd1 0x1 0xffde 3 +phy raw c45 0xd1 0x1 0xd130 0x32 +phy raw c45 0xd1 0x1 0xd131 0x306 +phy raw c45 0xd1 0x1 0xd134 0x1 + +phy raw c45 0xe1 0x1 0xffde 0 +phy raw c45 0xe1 0x1 0xd130 0x32 +phy raw c45 0xe1 0x1 0xd131 0x306 +phy raw c45 0xe1 0x1 0xd134 0x1 +phy raw c45 0xe1 0x1 0xffde 1 +phy raw c45 0xe1 0x1 0xd130 0x32 +phy raw c45 0xe1 0x1 0xd131 0x306 +phy raw c45 0xe1 0x1 0xd134 0x1 +phy raw c45 0xe1 0x1 0xffde 2 +phy raw c45 0xe1 0x1 0xd130 0x32 +phy raw c45 0xe1 0x1 0xd131 0x306 +phy raw c45 0xe1 0x1 0xd134 0x1 +phy raw c45 0xe1 0x1 0xffde 3 +phy raw c45 0xe1 0x1 0xd130 0x32 +phy raw c45 0xe1 0x1 0xd131 0x306 +phy raw c45 0xe1 0x1 0xd134 0x1 + +phy raw c45 0xe5 0x1 0xffde 0 +phy raw c45 0xe5 0x1 0xd130 0x32 +phy raw c45 0xe5 0x1 0xd131 0x306 +phy raw c45 0xe5 0x1 0xd134 0x1 +phy raw c45 0xe5 0x1 0xffde 1 +phy raw c45 0xe5 0x1 0xd130 0x32 +phy raw c45 0xe5 0x1 0xd131 0x306 +phy raw c45 0xe5 0x1 0xd134 0x1 +phy raw c45 0xe5 0x1 0xffde 2 +phy raw c45 0xe5 0x1 0xd130 0x32 +phy raw c45 0xe5 0x1 0xd131 0x306 +phy raw c45 0xe5 0x1 0xd134 0x1 +phy raw c45 0xe5 0x1 0xffde 3 +phy raw c45 0xe5 0x1 0xd130 0x32 +phy raw c45 0xe5 0x1 0xd131 0x306 +phy raw c45 0xe5 0x1 0xd134 0x1 + +phy raw c45 0xe9 0x1 0xffde 0 +phy raw c45 0xe9 0x1 0xd130 0x32 +phy raw c45 0xe9 0x1 0xd131 0x306 +phy raw c45 0xe9 0x1 0xd134 0x1 +phy raw c45 0xe9 0x1 0xffde 1 +phy raw c45 0xe9 0x1 0xd130 0x32 +phy raw c45 0xe9 0x1 0xd131 0x306 +phy raw c45 0xe9 0x1 0xd134 0x1 +phy raw c45 0xe9 0x1 0xffde 2 +phy raw c45 0xe9 0x1 0xd130 0x32 +phy raw c45 0xe9 0x1 0xd131 0x306 +phy raw c45 0xe9 0x1 0xd134 0x1 +phy raw c45 0xe9 0x1 0xffde 3 +phy raw c45 0xe9 0x1 0xd130 0x32 +phy raw c45 0xe9 0x1 0xd131 0x306 +phy raw c45 0xe9 0x1 0xd134 0x1 + +phy raw c45 0xed 0x1 0xffde 0 +phy raw c45 0xed 0x1 0xd130 0x32 +phy raw c45 0xed 0x1 0xd131 0x306 +phy raw c45 0xed 0x1 0xd134 0x1 +phy raw c45 0xed 0x1 0xffde 1 +phy raw c45 0xed 0x1 0xd130 0x32 +phy raw c45 0xed 0x1 0xd131 0x306 +phy raw c45 0xed 0x1 0xd134 0x1 +phy raw c45 0xed 0x1 0xffde 2 +phy raw c45 0xed 0x1 0xd130 0x32 +phy raw c45 0xed 0x1 0xd131 0x306 +phy raw c45 0xed 0x1 0xd134 0x1 +phy raw c45 0xed 0x1 0xffde 3 +phy raw c45 0xed 0x1 0xd130 0x32 +phy raw c45 0xed 0x1 0xd131 0x306 +phy raw c45 0xed 0x1 0xd134 0x1 + +phy raw c45 0xf1 0x1 0xffde 0 +phy raw c45 0xf1 0x1 0xd130 0x32 +phy raw c45 0xf1 0x1 0xd131 0x306 +phy raw c45 0xf1 0x1 0xd134 0x1 +phy raw c45 0xf1 0x1 0xffde 1 +phy raw c45 0xf1 0x1 0xd130 0x32 +phy raw c45 0xf1 0x1 0xd131 0x306 +phy raw c45 0xf1 0x1 0xd134 0x1 +phy raw c45 0xf1 0x1 0xffde 2 +phy raw c45 0xf1 0x1 0xd130 0x32 +phy raw c45 0xf1 0x1 0xd131 0x306 +phy raw c45 0xf1 0x1 0xd134 0x1 +phy raw c45 0xf1 0x1 0xffde 3 +phy raw c45 0xf1 0x1 0xd130 0x32 +phy raw c45 0xf1 0x1 0xd131 0x306 +phy raw c45 0xf1 0x1 0xd134 0x1 + +# Start of 8x100G + +phy raw c45 0xc1 0x1 0xffde 0 +phy raw c45 0xc1 0x1 0xd130 0x50 +phy raw c45 0xc1 0x1 0xd131 0xa0a +phy raw c45 0xc1 0x1 0xd134 0x1 +phy raw c45 0xc1 0x1 0xffde 1 +phy raw c45 0xc1 0x1 0xd130 0x50 +phy raw c45 0xc1 0x1 0xd131 0xa0a +phy raw c45 0xc1 0x1 0xd134 0x1 +phy raw c45 0xc1 0x1 0xffde 2 +phy raw c45 0xc1 0x1 0xd130 0x50 +phy raw c45 0xc1 0x1 0xd131 0xa0a +phy raw c45 0xc1 0x1 0xd134 0x1 +phy raw c45 0xc1 0x1 0xffde 3 +phy raw c45 0xc1 0x1 0xd130 0x50 +phy raw c45 0xc1 0x1 0xd131 0xa0a +phy raw c45 0xc1 0x1 0xd134 0x1 + +phy raw c45 0xc5 0x1 0xffde 0 +phy raw c45 0xc5 0x1 0xd130 0x50 +phy raw c45 0xc5 0x1 0xd131 0xa0a +phy raw c45 0xc5 0x1 0xd134 0x1 +phy raw c45 0xc5 0x1 0xffde 1 +phy raw c45 0xc5 0x1 0xd130 0x50 +phy raw c45 0xc5 0x1 0xd131 0xa0a +phy raw c45 0xc5 0x1 0xd134 0x1 +phy raw c45 0xc5 0x1 0xffde 2 +phy raw c45 0xc5 0x1 0xd130 0x50 +phy raw c45 0xc5 0x1 0xd131 0xa0a +phy raw c45 0xc5 0x1 0xd134 0x1 +phy raw c45 0xc5 0x1 0xffde 3 +phy raw c45 0xc5 0x1 0xd130 0x50 +phy raw c45 0xc5 0x1 0xd131 0xa0a +phy raw c45 0xc5 0x1 0xd134 0x1 + +phy raw c45 0xc9 0x1 0xffde 0 +phy raw c45 0xc9 0x1 0xd130 0x50 +phy raw c45 0xc9 0x1 0xd131 0xa0a +phy raw c45 0xc9 0x1 0xd134 0x1 +phy raw c45 0xc9 0x1 0xffde 1 +phy raw c45 0xc9 0x1 0xd130 0x50 +phy raw c45 0xc9 0x1 0xd131 0xa0a +phy raw c45 0xc9 0x1 0xd134 0x1 +phy raw c45 0xc9 0x1 0xffde 2 +phy raw c45 0xc9 0x1 0xd130 0x50 +phy raw c45 0xc9 0x1 0xd131 0xa0a +phy raw c45 0xc9 0x1 0xd134 0x1 +phy raw c45 0xc9 0x1 0xffde 3 +phy raw c45 0xc9 0x1 0xd130 0x50 +phy raw c45 0xc9 0x1 0xd131 0xa0a +phy raw c45 0xc9 0x1 0xd134 0x1 + +phy raw c45 0xcd 0x1 0xffde 0 +phy raw c45 0xcd 0x1 0xd130 0x50 +phy raw c45 0xcd 0x1 0xd131 0xa0a +phy raw c45 0xcd 0x1 0xd134 0x1 +phy raw c45 0xcd 0x1 0xffde 1 +phy raw c45 0xcd 0x1 0xd130 0x50 +phy raw c45 0xcd 0x1 0xd131 0xa0a +phy raw c45 0xcd 0x1 0xd134 0x1 +phy raw c45 0xcd 0x1 0xffde 2 +phy raw c45 0xcd 0x1 0xd130 0x50 +phy raw c45 0xcd 0x1 0xd131 0xa0a +phy raw c45 0xcd 0x1 0xd134 0x1 +phy raw c45 0xcd 0x1 0xffde 3 +phy raw c45 0xcd 0x1 0xd130 0x50 +phy raw c45 0xcd 0x1 0xd131 0xa0a +phy raw c45 0xcd 0x1 0xd134 0x1 + +phy raw c45 0xad 0x1 0xffde 0 +phy raw c45 0xad 0x1 0xd130 0x50 +phy raw c45 0xad 0x1 0xd131 0xa0a +phy raw c45 0xad 0x1 0xd134 0x1 +phy raw c45 0xad 0x1 0xffde 1 +phy raw c45 0xad 0x1 0xd130 0x50 +phy raw c45 0xad 0x1 0xd131 0xa0a +phy raw c45 0xad 0x1 0xd134 0x1 +phy raw c45 0xad 0x1 0xffde 2 +phy raw c45 0xad 0x1 0xd130 0x50 +phy raw c45 0xad 0x1 0xd131 0xa0a +phy raw c45 0xad 0x1 0xd134 0x1 +phy raw c45 0xad 0x1 0xffde 3 +phy raw c45 0xad 0x1 0xd130 0x50 +phy raw c45 0xad 0x1 0xd131 0xa0a +phy raw c45 0xad 0x1 0xd134 0x1 + +phy raw c45 0xb1 0x1 0xffde 0 +phy raw c45 0xb1 0x1 0xd130 0x50 +phy raw c45 0xb1 0x1 0xd131 0xa0a +phy raw c45 0xb1 0x1 0xd134 0x1 +phy raw c45 0xb1 0x1 0xffde 1 +phy raw c45 0xb1 0x1 0xd130 0x50 +phy raw c45 0xb1 0x1 0xd131 0xa0a +phy raw c45 0xb1 0x1 0xd134 0x1 +phy raw c45 0xb1 0x1 0xffde 2 +phy raw c45 0xb1 0x1 0xd130 0x50 +phy raw c45 0xb1 0x1 0xd131 0xa0a +phy raw c45 0xb1 0x1 0xd134 0x1 +phy raw c45 0xb1 0x1 0xffde 3 +phy raw c45 0xb1 0x1 0xd130 0x50 +phy raw c45 0xb1 0x1 0xd131 0xa0a +phy raw c45 0xb1 0x1 0xd134 0x1 + +phy raw c45 0xa5 0x1 0xffde 0 +phy raw c45 0xa5 0x1 0xd130 0x50 +phy raw c45 0xa5 0x1 0xd131 0xa0a +phy raw c45 0xa5 0x1 0xd134 0x1 +phy raw c45 0xa5 0x1 0xffde 1 +phy raw c45 0xa5 0x1 0xd130 0x50 +phy raw c45 0xa5 0x1 0xd131 0xa0a +phy raw c45 0xa5 0x1 0xd134 0x1 +phy raw c45 0xa5 0x1 0xffde 2 +phy raw c45 0xa5 0x1 0xd130 0x50 +phy raw c45 0xa5 0x1 0xd131 0xa0a +phy raw c45 0xa5 0x1 0xd134 0x1 +phy raw c45 0xa5 0x1 0xffde 3 +phy raw c45 0xa5 0x1 0xd130 0x50 +phy raw c45 0xa5 0x1 0xd131 0xa0a +phy raw c45 0xa5 0x1 0xd134 0x1 + +phy raw c45 0xa9 0x1 0xffde 0 +phy raw c45 0xa9 0x1 0xd130 0x50 +phy raw c45 0xa9 0x1 0xd131 0xa0a +phy raw c45 0xa9 0x1 0xd134 0x1 +phy raw c45 0xa9 0x1 0xffde 1 +phy raw c45 0xa9 0x1 0xd130 0x50 +phy raw c45 0xa9 0x1 0xd131 0xa0a +phy raw c45 0xa9 0x1 0xd134 0x1 +phy raw c45 0xa9 0x1 0xffde 2 +phy raw c45 0xa9 0x1 0xd130 0x50 +phy raw c45 0xa9 0x1 0xd131 0xa0a +phy raw c45 0xa9 0x1 0xd134 0x1 +phy raw c45 0xa9 0x1 0xffde 3 +phy raw c45 0xa9 0x1 0xd130 0x50 +phy raw c45 0xa9 0x1 0xd131 0xa0a +phy raw c45 0xa9 0x1 0xd134 0x1 + +linkscan on \ No newline at end of file diff --git a/device/quanta/x86_64-quanta_ix8c_bwde-r0/Quanta-IX8C-56X/td3-ix8c-48x25G+8x100G.config.bcm b/device/quanta/x86_64-quanta_ix8c_bwde-r0/Quanta-IX8C-56X/td3-ix8c-48x25G+8x100G.config.bcm index 94560fb7e8..bf2248fbe4 100644 --- a/device/quanta/x86_64-quanta_ix8c_bwde-r0/Quanta-IX8C-56X/td3-ix8c-48x25G+8x100G.config.bcm +++ b/device/quanta/x86_64-quanta_ix8c_bwde-r0/Quanta-IX8C-56X/td3-ix8c-48x25G+8x100G.config.bcm @@ -2,7 +2,6 @@ sai_load_hw_config=/etc/bcm/flex/bcm56870_a0_issu/b870.6.4.1/ bcm_tunnel_term_compatible_mode=1 core_clock_frequency=1525 dpp_clock_ratio=2:3 -parity_enable=0 mem_cache_enable=0 l2_mem_entries=40960 l3_mem_entries=40960 @@ -91,8 +90,8 @@ portmap_123=121:100 portmap_127=125:100 # datapath port -- MerlinCore -portmap_66=129:10:m -portmap_130=128:10:m +#portmap_66=129:10:m +#portmap_130=128:10:m # loopback port portmap_65=130:10 @@ -479,3 +478,85 @@ phy_chain_rx_polarity_flip_physical{130.0}=0x0 phy_chain_rx_polarity_flip_physical{131.0}=0x0 phy_chain_rx_polarity_flip_physical{132.0}=0x0 + +serdes_preemphasis_1=0x35503 +serdes_preemphasis_2=0x35503 +serdes_preemphasis_3=0x35503 +serdes_preemphasis_4=0x35503 +serdes_preemphasis_5=0x35503 +serdes_preemphasis_6=0x35503 +serdes_preemphasis_7=0x35503 +serdes_preemphasis_8=0x35503 +serdes_preemphasis_13=0x35503 +serdes_preemphasis_14=0x35503 +serdes_preemphasis_15=0x35503 +serdes_preemphasis_16=0x35503 +serdes_preemphasis_21=0x35503 +serdes_preemphasis_22=0x35503 +serdes_preemphasis_23=0x35503 +serdes_preemphasis_24=0x35503 +serdes_preemphasis_29=0x35503 +serdes_preemphasis_30=0x35503 +serdes_preemphasis_31=0x35503 +serdes_preemphasis_32=0x35503 +serdes_preemphasis_33=0x35503 +serdes_preemphasis_34=0x35503 +serdes_preemphasis_35=0x35503 +serdes_preemphasis_36=0x35503 +serdes_preemphasis_41=0x35503 +serdes_preemphasis_42=0x35503 +serdes_preemphasis_43=0x35503 +serdes_preemphasis_44=0x35503 +serdes_preemphasis_49=0x35503 +serdes_preemphasis_50=0x35503 +serdes_preemphasis_51=0x35503 +serdes_preemphasis_52=0x35503 +serdes_preemphasis_57=0x35503 +serdes_preemphasis_58=0x35503 +serdes_preemphasis_59=0x35503 +serdes_preemphasis_60=0x35503 +serdes_preemphasis_61=0x35503 +serdes_preemphasis_62=0x35503 +serdes_preemphasis_63=0x35503 +serdes_preemphasis_64=0x35503 +serdes_preemphasis_lane0_67=0x25905 +serdes_preemphasis_lane1_67=0x25905 +serdes_preemphasis_lane2_67=0x25905 +serdes_preemphasis_lane3_67=0x25905 +serdes_preemphasis_lane0_71=0x25905 +serdes_preemphasis_lane1_71=0x25905 +serdes_preemphasis_lane2_71=0x25905 +serdes_preemphasis_lane3_71=0x25905 +serdes_preemphasis_lane0_79=0x25905 +serdes_preemphasis_lane1_79=0x25905 +serdes_preemphasis_lane2_79=0x25905 +serdes_preemphasis_lane3_79=0x25905 +serdes_preemphasis_87=0x35503 +serdes_preemphasis_88=0x35503 +serdes_preemphasis_89=0x35503 +serdes_preemphasis_90=0x35503 +serdes_preemphasis_95=0x35503 +serdes_preemphasis_96=0x35503 +serdes_preemphasis_97=0x35503 +serdes_preemphasis_98=0x35503 +serdes_preemphasis_lane0_99=0x35503 +serdes_preemphasis_lane1_99=0x35503 +serdes_preemphasis_lane2_99=0x35503 +serdes_preemphasis_lane3_99=0x55905 +serdes_preemphasis_lane0_107=0x25905 +serdes_preemphasis_lane1_107=0x25905 +serdes_preemphasis_lane2_107=0x25905 +serdes_preemphasis_lane3_107=0x25905 +serdes_preemphasis_lane0_115=0x25905 +serdes_preemphasis_lane1_115=0x25905 +serdes_preemphasis_lane2_115=0x25905 +serdes_preemphasis_lane3_115=0x25905 +serdes_preemphasis_lane0_123=0x25905 +serdes_preemphasis_lane1_123=0x25905 +serdes_preemphasis_lane2_123=0x25905 +serdes_preemphasis_lane3_123=0x25905 +serdes_preemphasis_lane0_127=0x25905 +serdes_preemphasis_lane1_127=0x25905 +serdes_preemphasis_lane2_127=0x25905 +serdes_preemphasis_lane3_127=0x25905 + diff --git a/device/quanta/x86_64-quanta_ix8c_bwde-r0/custom_led.bin b/device/quanta/x86_64-quanta_ix8c_bwde-r0/custom_led.bin new file mode 100644 index 0000000000..4b23c95ce9 Binary files /dev/null and b/device/quanta/x86_64-quanta_ix8c_bwde-r0/custom_led.bin differ diff --git a/device/quanta/x86_64-quanta_ix8c_bwde-r0/led_proc_init.soc b/device/quanta/x86_64-quanta_ix8c_bwde-r0/led_proc_init.soc index 0861486660..49f097daca 100644 --- a/device/quanta/x86_64-quanta_ix8c_bwde-r0/led_proc_init.soc +++ b/device/quanta/x86_64-quanta_ix8c_bwde-r0/led_proc_init.soc @@ -1,6 +1,4 @@ sleep 10 -led stop -sleep 3 +m0 Load 0 0x3800 /usr/share/sonic/platform/custom_led.bin +led auto on led start -sleep 3 -led auto on \ No newline at end of file diff --git a/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/eeprom.py b/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/eeprom.py index fa34110c04..3752a919cb 100644 --- a/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/eeprom.py +++ b/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/eeprom.py @@ -16,5 +16,5 @@ class board(eeprom_tlvinfo.TlvInfoDecoder): _TLV_INFO_MAX_LEN = 256 def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/sys/bus/i2c/devices/18-0054/eeprom" + self.eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/sfputil.py b/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/sfputil.py index 3067919795..aed53ca0c0 100644 --- a/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/sfputil.py +++ b/device/quanta/x86_64-quanta_ix8c_bwde-r0/plugins/sfputil.py @@ -23,62 +23,62 @@ class SfpUtil(SfpUtilBase): _port_to_eeprom_mapping = {} _port_to_i2c_mapping = { - 1: 32, - 2: 33, - 3: 34, - 4: 35, - 5: 36, - 6: 37, - 7: 38, - 8: 39, - 9: 40, - 10: 41, - 11: 42, - 12: 43, - 13: 44, - 14: 45, - 15: 46, - 16: 47, - 17: 48, - 18: 49, - 19: 50, - 20: 51, - 21: 52, - 22: 53, - 23: 54, - 24: 55, - 25: 56, - 26: 57, - 27: 58, - 28: 59, - 29: 60, - 30: 61, - 31: 62, - 32: 63, - 33: 64, - 34: 65, - 35: 66, - 36: 67, - 37: 68, - 38: 69, - 39: 70, - 40: 71, - 41: 72, - 42: 73, - 43: 74, - 44: 75, - 45: 76, - 46: 77, - 47: 78, - 48: 79, - 49: 80, # QSFP49 - 50: 81, # QSFP50 - 51: 82, # QSFP51 - 52: 83, # QSFP52 - 53: 84, # QSFP53 - 54: 85, # QSFP54 - 55: 86, # QSFP55 - 56: 87, # QSFP56 + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44, + 33 : 45, + 34 : 46, + 35 : 47, + 36 : 48, + 37 : 49, + 38 : 50, + 39 : 51, + 40 : 52, + 41 : 53, + 42 : 54, + 43 : 55, + 44 : 56, + 45 : 57, + 46 : 58, + 47 : 59, + 48 : 60, + 49 : 61,#QSFP49 + 50 : 62,#QSFP50 + 51 : 63,#QSFP51 + 52 : 64,#QSFP52 + 53 : 65,#QSFP53 + 54 : 66,#QSFP54 + 55 : 67,#QSFP55 + 56 : 68,#QSFP56 } @property diff --git a/device/quanta/x86_64-quanta_ix8c_bwde-r0/pmon_daemon_control.json b/device/quanta/x86_64-quanta_ix8c_bwde-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..44bad64942 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix8c_bwde-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true +} + diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers.json.j2 b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers.json.j2 new file mode 100644 index 0000000000..1083a6210f --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't0' %} +{%- include 'buffers_config.j2' %} diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers_defaults_t0.j2 b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..9a25d6fe9f --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers_defaults_t0.j2 @@ -0,0 +1,57 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "egress_lossy_pool": { + "size": "67108864", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "0", + "type": "egress", + "mode": "dynamic" + }, + "ingress_lossless_pool": { + "mode": "dynamic", + "size": "59001152", + "xoff": "7428992", + "type": "ingress" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"67108864" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + } + }, +{%- endmacro %} + + "BUFFER_PG": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }{% if not loop.last %},{% endif %} +{% endfor %} + }, + + "BUFFER_QUEUE": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }{% if not loop.last %},{% endif %} +{% endfor %} + } + diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers_defaults_t1.j2 b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..9a25d6fe9f --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/buffers_defaults_t1.j2 @@ -0,0 +1,57 @@ + +{%- set default_cable = '40m' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "egress_lossy_pool": { + "size": "67108864", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "0", + "type": "egress", + "mode": "dynamic" + }, + "ingress_lossless_pool": { + "mode": "dynamic", + "size": "59001152", + "xoff": "7428992", + "type": "ingress" + } + }, + "BUFFER_PROFILE": { + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "size":"0", + "static_th":"67108864" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"0", + "dynamic_th":"3" + } + }, +{%- endmacro %} + + "BUFFER_PG": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { + "profile" : "[BUFFER_PROFILE|ingress_lossy_profile]" + }{% if not loop.last %},{% endif %} +{% endfor %} + }, + + "BUFFER_QUEUE": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0-6": { + "profile" : "[BUFFER_PROFILE|egress_lossy_profile]" + }{% if not loop.last %},{% endif %} +{% endfor %} + } + diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/pg_profile_lookup.ini b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/pg_profile_lookup.ini new file mode 100644 index 0000000000..a5f3286bee --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/pg_profile_lookup.ini @@ -0,0 +1,23 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1270 0 190500 -2 2540 + 25000 5m 1270 0 190500 -2 2540 + 40000 5m 1270 0 190500 -2 2540 + 50000 5m 1270 0 190500 -2 2540 + 100000 5m 1270 0 190500 -2 2540 + 200000 5m 1270 0 190500 -2 2540 + 400000 5m 1270 0 190500 -2 2540 + 10000 40m 1270 0 190500 -2 2540 + 25000 40m 1270 0 190500 -2 2540 + 40000 40m 1270 0 190500 -2 2540 + 50000 40m 1270 0 190500 -2 2540 + 100000 40m 1270 0 190500 -2 2540 + 200000 40m 1270 0 190500 -2 2540 + 400000 40m 1270 0 190500 -2 2540 + 10000 300m 1270 0 190500 -2 2540 + 25000 300m 1270 0 190500 -2 2540 + 40000 300m 1270 0 190500 -2 2540 + 50000 300m 1270 0 190500 -2 2540 + 100000 300m 1270 0 190500 -2 2540 + 200000 300m 1270 0 190500 -2 2540 + 400000 300m 1270 0 190500 -2 2540 diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/platform-def.json b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/platform-def.json new file mode 100644 index 0000000000..4885a3e172 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/platform-def.json @@ -0,0 +1,43 @@ +{ + "fec-mode": { + "Ethernet0-255": { + "1": { + "10000": [ "none", "fc" ], + "25000": [ "none", "fc", "rs" ], + "50000": [ "none", "rs" ] + }, + "2": [ "none", "rs" ], + "4": { + "40000": [ "none", "fc" ], + "100000": [ "none", "rs" ], + "200000": [ "none", "rs" ] + }, + "8": [ "rs" ] + } + }, + "default-fec-mode": { + "Ethernet0-255": { + "1": { + "10000": "none", + "25000": "none", + "50000": "none" + }, + "2": { + "20000": "none", + "50000": "none", + "100000": "rs" + }, + "4": { + "40000": "none", + "100000": "none", + "200000": "none" + }, + "8": "rs" + } + }, + "native-port-supported-speeds": { + "Ethernet0-255": { + } + } +} + diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/port_config.ini b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/port_config.ini index 8f77032943..831083b3ac 100644 --- a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/port_config.ini +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/port_config.ini @@ -1,33 +1,33 @@ -# name lanes alias index -Ethernet0 33,34,35,36,37,38,39,40 fourhundredGigE1 0 -Ethernet4 25,26,27,28,29,30,31,32 fourhundredGigE2 1 -Ethernet8 49,50,51,52,53,54,55,56 fourhundredGigE3 2 -Ethernet12 57,58,59,60,61,62,63,64 fourhundredGigE4 3 -Ethernet16 65,66,67,68,69,70,71,72 fourhundredGigE5 4 -Ethernet20 73,74,75,76,77,78,79,80 fourhundredGigE6 5 -Ethernet24 81,82,83,84,85,86,87,88 fourhundredGigE7 6 -Ethernet28 89,90,91,92,93,94,95,96 fourhundredGigE8 7 -Ethernet32 17,18,19,20,21,22,23,24 fourhundredGigE9 8 -Ethernet36 97,98,99,100,101,102,103,104 fourhundredGigE10 9 -Ethernet40 9,10,11,12,13,14,15,16 fourhundredGigE11 10 -Ethernet44 41,42,43,44,45,46,47,48 fourhundredGigE12 11 -Ethernet48 113,114,115,116,117,118,119,120 fourhundredGigE13 12 -Ethernet52 105,106,107,108,109,110,111,112 fourhundredGigE14 13 -Ethernet56 121,122,123,124,125,126,127,128 fourhundredGigE15 14 -Ethernet60 1,2,3,4,5,6,7,8 fourhundredGigE16 15 -Ethernet64 137,138,139,140,141,142,143,144 fourhundredGigE17 16 -Ethernet68 129,130,131,132,133,134,135,136 fourhundredGigE18 17 -Ethernet72 241,242,243,244,245,246,247,248 fourhundredGigE19 18 -Ethernet76 249,250,251,252,253,254,255,256 fourhundredGigE20 19 -Ethernet80 225,226,227,228,229,230,231,232 fourhundredGigE21 20 -Ethernet84 145,146,147,148,149,150,151,152 fourhundredGigE22 21 -Ethernet88 153,154,155,156,157,158,159,160 fourhundredGigE23 22 -Ethernet92 233,234,235,236,237,238,239,240 fourhundredGigE24 23 -Ethernet96 161,162,163,164,165,166,167,168 fourhundredGigE25 24 -Ethernet100 169,170,171,172,173,174,175,176 fourhundredGigE26 25 -Ethernet104 177,178,179,180,181,182,183,184 fourhundredGigE27 26 -Ethernet108 185,186,187,188,189,190,191,192 fourhundredGigE28 27 -Ethernet112 193,194,195,196,197,198,199,200 fourhundredGigE29 28 -Ethernet116 201,202,203,204,205,206,207,208 fourhundredGigE30 29 -Ethernet120 209,210,211,212,213,214,215,216 fourhundredGigE31 30 -Ethernet124 217,218,219,220,221,222,223,224 fourhundredGigE32 31 +# name lanes alias index speed fec +Ethernet0 33,34,35,36,37,38,39,40 fourhundredGigE1 1 400000 rs +Ethernet8 25,26,27,28,29,30,31,32 fourhundredGigE2 2 400000 rs +Ethernet16 49,50,51,52,53,54,55,56 fourhundredGigE3 3 400000 rs +Ethernet24 57,58,59,60,61,62,63,64 fourhundredGigE4 4 400000 rs +Ethernet32 65,66,67,68,69,70,71,72 fourhundredGigE5 5 400000 rs +Ethernet40 73,74,75,76,77,78,79,80 fourhundredGigE6 6 400000 rs +Ethernet48 81,82,83,84,85,86,87,88 fourhundredGigE7 7 400000 rs +Ethernet56 89,90,91,92,93,94,95,96 fourhundredGigE8 8 400000 rs +Ethernet64 17,18,19,20,21,22,23,24 fourhundredGigE9 9 400000 rs +Ethernet72 97,98,99,100,101,102,103,104 fourhundredGigE10 10 400000 rs +Ethernet80 9,10,11,12,13,14,15,16 fourhundredGigE11 11 400000 rs +Ethernet88 41,42,43,44,45,46,47,48 fourhundredGigE12 12 400000 rs +Ethernet96 113,114,115,116,117,118,119,120 fourhundredGigE13 13 400000 rs +Ethernet104 105,106,107,108,109,110,111,112 fourhundredGigE14 14 400000 rs +Ethernet112 121,122,123,124,125,126,127,128 fourhundredGigE15 15 400000 rs +Ethernet120 1,2,3,4,5,6,7,8 fourhundredGigE16 16 400000 rs +Ethernet128 137,138,139,140,141,142,143,144 fourhundredGigE17 17 400000 rs +Ethernet136 129,130,131,132,133,134,135,136 fourhundredGigE18 18 400000 rs +Ethernet144 241,242,243,244,245,246,247,248 fourhundredGigE19 19 400000 rs +Ethernet152 249,250,251,252,253,254,255,256 fourhundredGigE20 20 400000 rs +Ethernet160 225,226,227,228,229,230,231,232 fourhundredGigE21 21 400000 rs +Ethernet168 145,146,147,148,149,150,151,152 fourhundredGigE22 22 400000 rs +Ethernet176 153,154,155,156,157,158,159,160 fourhundredGigE23 23 400000 rs +Ethernet184 233,234,235,236,237,238,239,240 fourhundredGigE24 24 400000 rs +Ethernet192 161,162,163,164,165,166,167,168 fourhundredGigE25 25 400000 rs +Ethernet200 169,170,171,172,173,174,175,176 fourhundredGigE26 26 400000 rs +Ethernet208 177,178,179,180,181,182,183,184 fourhundredGigE27 27 400000 rs +Ethernet216 185,186,187,188,189,190,191,192 fourhundredGigE28 28 400000 rs +Ethernet224 193,194,195,196,197,198,199,200 fourhundredGigE29 29 400000 rs +Ethernet232 201,202,203,204,205,206,207,208 fourhundredGigE30 30 400000 rs +Ethernet240 209,210,211,212,213,214,215,216 fourhundredGigE31 31 400000 rs +Ethernet248 217,218,219,220,221,222,223,224 fourhundredGigE32 32 400000 rs diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/qos.json.j2 b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/qos.json.j2 new file mode 100644 index 0000000000..5f957d5039 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/qos.json.j2 @@ -0,0 +1,230 @@ +{%- 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": { + "DEFAULT": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "7" + } + }, +{% endif %} + "MAP_PFC_PRIORITY_TO_QUEUE": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_QUEUE_MAP": { + "DEFAULT": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "DEFAULT": { + "0" : "0", + "1" : "0", + "2" : "0", + "3" : "0", + "4" : "0", + "5" : "0", + "6" : "0", + "7" : "0", + "8" : "0", + "9" : "0", + "10": "0", + "11": "0", + "12": "0", + "13": "0", + "14": "0", + "15": "0", + "16": "0", + "17": "0", + "18": "0", + "19": "0", + "20": "0", + "21": "0", + "22": "0", + "23": "0", + "24": "0", + "25": "0", + "26": "0", + "27": "0", + "28": "0", + "29": "0", + "30": "0", + "31": "0", + "32": "0", + "33": "0", + "34": "0", + "35": "0", + "36": "0", + "37": "0", + "38": "0", + "39": "0", + "40": "0", + "41": "0", + "42": "0", + "43": "0", + "44": "0", + "45": "0", + "46": "0", + "47": "0", + "48": "0", + "49": "0", + "50": "0", + "51": "0", + "52": "0", + "53": "0", + "54": "0", + "55": "0", + "56": "0", + "57": "0", + "58": "0", + "59": "0", + "60": "0", + "61": "0", + "62": "0", + "63": "0" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "2" + }, + "scheduler.2": { + "type" : "DWRR", + "weight": "3" + }, + "scheduler.3": { + "type" : "DWRR", + "weight": "4" + }, + "scheduler.4": { + "type" : "DWRR", + "weight": "5" + }, + "scheduler.5": { + "type" : "DWRR", + "weight": "10" + }, + "scheduler.6": { + "type" : "DWRR", + "weight": "25" + }, + "scheduler.7": { + "type" : "DWRR", + "weight": "50" + } + }, + "PORT_QOS_MAP": { +{% for port in PORT_ACTIVE %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|DEFAULT]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|DEFAULT]", + "pfc_enable" : "3,4", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|DEFAULT]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|DEFAULT]" + }{% if not loop.last %},{% endif %} +{% endfor %} + }, + "QUEUE": { +{% for port in PORT_ACTIVE %} + "{{ port }}|0": { + "scheduler" : "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|1": { + "scheduler" : "[SCHEDULER|scheduler.1]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|2": { + "scheduler": "[SCHEDULER|scheduler.2]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|3": { + "scheduler": "[SCHEDULER|scheduler.3]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|4": { + "scheduler": "[SCHEDULER|scheduler.4]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|5": { + "scheduler": "[SCHEDULER|scheduler.5]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|6": { + "scheduler": "[SCHEDULER|scheduler.6]" + }, +{% endfor %} +{% for port in PORT_ACTIVE %} + "{{ port }}|7": { + "scheduler": "[SCHEDULER|scheduler.7]" + }{% if not loop.last %},{% endif %} +{% endfor %} + } +} diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/th3-ix9-32x400G.config.bcm b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/th3-ix9-32x400G.config.bcm index 704183e109..93937398e8 100644 --- a/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/th3-ix9-32x400G.config.bcm +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/Quanta-IX9-32X/th3-ix9-32x400G.config.bcm @@ -1,23 +1,27 @@ -ccm_dma_enable=0 -ccmdma_intr_enable=0 -ctr_evict_enable=0 -mem_cache_enable=0 -parity_correction=0 -parity_enable=0 -phy_enable=0 phy_null=1 pll_bypass=1 -init_all_modules=0 core_clock_frequency=1325 dpr_clock_frequency=1000 device_clock_frequency=1325 - -load_firmware=0x2 port_flex_enable=1 +l2xmsg_mode.0=1 +l2_mem_entries.0=8192 +l3_alpm_enable.0=2 +l3_mem_entries.0=16384 +ipv6_lpm_128b_enable=1 +lpm_ipv6_128b_reserved=0 +l3_alpm_ipv6_128b_bkt_rsvd=0 +num_ipv6_lpm_128b_entries=768 +mmu_port_num_mc_queue.0=1 +module_64ports.0=1 +multicast_l2_range.0=511 +oversubscribe_mode=1 +led_fw_path="/usr/share/sonic/platform/" + # portmap settings -pbmp_xport_xe=0x111101111411110111101111011114111102222 +pbmp_xport_xe.0=0x3ffffffffffffffffffffffffffffffffffffffe portmap_1=1:400 portmap_5=9:400 @@ -47,17 +51,18 @@ portmap_108=177:400 portmap_112=185:400 portmap_120=193:400 -portmap_124=201:400 -portmap_128=209:400 -portmap_132=217:400 +portmap_121=201:400 +portmap_122=209:400 +portmap_130=217:400 + portmap_140=225:400 portmap_144=233:400 portmap_148=241:400 portmap_152=249:400 # datapath port -portmap_38=257:10 -portmap_118=258:10 +#portmap_38=257:10 +#portmap_118=258:10 # loopback port portmap_19=260:10 @@ -71,41 +76,165 @@ portmap_159=266:10 # port order remap dport_map_port_20=1 -dport_map_port_13=2 -dport_map_port_28=3 -dport_map_port_32=4 -dport_map_port_40=5 -dport_map_port_44=6 -dport_map_port_48=7 -dport_map_port_52=8 -dport_map_port_9=9 -dport_map_port_60=10 -dport_map_port_5=11 -dport_map_port_24=12 -dport_map_port_68=13 -dport_map_port_64=14 -dport_map_port_72=15 -dport_map_port_1=16 +dport_map_port_21=2 +dport_map_port_22=3 +dport_map_port_23=4 -dport_map_port_84=17 -dport_map_port_80=18 -dport_map_port_148=19 -dport_map_port_152=20 -dport_map_port_140=21 -dport_map_port_88=22 -dport_map_port_92=23 -dport_map_port_144=24 -dport_map_port_100=25 -dport_map_port_104=26 -dport_map_port_108=27 -dport_map_port_112=28 -dport_map_port_120=29 -dport_map_port_124=30 -dport_map_port_128=31 -dport_map_port_132=32 +dport_map_port_13=5 +dport_map_port_14=6 +dport_map_port_15=7 +dport_map_port_16=8 -dport_map_port_38=33 -dport_map_port_118=34 +dport_map_port_28=9 +dport_map_port_29=10 +dport_map_port_30=11 +dport_map_port_31=12 + +dport_map_port_32=13 +dport_map_port_33=14 +dport_map_port_34=15 +dport_map_port_35=16 + +dport_map_port_40=17 +dport_map_port_41=18 +dport_map_port_42=19 +dport_map_port_43=20 + +dport_map_port_44=21 +dport_map_port_45=22 +dport_map_port_46=23 +dport_map_port_47=24 + +dport_map_port_48=25 +dport_map_port_49=26 +dport_map_port_50=27 +dport_map_port_51=28 + +dport_map_port_52=29 +dport_map_port_53=30 +dport_map_port_54=31 +dport_map_port_55=32 + +dport_map_port_9=33 +dport_map_port_10=34 +dport_map_port_11=35 +dport_map_port_12=36 + +dport_map_port_60=37 +dport_map_port_61=38 +dport_map_port_62=39 +dport_map_port_63=40 + +dport_map_port_5=41 +dport_map_port_6=42 +dport_map_port_7=43 +dport_map_port_8=44 + +dport_map_port_24=45 +dport_map_port_25=46 +dport_map_port_26=47 +dport_map_port_27=48 + +dport_map_port_68=49 +dport_map_port_69=50 +dport_map_port_70=51 +dport_map_port_71=52 + +dport_map_port_64=53 +dport_map_port_65=54 +dport_map_port_66=55 +dport_map_port_67=56 + +dport_map_port_72=57 +dport_map_port_73=58 +dport_map_port_74=59 +dport_map_port_75=60 + +dport_map_port_1=61 +dport_map_port_2=62 +dport_map_port_3=63 +dport_map_port_4=64 + +dport_map_port_84=65 +dport_map_port_85=66 +dport_map_port_86=67 +dport_map_port_87=68 + +dport_map_port_80=69 +dport_map_port_81=70 +dport_map_port_82=71 +dport_map_port_83=72 + +dport_map_port_148=73 +dport_map_port_149=74 +dport_map_port_150=75 +dport_map_port_151=76 + +dport_map_port_152=77 +dport_map_port_153=78 +dport_map_port_154=79 +dport_map_port_155=80 + +dport_map_port_140=81 +dport_map_port_141=82 +dport_map_port_142=83 +dport_map_port_143=84 + + +dport_map_port_88=85 +dport_map_port_89=86 +dport_map_port_90=87 +dport_map_port_91=88 + +dport_map_port_92=89 +dport_map_port_93=90 +dport_map_port_94=91 +dport_map_port_95=92 + +dport_map_port_144=93 +dport_map_port_145=94 +dport_map_port_146=95 +dport_map_port_147=96 + +dport_map_port_100=97 +dport_map_port_101=98 +dport_map_port_102=99 +dport_map_port_103=100 + +dport_map_port_104=101 +dport_map_port_105=102 +dport_map_port_106=103 +dport_map_port_107=104 + +dport_map_port_108=105 +dport_map_port_109=106 +dport_map_port_110=107 +dport_map_port_111=108 + +dport_map_port_112=109 +dport_map_port_113=110 +dport_map_port_114=111 +dport_map_port_115=112 + +dport_map_port_120=113 +dport_map_port_121=114 +dport_map_port_122=115 +dport_map_port_123=116 + +dport_map_port_124=117 +dport_map_port_125=118 +dport_map_port_126=119 +dport_map_port_127=120 + +dport_map_port_128=121 +dport_map_port_129=122 +dport_map_port_130=123 +dport_map_port_131=124 + +dport_map_port_132=125 +dport_map_port_133=126 +dport_map_port_134=127 +dport_map_port_135=128 ### lane swap and polarity follow front port order ### phy_chain_tx_lane_map_physical{33.0}=0x75206431 @@ -269,73 +398,3 @@ phy_chain_rx_lane_map_physical{217.0}=0x67541203 serdes_core_rx_polarity_flip_physical{217}=0x33 -port_fec_20=9 -port_fec_13=9 -port_fec_28=9 -port_fec_32=9 -port_fec_40=9 -port_fec_44=9 -port_fec_48=9 -port_fec_52=9 -port_fec_9=9 -port_fec_60=9 -port_fec_5=9 -port_fec_24=9 -port_fec_68=9 -port_fec_64=9 -port_fec_72=9 -port_fec_1=9 - -port_fec_84=9 -port_fec_80=9 -port_fec_148=9 -port_fec_152=9 -port_fec_140=9 -port_fec_88=9 -port_fec_92=9 -port_fec_144=9 -port_fec_100=9 -port_fec_104=9 -port_fec_108=9 -port_fec_112=9 -port_fec_120=9 -port_fec_124=9 -port_fec_128=9 -port_fec_132=9 - - -port_init_cl72_20=1 -port_init_cl72_13=1 -port_init_cl72_28=1 -port_init_cl72_32=1 -port_init_cl72_40=1 -port_init_cl72_44=1 -port_init_cl72_48=1 -port_init_cl72_52=1 -port_init_cl72_9=1 -port_init_cl72_60=1 -port_init_cl72_5=1 -port_init_cl72_24=1 -port_init_cl72_68=1 -port_init_cl72_64=1 -port_init_cl72_72=1 -port_init_cl72_1=1 - -port_init_cl72_84=1 -port_init_cl72_80=1 -port_init_cl72_148=1 -port_init_cl72_152=1 -port_init_cl72_140=1 -port_init_cl72_88=1 -port_init_cl72_92=1 -port_init_cl72_144=1 -port_init_cl72_100=1 -port_init_cl72_104=1 -port_init_cl72_108=1 -port_init_cl72_112=1 -port_init_cl72_120=1 -port_init_cl72_124=1 -port_init_cl72_128=1 -port_init_cl72_132=1 - - diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/custom_led.bin b/device/quanta/x86_64-quanta_ix9_bwde-r0/custom_led.bin new file mode 100644 index 0000000000..1f12caa4fa Binary files /dev/null and b/device/quanta/x86_64-quanta_ix9_bwde-r0/custom_led.bin differ diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/led_proc_init.soc b/device/quanta/x86_64-quanta_ix9_bwde-r0/led_proc_init.soc index adff95218e..b6c5d50739 100644 --- a/device/quanta/x86_64-quanta_ix9_bwde-r0/led_proc_init.soc +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/led_proc_init.soc @@ -1,2 +1,6 @@ sleep 10 +m0 Load 0 0x3800 /usr/share/sonic/platform/custom_led.bin led auto on +led start + +rcload /usr/share/sonic/platform/preemphasis-32x400G.soc diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/eeprom.py b/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/eeprom.py index fa34110c04..3752a919cb 100644 --- a/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/eeprom.py +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/eeprom.py @@ -16,5 +16,5 @@ class board(eeprom_tlvinfo.TlvInfoDecoder): _TLV_INFO_MAX_LEN = 256 def __init__(self, name, path, cpld_root, ro): - self.eeprom_path = "/sys/bus/i2c/devices/18-0054/eeprom" + self.eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/sfputil.py b/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/sfputil.py index 832dac4e05..6735a7579a 100644 --- a/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/sfputil.py +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/plugins/sfputil.py @@ -8,52 +8,52 @@ except ImportError as e: class SfpUtil(SfpUtilBase): """Platform specific SfpUtill class""" - _port_start = 0 - _port_end = 31 + _port_start = 1 + _port_end = 32 ports_in_block = 32 _port_to_eeprom_mapping = {} port_to_i2c_mapping = { - 1: 32, - 2: 33, - 3: 34, - 4: 35, - 5: 36, - 6: 37, - 7: 38, - 8: 39, - 9: 40, - 10: 41, - 11: 42, - 12: 43, - 13: 44, - 14: 45, - 15: 46, - 16: 47, - 17: 48, - 18: 49, - 19: 50, - 20: 51, - 21: 52, - 22: 53, - 23: 54, - 24: 55, - 25: 56, - 26: 57, - 27: 58, - 28: 59, - 29: 60, - 30: 61, - 31: 62, - 32: 63, + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44, } - _qsfp_ports = list(range(0, ports_in_block + 1)) + _qsfp_ports = range(1, ports_in_block + 1) def __init__(self): eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' - for x in range(0, self._port_end + 1): - port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x+1]) + for x in range(self.port_start, self.port_end + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) self._port_to_eeprom_mapping[x] = port_eeprom_path SfpUtilBase.__init__(self) @@ -63,7 +63,7 @@ class SfpUtil(SfpUtilBase): return False try: - reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num+1)+"/reset", "r+") + reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num)+"/reset", "r+") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -77,7 +77,7 @@ class SfpUtil(SfpUtilBase): # Flip the value back write back to the register to take port out of reset try: - reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num+1)+"/reset", "r+") + reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num)+"/reset", "r+") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -94,7 +94,7 @@ class SfpUtil(SfpUtilBase): return False try: - reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num+1)+"/lpmode", "r+") + reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num)+"/lpmode", "r+") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -118,7 +118,7 @@ class SfpUtil(SfpUtilBase): return False try: - reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num+1)+"/lpmode") + reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num)+"/lpmode") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -136,7 +136,7 @@ class SfpUtil(SfpUtilBase): return False try: - reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num+1)+"/module_present") + reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(port_num)+"/module_present") except IOError as e: print("Error: unable to open file: %s" % str(e)) return False @@ -155,9 +155,13 @@ class SfpUtil(SfpUtilBase): def port_end(self): return self._port_end + @property + def osfp_ports(self): + return range(self.port_start, self.ports_in_block + 1) + @property def qsfp_ports(self): - return list(range(0, self.ports_in_block + 1)) + return {} @property def port_to_eeprom_mapping(self): diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/pmon_daemon_control.json b/device/quanta/x86_64-quanta_ix9_bwde-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..44bad64942 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + "skip_ledd": true +} + diff --git a/device/quanta/x86_64-quanta_ix9_bwde-r0/preemphasis-32x400G.soc b/device/quanta/x86_64-quanta_ix9_bwde-r0/preemphasis-32x400G.soc new file mode 100644 index 0000000000..f324ad9670 --- /dev/null +++ b/device/quanta/x86_64-quanta_ix9_bwde-r0/preemphasis-32x400G.soc @@ -0,0 +1,1057 @@ +# Pre-emphasis + +phy raw c45 0xa9 0x1 0xffde 0 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 1 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 2 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 3 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 4 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 5 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 6 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 +phy raw c45 0xa9 0x1 0xffde 7 +phy raw c45 0xa9 0x1 0xd134 0x1f0 +phy raw c45 0xa9 0x1 0xd135 0x98 +phy raw c45 0xa9 0x1 0xd136 0x0 + +phy raw c45 0xa1 0x1 0xffde 0 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 1 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 2 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 3 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 4 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 5 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 6 +phy raw c45 0xa1 0x1 0xd134 0x1f0 +phy raw c45 0xa1 0x1 0xd135 0x98 +phy raw c45 0xa1 0x1 0xd136 0x0 +phy raw c45 0xa1 0x1 0xffde 7 +phy raw c45 0xa1 0x1 0xd134 0x1ee +phy raw c45 0xa1 0x1 0xd135 0x90 +phy raw c45 0xa1 0x1 0xd136 0x1fc + +phy raw c45 0xc1 0x1 0xffde 0 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 1 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 2 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 3 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 4 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 5 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 6 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 +phy raw c45 0xc1 0x1 0xffde 7 +phy raw c45 0xc1 0x1 0xd134 0x1f0 +phy raw c45 0xc1 0x1 0xd135 0x98 +phy raw c45 0xc1 0x1 0xd136 0x0 + +phy raw c45 0xc9 0x1 0xffde 0 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 1 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 2 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 3 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 4 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 5 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 6 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 +phy raw c45 0xc9 0x1 0xffde 7 +phy raw c45 0xc9 0x1 0xd134 0x1f0 +phy raw c45 0xc9 0x1 0xd135 0x98 +phy raw c45 0xc9 0x1 0xd136 0x0 + +phy raw c45 0xd1 0x1 0xffde 0 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 1 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 2 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 3 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 4 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 5 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 6 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 +phy raw c45 0xd1 0x1 0xffde 7 +phy raw c45 0xd1 0x1 0xd134 0x1f0 +phy raw c45 0xd1 0x1 0xd135 0x98 +phy raw c45 0xd1 0x1 0xd136 0x0 + +phy raw c45 0xe1 0x1 0xffde 0 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 1 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 2 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 3 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 4 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 5 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 6 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 +phy raw c45 0xe1 0x1 0xffde 7 +phy raw c45 0xe1 0x1 0xd134 0x1f0 +phy raw c45 0xe1 0x1 0xd135 0x98 +phy raw c45 0xe1 0x1 0xd136 0x0 + +phy raw c45 0xe9 0x1 0xffde 0 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 1 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 2 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 3 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 4 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 5 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 6 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 +phy raw c45 0xe9 0x1 0xffde 7 +phy raw c45 0xe9 0x1 0xd134 0x1f0 +phy raw c45 0xe9 0x1 0xd135 0x98 +phy raw c45 0xe9 0x1 0xd136 0x0 + +phy raw c45 0xf1 0x1 0xffde 0 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 1 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 2 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 3 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 4 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 5 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 6 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 +phy raw c45 0xf1 0x1 0xffde 7 +phy raw c45 0xf1 0x1 0xd134 0x1f0 +phy raw c45 0xf1 0x1 0xd135 0x98 +phy raw c45 0xf1 0x1 0xd136 0x0 + +phy raw c45 0x91 0x1 0xffde 0 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 1 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 2 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 3 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 4 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 5 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 6 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 +phy raw c45 0x91 0x1 0xffde 7 +phy raw c45 0x91 0x1 0xd134 0x1f0 +phy raw c45 0x91 0x1 0xd135 0x98 +phy raw c45 0x91 0x1 0xd136 0x0 + +phy raw c45 0x181 0x1 0xffde 0 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 1 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 2 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 3 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 4 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 5 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 6 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 +phy raw c45 0x181 0x1 0xffde 7 +phy raw c45 0x181 0x1 0xd134 0x1f0 +phy raw c45 0x181 0x1 0xd135 0x98 +phy raw c45 0x181 0x1 0xd136 0x0 + +phy raw c45 0x89 0x1 0xffde 0 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 1 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 2 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 3 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 4 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 5 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 6 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 +phy raw c45 0x89 0x1 0xffde 7 +phy raw c45 0x89 0x1 0xd134 0x1f0 +phy raw c45 0x89 0x1 0xd135 0x98 +phy raw c45 0x89 0x1 0xd136 0x0 + +phy raw c45 0xb1 0x1 0xffde 0 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 1 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 2 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 3 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 4 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 5 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 6 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 +phy raw c45 0xb1 0x1 0xffde 7 +phy raw c45 0xb1 0x1 0xd134 0x1f0 +phy raw c45 0xb1 0x1 0xd135 0x98 +phy raw c45 0xb1 0x1 0xd136 0x0 + +phy raw c45 0x191 0x1 0xffde 0 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 1 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 2 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 3 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 4 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 5 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 6 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 +phy raw c45 0x191 0x1 0xffde 7 +phy raw c45 0x191 0x1 0xd134 0x1f0 +phy raw c45 0x191 0x1 0xd135 0x98 +phy raw c45 0x191 0x1 0xd136 0x0 + +phy raw c45 0x189 0x1 0xffde 0 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 1 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 2 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 3 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 4 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 5 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 6 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 +phy raw c45 0x189 0x1 0xffde 7 +phy raw c45 0x189 0x1 0xd134 0x1f0 +phy raw c45 0x189 0x1 0xd135 0x98 +phy raw c45 0x189 0x1 0xd136 0x0 + +phy raw c45 0x1a1 0x1 0xffde 0 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 1 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 2 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 3 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 4 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 5 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 6 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 +phy raw c45 0x1a1 0x1 0xffde 7 +phy raw c45 0x1a1 0x1 0xd134 0x1f0 +phy raw c45 0x1a1 0x1 0xd135 0x98 +phy raw c45 0x1a1 0x1 0xd136 0x0 + +phy raw c45 0x81 0x1 0xffde 0 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 1 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 2 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 3 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 4 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 5 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 6 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 +phy raw c45 0x81 0x1 0xffde 7 +phy raw c45 0x81 0x1 0xd134 0x1f0 +phy raw c45 0x81 0x1 0xd135 0x98 +phy raw c45 0x81 0x1 0xd136 0x0 + +phy raw c45 0x1b1 0x1 0xffde 0 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 1 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 2 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 3 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 4 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 5 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 6 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 +phy raw c45 0x1b1 0x1 0xffde 7 +phy raw c45 0x1b1 0x1 0xd134 0x1f0 +phy raw c45 0x1b1 0x1 0xd135 0x98 +phy raw c45 0x1b1 0x1 0xd136 0x0 + +phy raw c45 0x1a9 0x1 0xffde 0 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 1 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 2 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 3 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 4 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 5 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 6 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 +phy raw c45 0x1a9 0x1 0xffde 7 +phy raw c45 0x1a9 0x1 0xd134 0x1f0 +phy raw c45 0x1a9 0x1 0xd135 0x98 +phy raw c45 0x1a9 0x1 0xd136 0x0 + +phy raw c45 0x2c1 0x1 0xffde 0 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 1 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 2 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 3 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 4 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 5 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 6 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 +phy raw c45 0x2c1 0x1 0xffde 7 +phy raw c45 0x2c1 0x1 0xd134 0x1f0 +phy raw c45 0x2c1 0x1 0xd135 0x98 +phy raw c45 0x2c1 0x1 0xd136 0x0 + +phy raw c45 0x2c9 0x1 0xffde 0 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 1 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 2 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 3 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 4 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 5 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 6 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 +phy raw c45 0x2c9 0x1 0xffde 7 +phy raw c45 0x2c9 0x1 0xd134 0x1f0 +phy raw c45 0x2c9 0x1 0xd135 0x98 +phy raw c45 0x2c9 0x1 0xd136 0x0 + +phy raw c45 0x2a9 0x1 0xffde 0 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 1 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 2 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 3 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 4 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 5 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 6 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 +phy raw c45 0x2a9 0x1 0xffde 7 +phy raw c45 0x2a9 0x1 0xd134 0x1f0 +phy raw c45 0x2a9 0x1 0xd135 0x98 +phy raw c45 0x2a9 0x1 0xd136 0x0 + +phy raw c45 0x1c1 0x1 0xffde 0 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 1 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 2 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 3 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 4 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 5 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 6 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 +phy raw c45 0x1c1 0x1 0xffde 7 +phy raw c45 0x1c1 0x1 0xd134 0x1f0 +phy raw c45 0x1c1 0x1 0xd135 0x98 +phy raw c45 0x1c1 0x1 0xd136 0x0 + +phy raw c45 0x1c9 0x1 0xffde 0 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 1 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 2 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 3 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 4 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 5 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 6 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 +phy raw c45 0x1c9 0x1 0xffde 7 +phy raw c45 0x1c9 0x1 0xd134 0x1f0 +phy raw c45 0x1c9 0x1 0xd135 0x98 +phy raw c45 0x1c9 0x1 0xd136 0x0 + +phy raw c45 0x2b1 0x1 0xffde 0 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 1 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 2 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 3 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 4 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 5 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 6 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 +phy raw c45 0x2b1 0x1 0xffde 7 +phy raw c45 0x2b1 0x1 0xd134 0x1f0 +phy raw c45 0x2b1 0x1 0xd135 0x98 +phy raw c45 0x2b1 0x1 0xd136 0x0 + +phy raw c45 0x1d1 0x1 0xffde 0 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 1 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 2 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 3 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 4 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 5 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 6 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 +phy raw c45 0x1d1 0x1 0xffde 7 +phy raw c45 0x1d1 0x1 0xd134 0x1f0 +phy raw c45 0x1d1 0x1 0xd135 0x98 +phy raw c45 0x1d1 0x1 0xd136 0x0 + +phy raw c45 0x1e1 0x1 0xffde 0 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 1 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 2 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 3 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 4 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 5 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 6 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 +phy raw c45 0x1e1 0x1 0xffde 7 +phy raw c45 0x1e1 0x1 0xd134 0x1f0 +phy raw c45 0x1e1 0x1 0xd135 0x98 +phy raw c45 0x1e1 0x1 0xd136 0x0 + +phy raw c45 0x1e9 0x1 0xffde 0 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 1 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 2 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 3 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 4 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 5 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 6 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 +phy raw c45 0x1e9 0x1 0xffde 7 +phy raw c45 0x1e9 0x1 0xd134 0x1f0 +phy raw c45 0x1e9 0x1 0xd135 0x98 +phy raw c45 0x1e9 0x1 0xd136 0x0 + +phy raw c45 0x1f1 0x1 0xffde 0 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 1 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 2 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 3 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 4 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 5 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 6 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 +phy raw c45 0x1f1 0x1 0xffde 7 +phy raw c45 0x1f1 0x1 0xd134 0x1f0 +phy raw c45 0x1f1 0x1 0xd135 0x98 +phy raw c45 0x1f1 0x1 0xd136 0x0 + +phy raw c45 0x281 0x1 0xffde 0 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 1 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 2 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 3 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 4 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 5 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 6 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 +phy raw c45 0x281 0x1 0xffde 7 +phy raw c45 0x281 0x1 0xd134 0x1f0 +phy raw c45 0x281 0x1 0xd135 0x98 +phy raw c45 0x281 0x1 0xd136 0x0 + +phy raw c45 0x289 0x1 0xffde 0 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 1 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 2 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 3 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 4 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 5 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 6 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 +phy raw c45 0x289 0x1 0xffde 7 +phy raw c45 0x289 0x1 0xd134 0x1f0 +phy raw c45 0x289 0x1 0xd135 0x98 +phy raw c45 0x289 0x1 0xd136 0x0 + +phy raw c45 0x291 0x1 0xffde 0 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 1 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 2 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 3 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 4 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 5 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 6 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 +phy raw c45 0x291 0x1 0xffde 7 +phy raw c45 0x291 0x1 0xd134 0x1f0 +phy raw c45 0x291 0x1 0xd135 0x98 +phy raw c45 0x291 0x1 0xd136 0x0 + +phy raw c45 0x2a1 0x1 0xffde 0 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 1 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 2 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 3 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 4 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 5 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 6 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 +phy raw c45 0x2a1 0x1 0xffde 7 +phy raw c45 0x2a1 0x1 0xd134 0x1f0 +phy raw c45 0x2a1 0x1 0xd135 0x98 +phy raw c45 0x2a1 0x1 0xd136 0x0 diff --git a/platform/broadcom/one-image.mk b/platform/broadcom/one-image.mk index d0e34b5d11..7b3df0dd73 100644 --- a/platform/broadcom/one-image.mk +++ b/platform/broadcom/one-image.mk @@ -53,7 +53,9 @@ $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(DELL_S6000_PLATFORM_MODULE) \ $(DELTA_ET6248BRB_PLATFORM_MODULE) \ $(QUANTA_IX1B_32X_PLATFORM_MODULE) \ $(QUANTA_IX7_32X_PLATFORM_MODULE) \ + $(QUANTA_IX7_BWDE_32X_PLATFORM_MODULE) \ $(QUANTA_IX8_56X_PLATFORM_MODULE) \ + $(QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE) \ $(QUANTA_IX8C_56X_PLATFORM_MODULE) \ $(QUANTA_IX9_32X_PLATFORM_MODULE) \ $(MITAC_LY1200_32X_PLATFORM_MODULE) \ diff --git a/platform/broadcom/platform-modules-quanta.mk b/platform/broadcom/platform-modules-quanta.mk index 267d3d9e73..4847af2983 100644 --- a/platform/broadcom/platform-modules-quanta.mk +++ b/platform/broadcom/platform-modules-quanta.mk @@ -2,13 +2,17 @@ QUANTA_IX1B_32X_PLATFORM_MODULE_VERSION = 1.0 QUANTA_IX7_32X_PLATFORM_MODULE_VERSION = 1.0 +QUANTA_IX7_BWDE_32X_PLATFORM_MODULE_VERSION = 1.0 QUANTA_IX8_56X_PLATFORM_MODULE_VERSION = 1.0 +QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE_VERSION = 1.0 QUANTA_IX8C_56X_PLATFORM_MODULE_VERSION = 1.0 QUANTA_IX9_32X_PLATFORM_MODULE_VERSION = 1.0 export QUANTA_IX1B_32X_PLATFORM_MODULE_VERSION export QUANTA_IX7_32X_PLATFORM_MODULE_VERSION +export QUANTA_IX7_BWDE_32X_PLATFORM_MODULE_VERSION export QUANTA_IX8_56X_PLATFORM_MODULE_VERSION +export QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE_VERSION export QUANTA_IX8C_56X_PLATFORM_MODULE_VERSION export QUANTA_IX9_32X_PLATFORM_MODULE_VERSION @@ -22,10 +26,18 @@ QUANTA_IX7_32X_PLATFORM_MODULE = sonic-platform-quanta-ix7-32x_$(QUANTA_IX7_32X_ $(QUANTA_IX7_32X_PLATFORM_MODULE)_PLATFORM = x86_64-quanta_ix7_rglbmc-r0 $(eval $(call add_extra_package,$(QUANTA_IX1B_32X_PLATFORM_MODULE),$(QUANTA_IX7_32X_PLATFORM_MODULE))) +QUANTA_IX7_BWDE_32X_PLATFORM_MODULE = sonic-platform-quanta-ix7-bwde-32x_$(QUANTA_IX7_BWDE_32X_PLATFORM_MODULE_VERSION)_amd64.deb +$(QUANTA_IX7_BWDE_32X_PLATFORM_MODULE)_PLATFORM = x86_64-quanta_ix7_bwde-r0 +$(eval $(call add_extra_package,$(QUANTA_IX1B_32X_PLATFORM_MODULE),$(QUANTA_IX7_BWDE_32X_PLATFORM_MODULE))) + QUANTA_IX8_56X_PLATFORM_MODULE = sonic-platform-quanta-ix8-56x_$(QUANTA_IX8_56X_PLATFORM_MODULE_VERSION)_amd64.deb $(QUANTA_IX8_56X_PLATFORM_MODULE)_PLATFORM = x86_64-quanta_ix8_rglbmc-r0 $(eval $(call add_extra_package,$(QUANTA_IX1B_32X_PLATFORM_MODULE),$(QUANTA_IX8_56X_PLATFORM_MODULE))) +QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE = sonic-platform-quanta-ix8a-bwde-56x_$(QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE_VERSION)_amd64.deb +$(QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE)_PLATFORM = x86_64-quanta_ix8a_bwde-r0 +$(eval $(call add_extra_package,$(QUANTA_IX1B_32X_PLATFORM_MODULE),$(QUANTA_IX8A_BWDE_56X_PLATFORM_MODULE))) + QUANTA_IX8C_56X_PLATFORM_MODULE = sonic-platform-quanta-ix8c-56x_$(QUANTA_IX8C_56X_PLATFORM_MODULE_VERSION)_amd64.deb $(QUANTA_IX8C_56X_PLATFORM_MODULE)_PLATFORM = x86_64-quanta_ix8c_bwde-r0 $(eval $(call add_extra_package,$(QUANTA_IX1B_32X_PLATFORM_MODULE),$(QUANTA_IX8C_56X_PLATFORM_MODULE))) diff --git a/platform/broadcom/sonic-platform-modules-quanta/LICENSE b/platform/broadcom/sonic-platform-modules-quanta/LICENSE old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-quanta/debian/changelog b/platform/broadcom/sonic-platform-modules-quanta/debian/changelog index fe1cfa4549..ff5d9587c4 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/debian/changelog +++ b/platform/broadcom/sonic-platform-modules-quanta/debian/changelog @@ -32,3 +32,17 @@ sonic-quanta-platform-modules (1.0) unstable; urgency=low * Initial release -- Jonathan Tsai Thu, 31 Jan 2019 13:09:01 +0800 + +sonic-quanta-platform-modules (1.0) unstable; urgency=low + + * Add support for Quanta IX7-BWDE-32X + * Initial release + + -- Robert Hong Tue, 2 Mar 2021 11:07:01 +0800 + +sonic-quanta-platform-modules (1.0) unstable; urgency=low + + * Add support for Quanta IX8A-BWDE-56X + * Initial release + + -- Robert Hong Tue, 2 Mar 2021 15:20:01 +0800 diff --git a/platform/broadcom/sonic-platform-modules-quanta/debian/compat b/platform/broadcom/sonic-platform-modules-quanta/debian/compat old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-quanta/debian/control b/platform/broadcom/sonic-platform-modules-quanta/debian/control index f25b0d8e3c..c42a033806 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/debian/control +++ b/platform/broadcom/sonic-platform-modules-quanta/debian/control @@ -13,10 +13,18 @@ Package: sonic-platform-quanta-ix7-32x Architecture: amd64 Description: kernel modules for platform devices such as psu, led, sfp +Package: sonic-platform-quanta-ix7-bwde-32x +Architecture: amd64 +Description: kernel modules for platform devices such as psu, led, sfp + Package: sonic-platform-quanta-ix8-56x Architecture: amd64 Description: kernel modules for platform devices such as psu, led, sfp +Package: sonic-platform-quanta-ix8a-bwde-56x +Architecture: amd64 +Description: kernel modules for platform devices such as psu, led, sfp + Package: sonic-platform-quanta-ix8c-56x Architecture: amd64 Description: kernel modules for platform devices such as psu, led, sfp diff --git a/platform/broadcom/sonic-platform-modules-quanta/debian/rules b/platform/broadcom/sonic-platform-modules-quanta/debian/rules index 46b9607135..9ddb763555 100755 --- a/platform/broadcom/sonic-platform-modules-quanta/debian/rules +++ b/platform/broadcom/sonic-platform-modules-quanta/debian/rules @@ -13,44 +13,54 @@ include /usr/share/dpkg/pkg-info.mk export INSTALL_MOD_DIR:=extra -PYTHON ?= python2 PACKAGE_PRE_NAME := sonic-platform-quanta KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS:= ix1b-32x ix7-32x ix8-56x ix8c-56x ix9-32x +MODULE_DIRS:= ix1b-32x ix7-32x ix7-bwde-32x ix8-56x ix8a-bwde-56x ix8c-56x ix9-32x MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service CLASSES_DIR := classes CONF_DIR := conf - +SYSTEMD_DIR := systemd %: - dh $@ --with systemd,python2,python3 --buildsystem=pybuild + dh $@ --with systemd,python3 --buildsystem=pybuild clean: dh_testdir dh_testroot dh_clean + (for mod in $(MODULE_DIRS); do \ + if [ -f $(MOD_SRC_DIR)/$${mod}/*.whl ]; then \ + rm -f $(MOD_SRC_DIR)/$${mod}/*.whl; \ + fi; \ + done) build: #make modules -C $(KERNEL_SRC)/build M=$(MODULE_SRC) (for mod in $(MODULE_DIRS); do \ make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ - $(PYTHON) $${mod}/setup.py build; \ + python3 $${mod}/setup.py build; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + if [ -f sonic_platform_setup.py ]; then \ + python3 sonic_platform_setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}; \ + echo "Finished makig whl package for $$mod"; \ + fi; \ + cd $(MOD_SRC_DIR); \ done) binary: binary-arch binary-indep # Nothing to do -binary-arch: +binary-arch: # Nothing to do #install: build #dh_testdir #dh_testroot - #dh_clean -k + #dh_clean -k #dh_installdirs binary-indep: @@ -62,10 +72,12 @@ binary-indep: dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} $(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} usr/local/bin; \ dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} lib/systemd/system; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} lib/systemd/system.conf.d/; \ cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ - $(PYTHON) $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SYSTEMD_DIR)/*.conf debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system.conf.d/; \ + python3 $${mod}/setup.py install --root=$(MOD_SRC_DIR)/debian/$(PACKAGE_PRE_NAME)-$${mod} --install-layout=deb; \ done) # Resuming debhelper scripts dh_testroot diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix1b-32x/modules/qci_cpld_qsfp28.c b/platform/broadcom/sonic-platform-modules-quanta/ix1b-32x/modules/qci_cpld_qsfp28.c index 15c5369fd2..92fa9a13c4 100755 --- a/platform/broadcom/sonic-platform-modules-quanta/ix1b-32x/modules/qci_cpld_qsfp28.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix1b-32x/modules/qci_cpld_qsfp28.c @@ -396,8 +396,11 @@ static int cpld_remove(struct i2c_client *client) kfree(data->port_data[i]); } - if (cpld_idr_is_empty(&cpld_ida.idr)) + if (ida_is_empty(&cpld_ida)) + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/Makefile b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/Makefile index 405c9153c0..c36586fa82 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/Makefile @@ -1,3 +1,3 @@ -obj-m:=qci_cpld.o qci_cpld_led.o quanta_platform_ix7.o +obj-m:=qci_cpld.o qci_cpld_led.o quanta_platform_ix7.o quanta_hwmon_ipmi.o diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld.c index e8556bc72d..1d2bf20233 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld.c @@ -172,11 +172,20 @@ static ssize_t get_module_present(struct device *dev, u8 group = (u8)(data->cpld_port / 4); u8 group_port = data->cpld_port % 4; s32 value; + int retry = 0; dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, data->cpld_port + 1, group + 1, group_port + 1); - value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + for (retry = 0; retry < 10; retry++) + { + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value >= 0) + break; + else + printk("%s: retry:%d\n", __FUNCTION__, retry); + msleep(1); + } if (value < 0) return -ENODEV; @@ -338,7 +347,7 @@ static int cpld_probe(struct i2c_client *client, if (!cpld_class) { - cpld_class = class_create(THIS_MODULE, name); + cpld_class = class_create(THIS_MODULE, "cpld-qsfp28"); if (IS_ERR(cpld_class)) { pr_err("couldn't create sysfs class\n"); return PTR_ERR(cpld_class); @@ -405,7 +414,7 @@ err_out: } /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ -#if 1 +#if 0 static int idr_has_entry(int id, void *p, void *data) { return 1; @@ -438,8 +447,11 @@ static int cpld_remove(struct i2c_client *client) kfree(data->port_data[i]); } - if (cpld_idr_is_empty(&cpld_ida.idr)) + if (ida_is_empty(&cpld_ida)) + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld_led.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld_led.c index 37fc2e0724..64841e8538 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld_led.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/qci_cpld_led.c @@ -241,6 +241,7 @@ err_out: return nr; } +#if 0 /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ static int idr_has_entry(int id, void *p, void *data) { @@ -251,6 +252,7 @@ static bool cpld_idr_is_empty(struct idr *idp) { return !idr_for_each(idp, idr_has_entry, NULL); } +#endif static int cpld_led_remove(struct i2c_client *client) { @@ -261,8 +263,11 @@ static int cpld_led_remove(struct i2c_client *client) ida_simple_remove(&cpld_led_ida, data->cpld_data->cpld_id); kfree(data->cpld_data); - if (cpld_idr_is_empty(&cpld_led_ida.idr)) + if (ida_is_empty(&cpld_led_ida)) + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_hwmon_ipmi.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_hwmon_ipmi.c new file mode 100644 index 0000000000..08d6a97d9a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_hwmon_ipmi.c @@ -0,0 +1,1908 @@ +/* +* +* A hwmon driver for the Quanta switch BMC hwmon +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define enable_debug_msg 0 +#define DEBUGUSE_SHIFT 0 + +#define DRVNAME "quanta_hwmon_ipmi" + +#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & (1<<((bits)-1))) | (val)) : (val)) +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) +#define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) +#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & 0xff000000) >> 24) | ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) +#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4), 4)) +#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) + +#define SENSOR_ATTR_MAX 19 +#define SENSOR_ATTR_NAME_LENGTH 20 + +#define SENSOR_GET_CAP_LABEL 0x001 +#define SENSOR_GET_CAP_ALARM 0x002 +#define SENSOR_GET_CAP_INPUT 0x004 + +#define SENSOR_GET_CAP_LNC 0x008 +#define SENSOR_GET_CAP_LCR 0x010 +#define SENSOR_GET_CAP_LNR 0x020 + +#define SENSOR_GET_CAP_UNC 0x040 +#define SENSOR_GET_CAP_UCR 0x080 +#define SENSOR_GET_CAP_UNR 0x100 + +#define SENSOR_GET_CAP_MODEL 0x200 +#define SENSOR_GET_CAP_SN 0x400 +#define SENSOR_GET_CAP_PWM 0x800 + +#define SENSOR_GET_CAP_CONMODE 0x1000 +#define SENSOR_GET_CAP_DIRECTION 0x2000 +#define SENSOR_GET_CAP_FAN_PRESENT 0x4000 +#define SENSOR_GET_CAP_PSU_PRESENT 0x8000 + +#define SENSOR_GET_CAP_MFRID 0x10000 +#define SENSOR_GET_CAP_VIN_TYPE 0x20000 +#define SENSOR_GET_CAP_POUT_MAX 0x40000 + +#define SDR_SENSOR_TYPE_TEMP 0x01 +#define SDR_SENSOR_TYPE_VOLT 0x02 +#define SDR_SENSOR_TYPE_CURR 0x03 +#define SDR_SENSOR_TYPE_FAN 0x04 +#define SDR_SENSOR_TYPE_PS 0x08 +#define SDR_SENSOR_TYPE_OTHER 0x0b + +#define BMC_GET_DEVICE_ID 0x01 + +#define IPMI_NETFN_SE 0x04 +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_STORAGE 0x0a +#define IPMI_NETFN_TSOL 0x30 + +#define GET_SDR_REPO_INFO 0x20 +#define GET_DEVICE_SDR 0x21 +#define GET_SDR_RESERVE_REPO 0x22 +#define GET_SDR 0x23 +#define GET_SENSOR_THRESHOLDS 0x27 +#define GET_SENSOR_EVENT_ENABLE 0x29 +#define GET_SENSOR_EVENT_STATUS 0x2b +#define GET_SENSOR_READING 0x2d +#define GET_PSU_READING 0x52 +#define GET_FAN_INFO 0xd6 +#define GET_FRU_INFO 0x11 + +#define IPM_DEV_DEVICE_ID_SDR_MASK (0x80) /* 1 = provides SDRs */ +#define IPMI_TIMEOUT (4 * HZ) +#define IPMI_MAX_WAIT_QUEUE 1 + +struct quanta_hwmon_ipmi_data +{ + struct platform_device *ipmi_platform_dev; + struct device *ipmi_hwmon_dev; + /*struct mutex ipmi_lock; */ + + int32_t total_sensor_id; + int32_t total_suport_sensor; + int32_t total_create_sysfs; +} *data; + +static struct mutex ipmi_lock; +static struct completion g_read_complete; + +static ipmi_user_t ipmi_mh_user = NULL; + +static int8_t g_fan_control_mode = 3; +static int32_t g_use_built_in = 0; +static int32_t ipmi_wait_queue = 0; + +struct ipmi_sensor_data +{ + uint8_t addr; + uint8_t sensor_type; + uint8_t sensor_idstring[SENSOR_ATTR_NAME_LENGTH]; + + uint32_t capability; + + struct header_info + { + uint8_t header_type; + uint8_t header_byte; + } headerinfo; + + struct record_info + { + uint8_t record_analog; + uint8_t record_linearization; + + int32_t record_m; + int32_t record_b; + int32_t record_k1; + int32_t record_k2; + } recordinfo; + + struct threshold_upper_info + { + uint8_t unr; + uint8_t ucr; + uint8_t unc; + } upperinfo; + + struct threshold_lower_info + { + uint8_t lnr; + uint8_t lcr; + uint8_t lnc; + } lowerinfo; + + struct attr_info + { + bool attr_exist; + char attr_name[SENSOR_ATTR_MAX][SENSOR_ATTR_NAME_LENGTH]; + char attr_type_str[SENSOR_ATTR_NAME_LENGTH]; + + struct attribute *attrs[SENSOR_ATTR_MAX + 1]; + struct attribute_group attr_group; + struct sensor_device_attribute sd_attrs[SENSOR_ATTR_MAX + 1]; + } attrinfo; + +} *g_sensor_data; + +struct ipmi_comm_data +{ + int32_t tx_id; + + int32_t rx_result; + int64_t rx_len; + void *rx_data; + struct completion *rx_read_complete; +}; + +struct ipmi_sdr_iterator +{ + uint16_t reservation; + int32_t total; + int32_t next; +}; + +struct ipm_devid_rsp +{ + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +} __attribute__((packed)); + +struct sdr_repo_info_rs +{ + uint8_t version; /* SDR version (51h) */ + uint16_t count; /* number of records */ + uint16_t free; /* free space in SDR */ + uint32_t add_stamp; /* last add timestamp */ + uint32_t erase_stamp; /* last del timestamp */ + uint8_t op_support; /* supported operations */ +} __attribute__((packed)); + +struct sdr_device_info_rs +{ + uint8_t count; /* number of records */ + uint8_t flags; /* flags */ + uint8_t popChangeInd[3]; /* free space in SDR */ +} __attribute__((packed)); + +struct sdr_get_rs +{ + uint16_t next; /* next record id */ + uint16_t id; /* record ID */ + uint8_t version; /* SDR version (51h) */ +#define SDR_RECORD_TYPE_FULL_SENSOR 0x01 +#define SDR_RECORD_TYPE_COMPACT_SENSOR 0x02 +#define SDR_RECORD_TYPE_EVENTONLY_SENSOR 0x03 +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC 0x09 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 +#define SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR 0x11 +#define SDR_RECORD_TYPE_MC_DEVICE_LOCATOR 0x12 +#define SDR_RECORD_TYPE_MC_CONFIRMATION 0x13 +#define SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO 0x14 +#define SDR_RECORD_TYPE_OEM 0xc0 + uint8_t type; /* record type */ + uint8_t length; /* remaining record bytes */ +} __attribute__((packed)); + +struct sdr_get_rq +{ + uint16_t reserve_id; /* reservation ID */ + uint16_t id; /* record ID */ + uint8_t offset; /* offset into SDR */ +#define GET_SDR_ENTIRE_RECORD 0xff + uint8_t length; /* length to read */ +} __attribute__((packed)); + +struct entity_id +{ + uint8_t id; /* physical entity id */ +#ifdef WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} __attribute__((packed)); + +struct sdr_record_mask +{ + union + { + struct + { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event mask */ + uint16_t read; /* discrete reading mask */ + } discrete; + struct + { +#ifdef WORDS_BIGENDIAN + uint16_t reserved : 1; + uint16_t status_lnr : 1; + uint16_t status_lcr : 1; + uint16_t status_lnc : 1; + uint16_t assert_unr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lnc_low : 1; +#else + uint16_t assert_lnc_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_unr_high : 1; + uint16_t status_lnc : 1; + uint16_t status_lcr : 1; + uint16_t status_lnr : 1; + uint16_t reserved : 1; +#endif +#ifdef WORDS_BIGENDIAN + uint16_t reserved_2 : 1; + uint16_t status_unr : 1; + uint16_t status_ucr : 1; + uint16_t status_unc : 1; + uint16_t deassert_unr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lnc_low : 1; +#else + uint16_t deassert_lnc_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_unr_high : 1; + uint16_t status_unc : 1; + uint16_t status_ucr : 1; + uint16_t status_unr : 1; + uint16_t reserved_2 : 1; +#endif + union + { + struct + { +#ifdef WORDS_BIGENDIAN /* settable threshold mask */ + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; + /* padding lower 8 bits */ + uint16_t readable : 8; +#else + uint16_t readable : 8; + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; +#endif + } set; + struct + { +#ifdef WORDS_BIGENDIAN /* readable threshold mask */ + /* padding upper 8 bits */ + uint16_t settable : 8; + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; +#else + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; + uint16_t settable : 8; +#endif + } read; + }; + } threshold; + } type; +} __attribute__((packed)); + +struct sdr_record_full_sensor +{ + struct + { + uint8_t owner_id; +#ifdef WORDS_BIGENDIAN + uint8_t channel : 4; /* channel number */ + uint8_t __reserved : 2; + uint8_t lun : 2; /* sensor owner lun */ +#else + uint8_t lun : 2; /* sensor owner lun */ + uint8_t __reserved : 2; + uint8_t channel : 4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } keys; + + struct entity_id entity; + + struct + { + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 1; + uint8_t scanning : 1; + uint8_t events : 1; + uint8_t thresholds : 1; + uint8_t hysteresis : 1; + uint8_t type : 1; + uint8_t event_gen : 1; + uint8_t sensor_scan : 1; +#else + uint8_t sensor_scan : 1; + uint8_t event_gen : 1; + uint8_t type : 1; + uint8_t hysteresis : 1; + uint8_t thresholds : 1; + uint8_t events : 1; + uint8_t scanning : 1; + uint8_t __reserved : 1; +#endif + } init; + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t ignore : 1; + uint8_t rearm : 1; + uint8_t hysteresis : 2; + uint8_t threshold : 2; + uint8_t event_msg : 2; +#else + uint8_t event_msg : 2; + uint8_t threshold : 2; + uint8_t hysteresis : 2; + uint8_t rearm : 1; + uint8_t ignore : 1; +#endif + } capabilities; + uint8_t type; + } sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t analog : 2; + uint8_t rate : 3; + uint8_t modifier : 2; + uint8_t pct : 1; +#else + uint8_t pct : 1; + uint8_t modifier : 2; + uint8_t rate : 3; + uint8_t analog : 2; +#endif + struct + { + uint8_t base; + uint8_t modifier; + } type; + } unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 5; + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t nominal_read : 1; /* nominal reading field specified */ +#else + uint8_t nominal_read : 1; /* nominal reading field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t __reserved : 5; +#endif + } analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct + { + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } upper; + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } lower; + struct + { + uint8_t positive; + uint8_t negative; + } hysteresis; + } threshold; + uint8_t __reserved[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} __attribute__((packed)); + +int32_t pow_convert(int32_t *a, int32_t b) +{ + /* function input parameter (a * 10 ^ b) */ + int32_t i = 0, r = 1, temp_b = 0; + + temp_b = (b > 0) ? b : -b; + + for (i = 0; i < temp_b; i++) + { + r = r * 10; + } + + if (b > 0) + { + *a = (*a) * r; + r = 1; + } + /* function return parameter calc_result = *a, decimal_point = r */ + return r; +} + +void simple_atoi(const char *buf, int8_t *output_val) +{ + while (*buf >= '0' && *buf <= '9') + { + *output_val = *output_val * 10 + *buf - '0'; + buf++; + } +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) +{ + int32_t rv = -IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + struct ipmi_comm_data *comm_data = msg->user_msg_data; + + ipmi_wait_queue--; + + if (msg->msg.data[0] != 0) + { + if ((msg->msg.data[0] != 0x83) && (msg->msg.netfn != 0x07) + && (msg->msg.cmd != 0x52)) + { + /*skip master r/w cmd return code */ + printk("ipmi: Error 0x%x on cmd 0x%x/0x%x\n", msg->msg.data[0], msg->msg.netfn, + msg->msg.cmd); + rv = msg->msg.data[0]; + goto get_BMC_response_fail; + } + } + + if (msg->msgid != comm_data->tx_id) + { + printk("ipmi: rx msgid %d mismatch tx msgid %d\n", (int32_t)msg->msgid, + comm_data->tx_id); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len <= 0) + { + printk("ipmi: Data len too low (%d)\n", msg->msg.data_len); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len > 1) + { + if (comm_data->rx_len) + { + comm_data->rx_len = msg->msg.data_len - 1; + memcpy(comm_data->rx_data, msg->msg.data + 1, comm_data->rx_len); + } + else + { + printk("ipmi: rx len = 0, it should be not retrun ?\n"); + goto get_BMC_response_fail; + } + } + + rv = 0; + +get_BMC_response_fail: + ipmi_free_recv_msg(msg); + + if (ipmi_wait_queue == 0) + { + comm_data->rx_result = rv; + if (rv == 0) + { + complete(comm_data->rx_read_complete); + } + } +} +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_msg_handler, }; + +int32_t ipmi_request_wait_for_response(struct kernel_ipmi_msg msg, + struct ipmi_comm_data *comm_data) +{ + int32_t rv = 0; + int32_t escape_time = 0; + + struct ipmi_addr ipmi_address; + + if (ipmi_wait_queue >= IPMI_MAX_WAIT_QUEUE) + { + /* printk("msg queue full, cannot send ipmi cmd\n"); */ + return -EBUSY; + } + ipmi_wait_queue++; + + ipmi_address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi_address.channel = IPMI_BMC_CHANNEL; + ipmi_address.data[0] = 0; + + rv = ipmi_validate_addr(&ipmi_address, sizeof(ipmi_address)); + if (rv) + { + printk("ipmi_validate_addr fail, err code : %d\n", rv); + return rv; + } + + ipmi_request_settime(ipmi_mh_user, &ipmi_address, comm_data->tx_id, &msg, + comm_data, 0, 0, 0); + + escape_time = wait_for_completion_timeout(comm_data->rx_read_complete, + IPMI_TIMEOUT); + + rv = comm_data->rx_result; + if (escape_time == 0) + { + printk("BMC not response (%d)\n", escape_time); + } + + return rv; +} + +int32_t ipmi_send_system_cmd(uint8_t *msg_tx_data, int32_t msg_tx_len, + void *msg_rx_data, int32_t msg_rx_len) +{ + int32_t i = 0; + int32_t rv = 0; + + static uint64_t tx_msgid = 1; + + struct kernel_ipmi_msg msg; + struct ipmi_comm_data *comm_data = NULL; + struct completion read_complete; + + init_completion(&read_complete); + + /* prepare transfer message */ + msg.netfn = msg_tx_data[0]; + msg.cmd = msg_tx_data[1]; + msg.data_len = msg_tx_len - 2; + + msg.data = kzalloc(msg.data_len, GFP_KERNEL); + if (msg.data == NULL) + { + printk("%s(%d): malloc [msg.data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + comm_data = kzalloc(sizeof(struct ipmi_comm_data), GFP_KERNEL); + if (comm_data == NULL) + { + printk("%s(%d): malloc [comm_data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + for (i = 2; i < msg_tx_len; i++) + { + msg.data[i - 2] = msg_tx_data[i]; + } + + comm_data->tx_id = tx_msgid++; + + /* prepare recive message */ + comm_data->rx_data = msg_rx_data; + comm_data->rx_len = msg_rx_len; + comm_data->rx_result = -1; + comm_data->rx_read_complete = &read_complete; + + rv = ipmi_request_wait_for_response(msg, comm_data); + +alloc_mem_fail: + if (msg.data) + { + kfree(msg.data); + } + if (comm_data) + { + kfree(comm_data); + } + if (tx_msgid > UINT_MAX) + { + tx_msgid = 1; + } + + return rv; +} + +int32_t ipmi_sdr_get_reservation(uint16_t *reserve_id) +{ + int32_t rv = 0; + uint8_t msg_data[] = { 0x00, GET_SDR_RESERVE_REPO }; /*netfn = 0x00; cmd = GET_SDR_RESERVE_REPO; */ + + msg_data[0] = (g_use_built_in == 0) ? IPMI_NETFN_STORAGE : IPMI_NETFN_SE; + + /* obtain reservation ID */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), reserve_id, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + +#if enable_debug_msg + printk("SDR reservation ID %04x\n", *reserve_id); +#endif + + return rv; +} + +int32_t ipmi_sdr_start(struct ipmi_sdr_iterator *itr) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { IPMI_NETFN_APP, BMC_GET_DEVICE_ID }; /*netfn = IPMI_NETFN_APP; cmd = BMC_GET_DEVICE_ID; */ + + struct ipm_devid_rsp devid; + + /* check SDRR capability */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &devid, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return rv; + } + + if (devid.device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) + { + if ((devid.adtl_device_support & 0x02) == 0) + { + if ((devid.adtl_device_support & 0x01)) + { + printk("Using Device SDRs\n"); + g_use_built_in = 1; + } + else + { + printk("Error obtaining SDR info\n"); + } + } + } + + if (g_use_built_in == 0) + { + struct sdr_repo_info_rs sdr_info; + /* get sdr repository info */ + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + +#if enable_debug_msg + printk("SDR version: 0x%x\n", sdr_info.version); + printk("SDR free space: %d\n", sdr_info.free); +#endif + } + else + { + struct sdr_device_info_rs sdr_info; + /* get device sdr info */ + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + } + +#if enable_debug_msg + printk("SDR records : %d\n", sdr_info.count); +#endif + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + itr->next = 0; + rv = ipmi_sdr_get_reservation(&(itr->reservation)); + } + + return rv; +} + +int32_t ipmi_sdr_get_header(struct ipmi_sdr_iterator *itr, + struct sdr_get_rs *sdr_rs) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = itr->next; + sdr_rq.offset = 0; + sdr_rq.length = 5; /* only get the header */ + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), sdr_rs, 1); + if ((rv) || (sdr_rs->length == 0)) + { + printk("SDR record id 0x%04x: invalid length %d", itr->next, sdr_rs->length); + return -1; + } + + if (sdr_rs->id != itr->next) + { +#if enable_debug_msg + printk("SDR record id mismatch: 0x%04x\n", sdr_rs->id); +#endif + sdr_rs->id = itr->next; + } +#if enable_debug_msg + printk("\nSDR record ID : 0x%04x", itr->next); + printk("SDR record type : 0x%02x\n", sdr_rs->type); + printk("SDR record next : 0x%04x\n", sdr_rs->next); + printk("SDR record bytes: %d\n", sdr_rs->length); +#endif + + return rv; +} + +int32_t ipmi_sdr_get_record(struct sdr_get_rs *header, + struct ipmi_sdr_iterator *itr, uint8_t *ret_data) +{ + int32_t rv = 0, len = 0; + + uint8_t buff[128] = ""; + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + len = header->length; + if (len > 0) + { + memset(&sdr_rq, 0, sizeof(sdr_rq)); + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = header->id; + sdr_rq.offset = 5; + sdr_rq.length = len; + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), ret_data, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + memset(buff, 0, sizeof(buff)); + memcpy(buff, ret_data + 2, sdr_rq.length); + memcpy(ret_data, buff, sdr_rq.length + 2); + } + } + + return rv; +} + +void ipmi_sdr_set_sensor_threshold(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + + /* lower threshold info */ + if (sensor->mask.type.threshold.read.lnc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNC; + } + if (sensor->mask.type.threshold.read.lcr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LCR; + } + if (sensor->mask.type.threshold.read.lnr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNR; + } + g_sensor_data[idx].lowerinfo.lnc = sensor->threshold.lower.non_critical; + g_sensor_data[idx].lowerinfo.lcr = sensor->threshold.lower.critical; + g_sensor_data[idx].lowerinfo.lnr = sensor->threshold.lower.non_recover; + + /* upper threshold info */ + if (sensor->mask.type.threshold.read.unc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNC; + } + if (sensor->mask.type.threshold.read.ucr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UCR; + } + if (sensor->mask.type.threshold.read.unr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNR; + } + g_sensor_data[idx].upperinfo.unc = sensor->threshold.upper.non_critical; + g_sensor_data[idx].upperinfo.ucr = sensor->threshold.upper.critical; + g_sensor_data[idx].upperinfo.unr = sensor->threshold.upper.non_recover; +} + +void ipmi_sdr_set_sensor_factor(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + char *loc = NULL; + + g_sensor_data[idx].sensor_type = sensor->sensor.type; + sprintf(g_sensor_data[idx].sensor_idstring, "%s", sensor->id_string); + + g_sensor_data[idx].recordinfo.record_m = __TO_M(sensor->mtol); + g_sensor_data[idx].recordinfo.record_b = __TO_B(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k1 = __TO_B_EXP(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k2 = __TO_R_EXP(sensor->bacc); + + g_sensor_data[idx].recordinfo.record_analog = sensor->unit.analog; + g_sensor_data[idx].recordinfo.record_linearization = sensor->linearization; + + memset(g_sensor_data[idx].attrinfo.attr_type_str, 0x00, + SENSOR_ATTR_NAME_LENGTH); + + switch (g_sensor_data[idx].sensor_type) + { + case SDR_SENSOR_TYPE_TEMP: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "temp"); + break; + case SDR_SENSOR_TYPE_VOLT: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + break; + case SDR_SENSOR_TYPE_FAN: + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PWM; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_CONMODE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_DIRECTION; + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "fan"); + break; + case SDR_SENSOR_TYPE_PS: + loc = strstr(g_sensor_data[idx].sensor_idstring, "POWER"); + if (loc) + { + if ((strncmp(g_sensor_data[idx].sensor_idstring + 11, "OUT", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MODEL; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_SN; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MFRID; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PSU_PRESENT; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_VIN_TYPE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_POUT_MAX; + } + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "power"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "VOLTAGE"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "CURRENT"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + } + + break; + case SDR_SENSOR_TYPE_CURR: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + break; + case SDR_SENSOR_TYPE_OTHER: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "other"); + break; + default: + printk("not support sensor type !! [%d]\n", g_sensor_data[idx].sensor_type); + break; + } + + if ((strncmp(g_sensor_data[idx].sensor_idstring, "Fan", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_FAN_PRESENT; + } + +#if enable_debug_msg + { + printk("\n********************\n"); + + printk("m[%d], b[%d], k1[%d], k2[%d]\n", g_sensor_data[idx].recordinfo.record_m, + g_sensor_data[idx].recordinfo.record_b + , g_sensor_data[idx].recordinfo.record_k1, + g_sensor_data[idx].recordinfo.record_k2); + + printk("sensor [%s] type[%d], analog[%d], linearization[%d]\n", + g_sensor_data[idx].sensor_idstring, g_sensor_data[idx].sensor_type + , g_sensor_data[idx].recordinfo.record_analog, + g_sensor_data[idx].recordinfo.record_linearization); + + printk("\n********************\n"); + } +#endif + +} + +int32_t sdr_convert_sensor_reading(uint8_t idx, uint8_t val, + int32_t *point_result) +{ + int32_t m = g_sensor_data[idx].recordinfo.record_m; + int32_t b = g_sensor_data[idx].recordinfo.record_b; + int32_t k1 = g_sensor_data[idx].recordinfo.record_k1; + int32_t k2 = g_sensor_data[idx].recordinfo.record_k2; + int32_t decimal_point = 0; + int32_t result = 0; + + decimal_point = pow_convert(&b, k1); + + switch (g_sensor_data[idx].recordinfo.record_analog) + { + case 0: + result = m * val * decimal_point + b; + break; + case 1: + if (val & 0x80) + { + val++; + } + case 2: + result = (m * (int16_t)val) * decimal_point + b; + break; + default: + return result; + } + + pow_convert(&result, k2); + if (k1 < 0) + { + *point_result += -k1; + } + if (k2 < 0) + { + *point_result += -k2; + } + + if (g_sensor_data[idx].sensor_type != SDR_SENSOR_TYPE_FAN) + { + result = result * 1000; /*shift for lm-sensors */ + } + + return result; +} + +int32_t ipmi_sdr_parsing_value(int32_t idx, uint8_t input_value, + int8_t *ret_str) +{ + int32_t calc_result = 0, point_result = 0; + int32_t temp_len = 0; + + uint8_t temp_str[16] = ""; + + calc_result = sdr_convert_sensor_reading(idx, input_value, &point_result); + + temp_len = sprintf(temp_str, "%d", calc_result); + temp_len = temp_len - point_result; + + /* int part */ + if (temp_len <= 0) + { + sprintf(ret_str, "0"); + } + else + { + snprintf(ret_str, temp_len + 1, "%s", + temp_str); /* +1 for snprintf reserve space'\0' */ + } + + /* point part */ + strcat(ret_str, "."); + + /* float part */ + if ((point_result == 0) || (temp_len < 0)) + { + strcat(ret_str, "0"); + } + else + { + strcat(ret_str, temp_str + temp_len); + } + + /* EOL part */ + strcat(ret_str, "\n\0"); + + return (temp_len + 1 + point_result + + 2); /*integer + point + float + EOL + \0 */ +} + + +uint8_t ipmi_check_psu_present(uint8_t psu_slot) +{ + uint8_t slot_mask = 0x0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x03 }; /*netfn = 0x36; cmd = 0xB9; */ + /*uint8_t msg_data[] = { 0x06, 0x52, 0x1B, 0x4C, 0x01, 0x00 }; //netfn = IPMI_NETFN_APP; cmd = GET_PSU_READING; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return 0; + } + else + { + slot_mask = (psu_slot == 1) ? 0x01 : 0x02; + return (returnData[0] & slot_mask) ? 0 : 1; + } +} + +int32_t ipmi_get_psu_info(uint8_t idx, uint8_t cmd, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xBB, 0x4C, 0x1C, 0x00, cmd, 0x00 }; /*netfn = 0x36; cmd = 0xBB; */ + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) + { + psu_slot = 1; + } + else + { + psu_slot = 2; + } + + if (ipmi_check_psu_present(psu_slot)) + { + msg_data[6] = psu_slot; + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + return sprintf(retbuf, "%s\n", returnData); + } + } + else + { + /*printk("Error ! cannot detect PSU%d\n", psu_slot); */ + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_vin_type(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData = 0; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x01, 0xd8 }; // read line status + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + switch (returnData) + { + case 0x7: //LVDC + case 0x3: //HVDC + return sprintf(retbuf, "DC\n"); + default: + return sprintf(retbuf, "AC\n"); + } + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_pout_max(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0, pout_max = 0; + + uint8_t returnData[2] = { 0 }; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x02, 0xa7 }; + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + /* MFR_POUT_MAX has 2 data format: Direct and Linear Data (see PMbus spec). + Query command is needed to tell the data format, but since we have not use PSU + whose output power is over 0x07ff (2047), just check the first 5 bits*/ + if ((returnData[1] & 0xf8) == 0) // Direct + pout_max = (returnData[1] << 8) | returnData[0]; + else // Linear Data + pout_max = (((returnData[1] & 0x07) << 8) | returnData[0]) << ((returnData[1] & 0xf8) >> 3); + return sprintf(retbuf, "%d\n", pout_max); + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +void ipmi_fan_control(uint8_t cmd_data1, uint8_t cmd_data2, uint8_t *retbuf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_TSOL, GET_FAN_INFO, cmd_data1, cmd_data2 }; /*netfn = IPMI_NETFN_TSOL; cmd = GET_FAN_INFO; */ + + mutex_lock(&ipmi_lock); + if (cmd_data1) + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), NULL, 0); + } + else + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + } + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + sprintf(retbuf, "N/A\n"); + } + else + { + sprintf(retbuf, "%s", returnData); + } +} + +static ssize_t show_label(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%s\n", + g_sensor_data[attr->index + DEBUGUSE_SHIFT].sensor_idstring); +} + +static ssize_t show_crit_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%d\n", attr->index); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int32_t rv = 0; + + uint8_t returnData[4] = ""; + uint8_t msg_data[] = { IPMI_NETFN_SE, GET_SENSOR_READING, 0x00 }; /*netfn = IPMI_NETFN_SE; cmd = GET_SENSOR_READING; */ + + mutex_lock(&ipmi_lock); + msg_data[2] = g_sensor_data[attr->index + DEBUGUSE_SHIFT].addr; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "0.0\n"); + } + else + { + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, returnData[0], buf); + } +} + +static ssize_t show_lnr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnr, buf); +} + +static ssize_t show_lcr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lcr, buf); +} + +static ssize_t show_lnc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnc, buf); +} + +static ssize_t show_unr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unr, buf); +} + +static ssize_t show_ucr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.ucr, buf); +} + +static ssize_t show_unc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unc, buf); +} + +static ssize_t show_model(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9a, buf); +} + +static ssize_t show_sn(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9e, buf); +} + +static ssize_t show_mfrid(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x99, buf); +} + +static ssize_t show_vin_type(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_vin_type(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pout_max(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_pout_max(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + uint8_t returnData[10] = { 0 }; + ipmi_fan_control(0x00, 0x00, returnData); + return sprintf(buf, "%d\n", returnData[0]); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + if (g_fan_control_mode == 1) + { + ipmi_fan_control(0x01, store_input, returnData); + } + + return count; +} + +static ssize_t show_controlmode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%d\n", g_fan_control_mode); +} + +static ssize_t store_controlmode(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + g_fan_control_mode = store_input; + if (g_fan_control_mode == 3) + { + ipmi_fan_control(0x7f, 0xff, returnData); + } + + return count; +} + +static ssize_t show_direction(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_STORAGE, GET_FRU_INFO, 0x00, 0x19, 0x00, 0x01 }; /*netfn = IPMI_NETFN_STORAGE; cmd = GET_FRU_INFO; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "N/A\n"); + } + else + { + return sprintf(buf, "%c\n", returnData[1]); + } +} + +static ssize_t show_fanpresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + int32_t fan_idx = 0, fan_present = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x02 }; /*netfn = 0x36; cmd = 0xB9; */ + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + fan_idx = (g_sensor_data[attr->index].sensor_idstring[8] - '0') - 1; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + fan_present = ((returnData[0] >> fan_idx) & 0x1) ? 0 : 1; + + return sprintf(buf, "%d\n", fan_present); +} + +static ssize_t show_psupresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t psu_idx = 0; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + psu_idx = g_sensor_data[attr->index].sensor_idstring[3] - '0'; + + return sprintf(buf, "%d\n", ipmi_check_psu_present(psu_idx)); +} + +static ssize_t(*const attr_show_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, char *buf) = +{ + show_label, show_crit_alarm, show_input + , show_lnc, show_lcr, show_lnr + , show_unc, show_ucr, show_unr + , show_model, show_sn, show_pwm + , show_controlmode, show_direction, show_fanpresent + , show_psupresent, show_mfrid, show_vin_type + , show_pout_max +}; + +static ssize_t(*const attr_store_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) = +{ + NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, store_pwm + , store_controlmode, NULL, NULL + , NULL, NULL, NULL + , NULL +}; + +static const char *const sensor_attrnames[SENSOR_ATTR_MAX] = +{ + "%s%d_label", "%s%d_crit_alarm", "%s%d_input" + , "%s%d_lncrit", "%s%d_lcrit", "%s%d_min" + , "%s%d_ncrit", "%s%d_crit", "%s%d_max" + , "%s%d_model", "%s%d_sn", "%s%d_pwm" + , "%s%d_controlmode", "%s%d_direction", "%s%d_present" + , "%s%d_present", "%s%d_mfrid", "%s%d_vin_type" + , "%s%d_pout_max" +}; + +static int32_t create_sensor_attrs(int32_t attr_no) +{ + int32_t i = 0, j = 0; + + struct attr_info *attrdata = &g_sensor_data[attr_no].attrinfo; + +#if enable_debug_msg + printk("##### %s:%d attr_no %d\n", __FUNCTION__, __LINE__, attr_no); +#endif + + for (i = 0; i < SENSOR_ATTR_MAX; i++) + { + if ((g_sensor_data[attr_no].capability >> i) & 0x01) + { + snprintf(attrdata->attr_name[j], SENSOR_ATTR_NAME_LENGTH, sensor_attrnames[i], + attrdata->attr_type_str, attr_no - DEBUGUSE_SHIFT); + + sysfs_attr_init(&attrdata->sd_attrs[j].dev_attr.attr); + attrdata->sd_attrs[j].dev_attr.attr.name = attrdata->attr_name[j]; + attrdata->sd_attrs[j].dev_attr.show = attr_show_func_ptr[i]; + attrdata->sd_attrs[j].dev_attr.store = attr_store_func_ptr[i]; + + attrdata->sd_attrs[j].dev_attr.attr.mode = S_IRUGO; + if (attrdata->sd_attrs[j].dev_attr.store) + { + attrdata->sd_attrs[j].dev_attr.attr.mode |= S_IWUSR; + } + + attrdata->sd_attrs[j].index = attr_no - DEBUGUSE_SHIFT; + attrdata->attrs[j] = &attrdata->sd_attrs[j].dev_attr.attr; + j++; + + data->total_create_sysfs++; + } + } + + attrdata->attrs[j] = NULL; + attrdata->attr_group.attrs = attrdata->attrs; + + g_sensor_data[attr_no].attrinfo.attr_exist = 1; + + return sysfs_create_group(&data->ipmi_hwmon_dev->kobj, &attrdata->attr_group); +} + +static int32_t remove_sensor_attrs(void) +{ + int32_t i = 0; + + for (i = 0; i < data->total_sensor_id; i++) + { + if (g_sensor_data[i].attrinfo.attr_exist) + { + sysfs_remove_group(&data->ipmi_hwmon_dev->kobj, + &g_sensor_data[i].attrinfo.attr_group); + } + } + return 0; +} + +int32_t ipmi_init_sdr_sensors_data(void) +{ + int32_t sdr_idx = 0; + int32_t err = 0; + + struct ipmi_sdr_iterator *itr = NULL; + struct sdr_get_rs *header = NULL; + + uint8_t *rec = NULL; + + mutex_lock(&ipmi_lock); + + itr = kzalloc(sizeof(struct ipmi_sdr_iterator), GFP_KERNEL); + if (itr == NULL) + { + printk("%s(%d): kzalloc failure.\n", __func__, __LINE__); + goto itr_malloc_fail; + } + + header = kzalloc(sizeof(struct sdr_get_rs), GFP_KERNEL); + if (header == NULL) + { + printk("%s(%d): malloc failure.\n", __func__, __LINE__); + goto header_malloc_fail; + } + + err = ipmi_sdr_start(itr); + if (err) + { + printk("%s(%d): ipmi_sdr_start fail.\n", __func__, __LINE__); + goto ipmi_sdr_start_fail; + } + + data->total_sensor_id = itr->total; + rec = kzalloc(GET_SDR_ENTIRE_RECORD, GFP_KERNEL); + if (rec == NULL) + { + printk("%s(%d): kzalloc failure\n", __func__, __LINE__); + goto rec_malloc_fail; + } + + g_sensor_data = kzalloc(itr->total * sizeof(struct ipmi_sensor_data), + GFP_KERNEL); + if (g_sensor_data == NULL) + { + printk("%s(%d): malloc failure", __func__, __LINE__); + goto g_sensor_data_malloc_fail; + } + + memset(g_sensor_data, 0x0, itr->total * sizeof(struct ipmi_sensor_data)); + + for (sdr_idx = 0; sdr_idx < itr->total; sdr_idx++) + { + err = ipmi_sdr_get_header(itr, header); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_header_fail; + } + + + memset(rec, 0, GET_SDR_ENTIRE_RECORD); + err = ipmi_sdr_get_record(header, itr, rec); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_record_fail; + } + + itr->next = header->next; + + switch (header->type) + { + case SDR_RECORD_TYPE_FULL_SENSOR: + /* prepare (threshold, factor)data whilie init, for reduce reading step and improve operate speed */ + g_sensor_data[sdr_idx].addr = rec[2]; + g_sensor_data[sdr_idx].capability = + SENSOR_GET_CAP_LABEL /*| SENSOR_GET_CAP_ALARM */ | SENSOR_GET_CAP_INPUT; + g_sensor_data[sdr_idx].headerinfo.header_type = header->type; + g_sensor_data[sdr_idx].headerinfo.header_byte = header->length; + + ipmi_sdr_set_sensor_threshold(sdr_idx, (struct sdr_record_full_sensor *) rec); + ipmi_sdr_set_sensor_factor(sdr_idx, (struct sdr_record_full_sensor *) rec); + + if (sdr_idx >= DEBUGUSE_SHIFT) + { + err = create_sensor_attrs(sdr_idx); + if (err) + { + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; + printk("[err : %d]sysfs_create_group fail in [%d] %s\n", err, sdr_idx, + g_sensor_data[sdr_idx].sensor_idstring); + goto create_sysfs_fail; + } + } + + data->total_suport_sensor++; + + break; + case SDR_RECORD_TYPE_COMPACT_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_EVENTONLY_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR: /* not supporrt now */ + default: + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; +#if enable_debug_msg + printk("ID[%d] : not support type [%d]\n", sdr_idx, header->type); +#endif + break; + } + } + + printk("quanta_hwmon_ipmi : detected [%d] sensor, create [%d] sysfs\n", + data->total_suport_sensor, data->total_create_sysfs); + +create_sysfs_fail: +ipmi_sdr_get_header_fail: +ipmi_sdr_get_record_fail: +g_sensor_data_malloc_fail: + if (header) + { + kfree(header); + header = NULL; + } + if (rec) + { + kfree(rec); + rec = NULL; + } + +rec_malloc_fail: +ipmi_sdr_start_fail: +header_malloc_fail: + if (itr) + { + kfree(itr); + itr = NULL; + } + +itr_malloc_fail: + mutex_unlock(&ipmi_lock); + + return err; +} + +static int32_t __init quanta_hwmon_ipmi_init(void) +{ + int32_t err = 0; + + init_completion(&g_read_complete); + + data = kzalloc(sizeof(struct quanta_hwmon_ipmi_data), GFP_KERNEL); + if (NULL == data) + { + printk("alloc data fail\n"); + goto alloc_err; + } + + data->ipmi_platform_dev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + err = IS_ERR(data->ipmi_platform_dev); + if (err) + { + printk("platform device register fail (err : %d)\n", err); + goto device_reg_err; + } + + data->ipmi_hwmon_dev = hwmon_device_register_with_groups(NULL, DRVNAME, NULL, + NULL); + err = IS_ERR(data->ipmi_hwmon_dev); + if (err) + { + printk("hwmon register fail\n"); + goto hwmon_register_err; + } + + err = ipmi_create_user(0, &ipmi_hndlrs, NULL, &ipmi_mh_user); + if (err) + { + printk("warning: create user fail, watchdog broken (err : %d)\n", err); + goto ipmi_create_err; + } + + mutex_init(&ipmi_lock); + err = ipmi_init_sdr_sensors_data(); + if (err) + { + printk("init sensor data fail (err : %d)\n", err); + goto init_sensor_err; + } + + return 0; + +init_sensor_err: + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } +ipmi_create_err: + hwmon_device_unregister(data->ipmi_hwmon_dev); +hwmon_register_err: + platform_device_unregister(data->ipmi_platform_dev); +device_reg_err: + if (data) + { + kfree(data); + data = NULL; + } +alloc_err: + return err; +} + +static void __exit quanta_hwmon_ipmi_exit(void) +{ + remove_sensor_attrs(); + hwmon_device_unregister(data->ipmi_hwmon_dev); + + mutex_lock(&ipmi_lock); + ipmi_destroy_user(ipmi_mh_user); + mutex_unlock(&ipmi_lock); + + platform_device_unregister(data->ipmi_platform_dev); + + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } + + if (data) + { + kfree(data); + data = NULL; + } +} + +module_init(quanta_hwmon_ipmi_init); +module_exit(quanta_hwmon_ipmi_exit); + +MODULE_AUTHOR("Charcar~~Charcar~Charlie li li"); +MODULE_VERSION("2.0"); +MODULE_DESCRIPTION("Quanta BMC hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_platform_ix7.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_platform_ix7.c index a6e5733199..02705e37d8 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_platform_ix7.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/modules/quanta_platform_ix7.c @@ -39,119 +39,12 @@ #include #include #include -#include #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)) #include #else #include #endif -#define MUX_INFO(bus, deselect) \ - {.adap_id = bus, .deselect_on_exit = deselect} - -static struct pca954x_platform_mode pca9548sfp1_modes[] = { - MUX_INFO(0x20, 1), - MUX_INFO(0x21, 1), - MUX_INFO(0x22, 1), - MUX_INFO(0x23, 1), - MUX_INFO(0x24, 1), - MUX_INFO(0x25, 1), - MUX_INFO(0x26, 1), - MUX_INFO(0x27, 1), -}; - -static struct pca954x_platform_data pca9548sfp1_data = { - .modes = pca9548sfp1_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp2_modes[] = { - MUX_INFO(0x28, 1), - MUX_INFO(0x29, 1), - MUX_INFO(0x2a, 1), - MUX_INFO(0x2b, 1), - MUX_INFO(0x2c, 1), - MUX_INFO(0x2d, 1), - MUX_INFO(0x2e, 1), - MUX_INFO(0x2f, 1), -}; - -static struct pca954x_platform_data pca9548sfp2_data = { - .modes = pca9548sfp2_modes, - .num_modes = 8, -}; -static struct pca954x_platform_mode pca9548sfp3_modes[] = { - MUX_INFO(0x30, 1), - MUX_INFO(0x31, 1), - MUX_INFO(0x32, 1), - MUX_INFO(0x33, 1), - MUX_INFO(0x34, 1), - MUX_INFO(0x35, 1), - MUX_INFO(0x36, 1), - MUX_INFO(0x37, 1), -}; - -static struct pca954x_platform_data pca9548sfp3_data = { - .modes = pca9548sfp3_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp4_modes[] = { - MUX_INFO(0x38, 1), - MUX_INFO(0x39, 1), - MUX_INFO(0x3a, 1), - MUX_INFO(0x3b, 1), - MUX_INFO(0x3c, 1), - MUX_INFO(0x3d, 1), - MUX_INFO(0x3e, 1), - MUX_INFO(0x3f, 1), -}; - -static struct pca954x_platform_data pca9548sfp4_data = { - .modes = pca9548sfp4_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9546_modes[] = { - MUX_INFO(0x10, 1), - MUX_INFO(0x11, 1), - MUX_INFO(0x12, 1), - MUX_INFO(0x13, 1), -}; - -static struct pca954x_platform_data pca9546_data = { - .modes = pca9546_modes, - .num_modes = 4, -}; - -static struct pca954x_platform_mode pca9548_modes[] = { - MUX_INFO(0x14, 1), - MUX_INFO(0x15, 1), - MUX_INFO(0x16, 1), - MUX_INFO(0x17, 1), - MUX_INFO(0x18, 1), - MUX_INFO(0x19, 1), - MUX_INFO(0x1a, 1), - MUX_INFO(0x1b, 1), -}; - -static struct pca954x_platform_data pca9548_data = { - .modes = pca9548_modes, - .num_modes = 8, -}; - -/* CPU Board i2c device */ -static struct pca954x_platform_mode pca9546_cpu_modes[] = { - MUX_INFO(0x02, 1), - MUX_INFO(0x03, 1), - MUX_INFO(0x04, 1), - MUX_INFO(0x05, 1), -}; - -static struct pca954x_platform_data pca9546_cpu_data = { - .modes = pca9546_cpu_modes, - .num_modes = 4, -}; //MB Board Data static struct pca953x_platform_data pca9555_1_data = { .gpio_base = 0x10, @@ -164,30 +57,24 @@ static struct pca953x_platform_data pca9555_CPU_data = { static struct i2c_board_info ix7_i2c_devices[] = { { I2C_BOARD_INFO("pca9546", 0x72), // 0 - .platform_data = &pca9546_data, }, { I2C_BOARD_INFO("pca9548", 0x77), // 1 - .platform_data = &pca9548_data, }, { I2C_BOARD_INFO("24c02", 0x54), // 2 0x72 ch2 eeprom }, { I2C_BOARD_INFO("pca9548", 0x73), // 3 0x77 ch0 - .platform_data = &pca9548sfp1_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 4 0x77 ch1 - .platform_data = &pca9548sfp2_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 5 0x77 ch2 - .platform_data = &pca9548sfp3_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 6 0x77 ch3 - .platform_data = &pca9548sfp4_data, }, { I2C_BOARD_INFO("pca9555", 0x23), // 7 0x72 ch3 pca9555 MB Board Data @@ -201,7 +88,6 @@ static struct i2c_board_info ix7_i2c_devices[] = { }, { I2C_BOARD_INFO("pca9546", 0x71), // 10 CPU Board i2c device - .platform_data = &pca9546_cpu_data, }, { I2C_BOARD_INFO("pca9555", 0x20), // 11 0x71 ch0 CPU Board Data @@ -227,9 +113,13 @@ static struct platform_driver ix7_platform_driver = { static struct platform_device *ix7_device; +static struct i2c_client **g_client; +static struct i2c_client **g_client_port; +int numof_i2c_devices = 14; // num of ix7_i2c_devices - 1 (for optoe1) +int numof_ports = 32; + static int __init ix7_platform_init(void) { - struct i2c_client *client; struct i2c_adapter *adapter; int ret, i; @@ -248,55 +138,139 @@ static int __init ix7_platform_init(void) if (ret) goto fail_platform_device; + g_client = kmalloc(sizeof(*g_client) * numof_i2c_devices, GFP_KERNEL); + for (i = 0; i < numof_i2c_devices; i++) g_client[i] = NULL; + + g_client_port = kmalloc(sizeof(*g_client_port) * numof_ports, GFP_KERNEL); + for (i = 0; i < numof_ports; i++) g_client_port[i] = NULL; + adapter = i2c_get_adapter(0); - client = i2c_new_device(adapter, &ix7_i2c_devices[0]); // pca9546 - client = i2c_new_device(adapter, &ix7_i2c_devices[1]); // pca9548 - client = i2c_new_device(adapter, &ix7_i2c_devices[10]); // pca9546 in CPU board - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x02); - client = i2c_new_device(adapter, &ix7_i2c_devices[11]); // CPU Board Data - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x10); - client = i2c_new_device(adapter, &ix7_i2c_devices[8]); // CPLD2 - client = i2c_new_device(adapter, &ix7_i2c_devices[13]); // CPLD_led_1 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x11); - client = i2c_new_device(adapter, &ix7_i2c_devices[9]); // CPLD3 - client = i2c_new_device(adapter, &ix7_i2c_devices[14]); // CPLD_led_2 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x12); - client = i2c_new_device(adapter, &ix7_i2c_devices[2]); // MB_BOARDINFO_EEPROM - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x13); - client = i2c_new_device(adapter, &ix7_i2c_devices[7]); // pca9555 MB Board Data - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x14); - client = i2c_new_device(adapter, &ix7_i2c_devices[3]); // pca9548_1 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x15); - client = i2c_new_device(adapter, &ix7_i2c_devices[4]); // pca9548_2 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x16); - client = i2c_new_device(adapter, &ix7_i2c_devices[5]); // pca9548_3 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x17); - client = i2c_new_device(adapter, &ix7_i2c_devices[6]); // pca9548_4 SFP - i2c_put_adapter(adapter); - for(i = 32; i < 64; i ++){ // QSFP 1~32 EEPROM - adapter = i2c_get_adapter(i); - client = i2c_new_device(adapter, &ix7_i2c_devices[12]); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[0] = i2c_new_device(adapter, &ix7_i2c_devices[0]); // pca9546 + g_client[1] = i2c_new_device(adapter, &ix7_i2c_devices[1]); // pca9548 + g_client[2] = i2c_new_device(adapter, &ix7_i2c_devices[10]); // pca9546 in CPU board i2c_put_adapter(adapter); } + adapter = i2c_get_adapter(13); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[3] = i2c_new_device(adapter, &ix7_i2c_devices[11]); // CPU Board Data + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(1); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[4] = i2c_new_device(adapter, &ix7_i2c_devices[8]); // CPLD2 + g_client[5] = i2c_new_device(adapter, &ix7_i2c_devices[13]); // CPLD_led_1 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(2); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[6] = i2c_new_device(adapter, &ix7_i2c_devices[9]); // CPLD3 + g_client[7] = i2c_new_device(adapter, &ix7_i2c_devices[14]); // CPLD_led_2 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(3); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[8] = i2c_new_device(adapter, &ix7_i2c_devices[2]); // MB_BOARDINFO_EEPROM + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(4); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[9] = i2c_new_device(adapter, &ix7_i2c_devices[7]); // pca9555 MB Board Data + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(5); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[10] = i2c_new_device(adapter, &ix7_i2c_devices[3]); // pca9548_1 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(6); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[11] = i2c_new_device(adapter, &ix7_i2c_devices[4]); // pca9548_2 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(7); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[12] = i2c_new_device(adapter, &ix7_i2c_devices[5]); // pca9548_3 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(8); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[13] = i2c_new_device(adapter, &ix7_i2c_devices[6]); // pca9548_4 SFP + i2c_put_adapter(adapter); + } + + for(i = 17; i < 49; i ++){ // QSFP 1~32 EEPROM + adapter = i2c_get_adapter(i); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client_port[i - 17] = i2c_new_device(adapter, &ix7_i2c_devices[12]); + i2c_put_adapter(adapter); + } + } + return 0; fail_platform_device: @@ -309,6 +283,26 @@ fail_platform_driver: static void __exit ix7_platform_exit(void) { + int i = 0; + + for (i = numof_ports - 1; i >= 0; i--) + { + if (g_client_port[i]) + { + i2c_unregister_device(g_client_port[i]); + g_client_port[i] = NULL; + } + } + + for (i = numof_i2c_devices - 1; i >= 0; i--) + { + if (g_client[i]) + { + i2c_unregister_device(g_client[i]); + g_client[i] = NULL; + } + } + platform_device_unregister(ix7_device); platform_driver_unregister(&ix7_platform_driver); } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/service/ix7-platform-init.service b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/service/ix7-platform-init.service old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/setup.py index a2f84b31a5..7973be9205 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/setup.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import sys from setuptools import setup os.listdir diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/__init__.py new file mode 100644 index 0000000000..d82f374931 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/chassis.py new file mode 100644 index 0000000000..58d44f4c55 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/chassis.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import sys + import time + import syslog + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 32 + self.__num_of_sfps = 0 + self.__num_of_fan_drawers = 6 + self.__fan_per_drawer = 2 + self.__num_of_thermals = 15 + self.__xcvr_presence = {} + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + fan_index = 1 + for drawer_index in range(1, self.__num_of_fan_drawers + 1): + drawer_fan_list = [] + for index in range(0, self.__fan_per_drawer): + fan = Fan(fan_index, False) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(1, self.__num_of_ports + 1): + if index in range(1, self.__num_of_sfps + 1): + sfp = Sfp(index, 'SFP') + else: + sfp = Sfp(index, 'QSFP') + + self._sfp_list.append(sfp) + + for index in range(1, self.__num_of_ports + 1): + self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() + +############################################## +# Device methods +############################################## + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + For Quanta the index in sfputil.py starts from 1, so override + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + if (index == 0): + raise IndexError + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("override: SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_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 + +############################################## +# Chassis methods +############################################## + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + 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. + """ + hw_reboot_cause = "" + with open("/sys/class/watchdog/watchdog0/reboot_reason", "r") as f: + hw_reboot_cause = f.read().strip('\n') + + if hw_reboot_cause == "2": + reboot_cause = self.REBOOT_CAUSE_WATCHDOG + description = 'Hardware Watchdog Reset' + else: + reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE + description = 'Unknown reason' + + return (reboot_cause, description) + + + ############################################## + # Other methods + ############################################## + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + """ + try: + if self._watchdog is None: + from sonic_platform.watchdog import Watchdog + # Create the watchdog Instance + self._watchdog = Watchdog() + + except Exception as e: + syslog.syslog(syslog.LOG_ERR, "Fail to load watchdog due to {}".format(e)) + return self._watchdog + + def get_change_event(self, timeout=0): + """ + Currently only support transceiver change events + """ + + start_ms = time.time() * 1000 + xcvr_change_event_dict = {} + event = False + + while True: + time.sleep(0.5) + for index in range(1, self.__num_of_ports + 1): + cur_xcvr_presence = self._sfp_list[index-1].get_presence() + if cur_xcvr_presence != self.__xcvr_presence[index]: + if cur_xcvr_presence is True: + xcvr_change_event_dict[str(index)] = '1' + self.__xcvr_presence[index] = True + elif cur_xcvr_presence is False: + xcvr_change_event_dict[str(index)] = '0' + self.__xcvr_presence[index] = False + event = True + + if event is True: + return True, {'sfp':xcvr_change_event_dict} + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, {'sfp':xcvr_change_event_dict} + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/eeprom.py new file mode 100644 index 0000000000..ef01115fe7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/eeprom.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.__eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + 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] + + if tlv[0] == self._TLV_CODE_VENDOR_EXT: + value = str((tlv[2] << 24) | (tlv[3] << 16) | + (tlv[4] << 8) | tlv[5]) + value += tlv[6:6 + tlv[1]].decode('ascii') + else: + value = self.decoder(None, tlv)[30:] + + 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): + (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): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in results[2]]).upper() + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + + def decoder(self, s, t): + ''' + Return a string representing the contents of the TLV field. The format of + the string is: + 1. The name of the field left justified in 20 characters + 2. The type code in hex right justified in 5 characters + 3. The length in decimal right justified in 4 characters + 4. The value, left justified in however many characters it takes + The vailidity of EEPROM contents and the TLV field has been verified + prior to calling this function. The 's' parameter is unused + ''' + if t[0] == self._TLV_CODE_PRODUCT_NAME: + name = "Product Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PART_NUMBER: + name = "Part Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERIAL_NUMBER: + name = "Serial Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_BASE: + name = "Base MAC Address" + value = ":".join(["{:02x}".format(T) for T in t[2:8]]).upper() + elif t[0] == self._TLV_CODE_MANUF_DATE: + name = "Manufacture Date" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DEVICE_VERSION: + name = "Device Version" + value = str(t[2]) + elif t[0] == self._TLV_CODE_LABEL_REVISION: + name = "Label Revision" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PLATFORM_NAME: + name = "Platform Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_ONIE_VERSION: + name = "ONIE Version" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_SIZE: + name = "MAC Addresses" + value = str((t[2] << 8) | t[3]) + elif t[0] == self._TLV_CODE_MANUF_NAME: + name = "Manufacturer" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MANUF_COUNTRY: + name = "Manufacture Country" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_NAME: + name = "Vendor Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DIAG_VERSION: + name = "Diag Version" + # Quanta legacy format of diag version + if t[1] == 4: + value = "{}.{}.{}.{}".format('{:02x}'.format(t[2])[0], '{:02x}'.format(t[2])[1], + '{:02x}'.format(t[3])[0], '{:02x}'.format(t[3])[1]) + else: + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERVICE_TAG: + name = "Service Tag" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_EXT: + name = "Vendor Extension" + value = "" + if self._TLV_DISPLAY_VENDOR_EXT: + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + elif t[0] == self._TLV_CODE_CRC_32 and len(t) == 6: + name = "CRC-32" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + # Quanta specific codes below here. + # These decodes are lifted from their U-Boot codes + elif t[0] == self._TLV_CODE_QUANTA_MAGIC and len(t) == 3: + name = "Magic Number" + value = "0x%02X" % t[2] + elif t[0] == self._TLV_CODE_QUANTA_CRC and len(t) == 4: + name = "QUANTA-CRC" + value = "0x%04X" % ((t[2] << 8) + t[3]) + elif t[0] == self._TLV_CODE_QUANTA_CARD_TYPE and len(t) == 6: + name = "Card Type" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + elif t[0] == self._TLV_CODE_QUANTA_HW_VERSION and len(t) == 6: + name = "Hardware Version" + value = "%d.%d" % (t[2], t[3]) + elif t[0] == self._TLV_CODE_QUANTA_SW_VERSION and len(t) == 6: + name = "Software Version" + value = "%d.%d.%d.%d" % ((t[2] >> 4), (t[2] & 0xF), (t[3] >> 4), (t[3] & 0xF)) + elif t[0] == self._TLV_CODE_QUANTA_MANUF_DATE and len(t) == 6: + name = "Manufacture Date" + value = "%04d/%d/%d" % (((t[2] << 8) | t[3]), t[4], t[5]) + elif t[0] == self._TLV_CODE_QUANTA_MODEL_NAME: + name = "Model Name" + value = t[2:2 + t[1]].decode("ascii") + else: + name = "Unknown" + value = "" + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + return name, value \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/fan.py new file mode 100644 index 0000000000..31bbe0e52e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/fan.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta IX7 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import logging + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +HWMON_DIR = "/sys/class/hwmon/hwmon1/" +FAN_INDEX_START = 21 +NUM_FANTRAYS = 6 +FANS_PERTRAY = 2 + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + self.fan_index = index + self.psu_fan_index_mapping = { + 1:40, + 2:50, + } + self.psu_index_mapping = { + 1:42, + 2:52, + } + if self.is_psu_fan: + self.fan_presence_attr = "power{}_present".format(self.psu_index_mapping[index]) + self.fan_pwm_attr = "fan{}_pwm".format(self.psu_fan_index_mapping[index]) + self.fan_rpm_attr = "fan{}_input".format(self.psu_fan_index_mapping[index]) + self.fan_direction_attr = "fan{}_direction".format(self.psu_fan_index_mapping[index]) + else: + self.fan_presence_attr = "fan{}_present".format(FAN_INDEX_START+(index-1)) + self.fan_pwm_attr = "fan{}_pwm".format(FAN_INDEX_START+(index-1)) + self.fan_rpm_attr = "fan{}_input".format(FAN_INDEX_START+(index-1)) + self.fan_direction_attr = "fan{}_direction".format(FAN_INDEX_START+(index-1)) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + 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.fan_index) + else: + fantray_index = (self.fan_index-1)//FANS_PERTRAY+1 + fan_index_intray = self.fan_index - ((fantray_index-1)*FANS_PERTRAY) + return "Fantray{}_{}".format(fantray_index, fan_index_intray) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.fan_presence_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == '1'): + return True + else: + return False + + return None + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR' and attr_rv != '0.0'): + return True + else: + return False + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + attr_path = HWMON_DIR + self.fan_direction_attr + attr_rv = self.__get_attr_value(attr_path) + + if attr_rv == '2': + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 25 + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + + Args: + color: A string representing the color with which to set the + fan module status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return True + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..75e954576a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/fan_drawer.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/platform.py new file mode 100644 index 0000000000..c4f945277f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +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): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/psu.py new file mode 100644 index 0000000000..49846fff48 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/psu.py @@ -0,0 +1,320 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import logging + 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") + +HWMON_DIR = "/sys/class/hwmon/hwmon1/" + + +class Psu(PsuBase): + def __init__(self, index): + PsuBase.__init__(self) + fan = Fan(index, True) + self._fan_list.append(fan) + + self.psu_index_mapping = { + 1:42, + 2:52, + } + self.psu_powerin_index_mapping = { + 1:41, + 2:51, + } + self.psu_currentout_index_mapping = { + 1:39, + 2:49, + } + self.psu_currentin_index_mapping = { + 1:38, + 2:48, + } + self.psu_voltageout_index_mapping = { + 1:47, + 2:57, + } + self.psu_voltagein_index_mapping = { + 1:46, + 2:56, + } + self.index = index + self.psu_presence_attr = "power{}_present".format(self.psu_index_mapping[self.index]) + self.psu_status_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_power_in_attr = "power{}_input".format(self.psu_powerin_index_mapping[self.index]) + self.psu_power_out_attr = "power{}_input".format(self.psu_index_mapping[self.index]) + self.psu_voltage_out_attr = "in{}_input".format(self.psu_voltageout_index_mapping[self.index]) + self.psu_current_out_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_voltage_in_attr = "in{}_input".format(self.psu_voltagein_index_mapping[self.index]) + self.psu_current_in_attr = "curr{}_input".format(self.psu_currentin_index_mapping[self.index]) + self.psu_serial_attr = "power{}_sn".format(self.psu_index_mapping[self.index]) + self.psu_model_attr = "power{}_model".format(self.psu_index_mapping[self.index]) + self.psu_mfr_id_attr = "power{}_mfrid".format(self.psu_index_mapping[self.index]) + self.psu_capacity_attr = "power{}_pout_max".format(self.psu_index_mapping[self.index]) + self.psu_type_attr = "power{}_vin_type".format(self.psu_index_mapping[self.index]) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + fd.close() + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = HWMON_DIR+self.psu_presence_attr + attr_normal = '1' + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = HWMON_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_mfr_id(self): + """ + Retrieves the manufacturer's name (or id) of the device + + Returns: + string: Manufacturer's id of device + """ + mfr_id = "N/A" + attr_path = HWMON_DIR+self.psu_mfr_id_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + mfr_id = attr_rv + + return mfr_id + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = HWMON_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = HWMON_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = HWMON_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_out = float(attr_rv) / 1000 + + return current_out + + def get_input_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_in = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_in = float(attr_rv) / 1000 + + return voltage_in + + def get_input_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_in = 0.0 + attr_path = HWMON_DIR+self.psu_current_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_in = float(attr_rv) / 1000 + + return current_in + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = HWMON_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + power_out = float(attr_rv) / 1000 + + return power_out + + 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. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + type = "AC" + attr_path = HWMON_DIR+self.psu_type_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + type = attr_rv + + return type + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + capacity = 0 + attr_path = HWMON_DIR+self.psu_capacity_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + try: + capacity = int(attr_rv) + except ValueError: + capacity = 0 + + return capacity + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/sfp.py new file mode 100644 index 0000000000..c97e91d74a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/sfp.py @@ -0,0 +1,1596 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +#import subprocess +#import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase +# from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_MODULE_THRESHOLD_OFFSET = 512 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 560 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +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_TYPE = "SFP" +QSFP_TYPE = "QSFP" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 32 + QSFP_START = 1 + QSFP_END = 32 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-quanta_ix7_rglbmc-r0" + HWSKU = "Quanta-IX7-32X" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + #self.dom_supported = False + self.sfp_type = sfp_type + self.lpmode_path = "/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/lpmode" + self.reset_path = "/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/reset" + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 1 : 17, + 2 : 18, + 3 : 19, + 4 : 20, + 5 : 21, + 6 : 22, + 7 : 23, + 8 : 24, + 9 : 25, + 10 : 26, + 11 : 27, + 12 : 28, + 13 : 29, + 14 : 30, + 15 : 31, + 16 : 32, + 17 : 33, + 18 : 34, + 19 : 35, + 20 : 36, + 21 : 37, + 22 : 38, + 23 : 39, + 24 : 40, + 25 : 41, + 26 : 42, + 27 : 43, + 28 : 44, + 29 : 45, + 30 : 46, + 31 : 47, + 32 : 48 + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self.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', 'vendor_date', + 'vendor_oui', 'application_advertisement'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', + 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the SFP module + Returns: + bool: True if SFP module is present, False if not + """ + # Check for invalid port_num + if self.port_num < self.PORT_START or self.port_num > self.PORT_END: + return False + + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/module_present") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + reg_file.close() + if reg_value == '1': + return True + + return False + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + eeprom_raw = None + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability = int(qsfp_dom_capability_raw[0], 16) + + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + if qsfp_version_compliance_raw is not None: + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qsfp_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qsfp_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qsfp_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + self.dom_tx_disable_supported = True + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ======================================================================== + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + if not self.get_presence(): + return transceiver_info_dict + + if self.sfp_type == QSFP_TYPE: + offset = QSFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == SFP_TYPE: + offset = SFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + else: + return transceiver_info_dict + + # Add retry for xcvr eeprom to get ready + max_retry = 10 + for i in range(0,max_retry): + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is not None: + break + else: + if not self.get_presence(): + return transceiver_info_dict + elif i == max_retry-1: + pass + else: + time.sleep(0.5) + + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + transceiver_info_dict['type'] = sfp_interface_bulk_data \ + ['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data \ + ['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data \ + ['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data \ + ['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data \ + ['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data \ + ['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data \ + ['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data \ + ['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data \ + ['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data \ + ['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data \ + ['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = 'N/A' + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = QSFP_DOM_OFFSET + offset_xcvr = QSFP_INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability_data = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qsfp_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + if not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + else: + return None + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + if not self.get_presence() or not sfpd_obj: + return {} + DOM_OFFSET = 0 + transceiver_dom_threshold_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + offset = DOM_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + module_threshold_values = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_channel_thres_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNEL_THRESHOLD_OFFSET), QSFP_CHANNEL_THRESHOLD_WIDTH) + if dom_channel_thres_raw is not None: + channel_threshold_values = sfpd_obj.parse_channel_threshold_values(dom_channel_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + else: + channel_threshold_data = None + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + DOM_OFFSET = 256 + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + else: + return None + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.reset_path) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return True + else: + return False + else: + return None + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + else: + return None + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + else: + return None + + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + else: + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return 0 + elif self.sfp_type == QSFP_TYPE: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + else: + return None + + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this QSFP module + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.lpmode_path) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return False + else: + return True + else: + return None + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_POWEROVERRIDE_OFFSET), QSFP_POWEROVERRIDE_WIDTH) + if dom_control_raw is not None: + if int(dom_control_raw[0],16) & (0x01 << QSFP_POWEROVERRIDE_BIT): + return True + else: + return False + else: + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( \ + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default state. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.reset_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/reset", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + offset = 256 + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( + status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(offset + SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + else: + return None + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + else: + return False + else: + return None + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.lpmode_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + else: + return None + + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings(self.__get_path_to_port_config_file()) + print("self.index{}".format(self.index)) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/thermal.py new file mode 100644 index 0000000000..bf5757c9fa --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/thermal.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import logging +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +HWMON_DIR = "/sys/class/hwmon/hwmon1/" + +thermal_index_mapping = { + 1:43, + 2:44, + 3:45, + 4:53, + 5:54, + 6:55, + 7:68, + 8:69, + 9:70, + 10:71, + 11:72, + 12:73, + 13:74, + 14:75, + 15:76 +} + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index + self.temp_attr = "temp{}_input".format(thermal_index_mapping[self.index]) + self.high_th_attr = "temp{}_ncrit".format(thermal_index_mapping[self.index]) + self.high_crit_th_attr = "temp{}_crit".format(thermal_index_mapping[self.index]) + self.name_attr = "temp{}_label".format(thermal_index_mapping[self.index]) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return attr_rv + else: + return None + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if (self.get_temperature() != None): + return True + else: + return False + + 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 + """ + attr_path = HWMON_DIR + self.temp_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + 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 + """ + attr_path = HWMON_DIR + self.high_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + def get_high_critical_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 + """ + attr_path = HWMON_DIR + self.high_crit_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/watchdog.py new file mode 100644 index 0000000000..282f356f4e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform/watchdog.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python + +############################################################################# +# +# Watchdog contains an implementation of SONiC Platform Base Watchdog API +# +############################################################################# +import fcntl +import os +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +""" ioctl constants """ +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +""" Watchdog ioctl commands """ +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +""" Watchdog status constants """ +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +WDT_COMMON_ERROR = -1 +WD_MAIN_IDENTITY = "iTCO_wdt" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + +DEFAULT_TIMEOUT=180 + +class Watchdog(WatchdogBase): + + def __init__(self): + + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = DEFAULT_TIMEOUT + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WD_MAIN_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + self.watchdog = os.open(watchdog_device_path, os.O_RDWR) + return self.watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + return int(req[0]) + + def _gettimeout(self, timeout_path): + """ + Get watchdog timeout + @return watchdog timeout + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + ################################################################# + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of 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 , 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. + """ + + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._settimeout(seconds) + self._enable() + self.armed = True + ret = self.timeout + except IOError as e: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + Returns: + A boolean, True if watchdog is armed, False if not + """ + + return self.armed + + 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 thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + + os.close(self.watchdog) + + + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform_setup.py new file mode 100644 index 0000000000..a4899c6183 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/sonic_platform_setup.py @@ -0,0 +1,24 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Quanta Platforms', + license='Apache 2.0', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/utils/quanta_ix7_util.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/utils/quanta_ix7_util.py old mode 100644 new mode 100755 index e583d2374a..901f7ba1ae --- a/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/utils/quanta_ix7_util.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-32x/utils/quanta_ix7_util.py @@ -21,19 +21,17 @@ Usage: %(scriptName)s [options] command object options: -h | --help : this help message -d | --debug : run with debug mode - -f | --force : ignore error during installation or clean + -f | --force : ignore error during installation or clean command: install : install drivers and generate related sysfs nodes - clean : uninstall drivers and remove related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes """ import os import commands import sys, getopt import logging -import re import time -from collections import namedtuple DEBUG = False args = [] @@ -43,77 +41,68 @@ i2c_prefix = '/sys/bus/i2c/devices/' if DEBUG == True: print sys.argv[0] - print 'ARGV :', sys.argv[1:] + print 'ARGV :', sys.argv[1:] def main(): global DEBUG global args global FORCE - + if len(sys.argv)<2: show_help() - + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', 'debug', 'force', ]) - if DEBUG == True: + if DEBUG == True: print options print args print len(sys.argv) - + for opt, arg in options: if opt in ('-h', '--help'): show_help() - elif opt in ('-d', '--debug'): + elif opt in ('-d', '--debug'): DEBUG = True logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): + elif opt in ('-f', '--force'): FORCE = 1 else: - logging.info('no option') - for arg in args: + logging.info('no option') + for arg in args: if arg == 'install': install() elif arg == 'clean': uninstall() else: show_help() - - - return 0 - + + + return 0 + def show_help(): print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} sys.exit(0) - + def show_log(txt): if DEBUG == True: print "[IX7-32X]"+txt return - + def exec_cmd(cmd, show): - logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) show_log (cmd +"with result:" + str(status)) - show_log (" output:"+output) + show_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: print('Failed :'+cmd) return status, output - + instantiate =[ -#turn on module power -'echo 21 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio21/direction', -'echo 1 >/sys/class/gpio/gpio21/value', -#Reset fron-ports LED CPLD -'echo 73 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio73/direction', -'echo 0 >/sys/class/gpio/gpio73/value', -'echo 1 >/sys/class/gpio/gpio73/value', #Enable front-ports LED decoding 'echo 1 > /sys/class/cpld-led/CPLDLED-1/led_decode', 'echo 1 > /sys/class/cpld-led/CPLDLED-2/led_decode', @@ -130,27 +119,40 @@ drivers =[ 'lpc_ich', 'i2c-i801', 'i2c-dev', +'i2c-mux-pca954x force_deselect_on_exit=1', +'gpio-pca953x', +'optoe', +'qci_cpld', +'qci_cpld_led', +'quanta_platform_ix7', +'ipmi_devintf', +'quanta_hwmon_ipmi' +] + +un_drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', 'i2c-mux-pca954x', 'gpio-pca953x', 'optoe', 'qci_cpld', 'qci_cpld_led', 'quanta_platform_ix7', -'ipmi_devintf' +'ipmi_devintf', +'quanta_hwmon_ipmi' ] - - def system_install(): global FORCE #remove default drivers to avoid modprobe order conflicts - status, output = exec_cmd("echo 'blacklist i2c-ismt' > /etc/modprobe.d/blacklist.conf", 1) + exec_cmd("echo 'blacklist i2c-ismt' > /etc/modprobe.d/blacklist.conf", 1) time.sleep(1) - status, output = exec_cmd("modprobe -r i2c-ismt ", 1) - status, output = exec_cmd("modprobe -r i2c-i801 ", 1) + exec_cmd("modprobe -r i2c-ismt ", 1) + exec_cmd("modprobe -r i2c-i801 ", 1) #setup driver dependency - status, output = exec_cmd("depmod -a ", 1) + exec_cmd("depmod -a ", 1) #install drivers for i in range(0,len(drivers)): status, output = exec_cmd("modprobe "+drivers[i], 1) @@ -159,6 +161,18 @@ def system_install(): if FORCE == 0: return status + #turn on module power + exec_cmd("echo 21 > /sys/class/gpio/export ", 1) + exec_cmd("echo high > /sys/class/gpio/gpio21/direction ", 1) + + #Reset fron-ports LED CPLD + exec_cmd("echo 33 > /sys/class/gpio/export ", 1) + status, output = exec_cmd("cat /sys/class/gpio/gpio33/value", 1) + if output != '1': + exec_cmd("echo out > /sys/class/gpio/gpio33/direction ", 1) + exec_cmd("echo 0 >/sys/class/gpio/gpio33/value", 1) + exec_cmd("echo 1 >/sys/class/gpio/gpio33/value", 1) + #instantiate devices for i in range(0,len(instantiate)): status, output = exec_cmd(instantiate[i], 1) @@ -166,26 +180,32 @@ def system_install(): print output if FORCE == 0: return status - + #QSFP for 1~32 port for port_number in range(1,33): - bus_number = port_number + 31 + bus_number = port_number + 16 os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) - return - - + return + + def system_ready(): - if not device_found(): + if not device_found(): return False return True - -def install(): + +def install(): if not device_found(): - print "No device, installing...." - status = system_install() + print "No device, installing...." + status = system_install() if status: - if FORCE == 0: - return status + if FORCE == 0: + return status + + status, output = exec_cmd("pip3 install /usr/share/sonic/device/x86_64-quanta_ix7_rglbmc-r0/sonic_platform-1.0-py3-none-any.whl",1) + if status: + print output + if FORCE == 0: + return status else: print " ix7 driver already installed...." return @@ -193,17 +213,28 @@ def install(): def uninstall(): global FORCE #uninstall drivers - for i in range(len(drivers)-1,-1,-1): - status, output = exec_cmd("rmmod "+drivers[i], 1) + for i in range(len(un_drivers)-1,-1,-1): + status, output = exec_cmd("rmmod "+un_drivers[i], 1) if status: print output if FORCE == 0: return status + + status, output = exec_cmd("pip3 uninstall sonic-platform -y ",1) + if status: + print output + if FORCE == 0: + return status return def device_found(): - ret1, log = exec_cmd("ls "+i2c_prefix+"i2c-0", 0) - return ret1 + ret1, log1 = exec_cmd("cat /proc/modules | grep ix7 > /tmp/chkdriver.log", 0) + ret2, log2 = exec_cmd("cat /tmp/chkdriver.log | grep ix7", 0) + + if ret1 == 0 and len(log2) > 0: + return True + else: + return False if __name__ == "__main__": main() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/classes/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/classes/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/Makefile b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/Makefile new file mode 100644 index 0000000000..160b2a28f1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/Makefile @@ -0,0 +1,3 @@ +obj-m:=qci_cpld.o qci_cpld_led.o quanta_platform_ix7_bwde.o quanta_hwmon_ipmi.o + + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/qci_cpld.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/qci_cpld.c new file mode 100644 index 0000000000..1d2bf20233 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/qci_cpld.c @@ -0,0 +1,463 @@ +/* + * A CPLD driver for monitor QSFP28 module I/O + * + * The CPLD is customize by Quanta for controlling QSFP28 module signals, + * they are RESET , INTERREPT , Module_Present, LPMODE + * Each CPLD control 16 modules, each module use 4 bits in register. + * + * Copyright (C) 2015 Quanta Inc. + * + * Author: Luffy Cheng + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDA(cpld_ida); + +enum platform_type { + SFP = 0, + QSFP, + QSFP28, + NONE +}; + +static struct class *cpld_class = NULL; + +struct sfp_data { + struct i2c_client *cpld_client; + char name[8]; + char type[8]; + u8 port_id; + u8 cpld_port; +}; + +struct cpld_data { + struct mutex lock; + struct device *port_dev[16]; + struct sfp_data *port_data[16]; +}; + +static int cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int cpld_remove(struct i2c_client *client); + +static const struct i2c_device_id cpld_id[] = { + { "CPLD-SFP", SFP }, + { "CPLD-QSFP", QSFP }, + { "CPLD-QSFP28", QSFP28 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cpld_id); + +static struct i2c_driver cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "qci_cpld", + }, + .probe = cpld_probe, + .remove = cpld_remove, + .id_table = cpld_id, +// .address_list = normal_i2c, +}; + +#define CPLD_ID_PREFIX "port-" +#define CPLD_ID_FORMAT CPLD_ID_PREFIX "%d" + +#define RESET_MASK 0x08 +#define INTERRUPT_MASK 0x04 +#define MODULE_PRESENT_MASK 0x02 +#define LPMODE_MASK 0x01 +//#define I2C_MONITOR_MASK 0x01 + +static inline u8 get_group_cmd(u8 group) +{ + //FIXME: if group cmd change + return (group + 1); +} + +static inline u8 port_remapping(u8 phy_port) +{ + /* FIXME: implement by hardware design */ + /* The CPLD register port mapping is weird : + * MSB -------- LSB (word data) + * P3 P4 P1 P2 (per port 4 bits) + * For easy coding bit shift, we treat it as hw port swap + */ + return (phy_port % 2) ? (phy_port - 1) : (phy_port + 1); +} + +static ssize_t get_reset(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= RESET_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t get_interrupt(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= INTERRUPT_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t get_module_present(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + int retry = 0; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + for (retry = 0; retry < 10; retry++) + { + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value >= 0) + break; + else + printk("%s: retry:%d\n", __FUNCTION__, retry); + msleep(1); + } + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= MODULE_PRESENT_MASK; + + //FIXME: if present is not low active + return sprintf(buf, "%d\n", value ? 0 : 1); +} + +static ssize_t get_lpmode(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= LPMODE_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t set_reset(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + long disable; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value &= ~(RESET_MASK << (group_port * 4)); + if (disable) + value |= (RESET_MASK << (group_port * 4)); + + dev_dbg(&client->dev, "write group%d value= %x\n", group + 1, value); + + i2c_smbus_write_word_data(client, get_group_cmd(group), (u16)value); +// mutex_unlock(&data->lock); + + return count; +} + +static ssize_t set_lpmode(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + long disable; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value &= ~(LPMODE_MASK << (group_port * 4)); + if (disable) + value |= (LPMODE_MASK << (group_port * 4)); + + dev_dbg(&client->dev, "write group%d value= %x\n", group + 1, value); + + i2c_smbus_write_word_data(client, get_group_cmd(group), (u16)value); +// mutex_unlock(&data->lock); + + return count; +} + +static DEVICE_ATTR(reset, S_IWUSR | S_IRUGO, get_reset, set_reset); +static DEVICE_ATTR(lpmode, S_IWUSR | S_IRUGO, get_lpmode, set_lpmode); +static DEVICE_ATTR(module_present, S_IRUGO, get_module_present, NULL); +static DEVICE_ATTR(interrupt, S_IRUGO, get_interrupt, NULL); +//static DEVICE_ATTR(led_enable, S_IWUSR | S_IRUGO, get_led_enable, set_led_enable); +//static DEVICE_ATTR(monitor_enable, S_IWUSR | S_IRUGO, get_monitor_enable, set_monitor_enable); + +static const struct attribute *sfp_attrs[] = { + &dev_attr_reset.attr, + &dev_attr_lpmode.attr, + &dev_attr_module_present.attr, + &dev_attr_interrupt.attr, +// &dev_attr_led_enable.attr, + NULL, +}; + +static const struct attribute_group sfp_attr_group = { + .attrs = (struct attribute **) sfp_attrs, +}; + +static int cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cpld_data *data; + struct sfp_data *port_data; +// struct i2c_monitor_data *monitor_data; + struct device *port_dev; +// struct device *i2c_dev; + int port_nr, i=0, err, max_port_num; + char name[I2C_NAME_SIZE], type[I2C_NAME_SIZE]; + + printk("cpld cpld_probe\n"); + + while(id->name[i]) + { + name[i]=tolower(id->name[i]); + i++; + } + name[i]='\0'; + strncpy(type,name+5,strlen(name)-5); + type[strlen(name)-5]='\0'; + + if (!cpld_class) + { + cpld_class = class_create(THIS_MODULE, "cpld-qsfp28"); + if (IS_ERR(cpld_class)) { + pr_err("couldn't create sysfs class\n"); + return PTR_ERR(cpld_class); + } + } + + data = devm_kzalloc(&client->dev, sizeof(struct cpld_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + if(!strcmp(client->name, "CPLD-QSFP28")){ + max_port_num = 16; + } + else{ + max_port_num = 4; + } + + /* register sfp port data to sysfs */ + for (i = 0; i < max_port_num; i++) + { + port_nr = ida_simple_get(&cpld_ida, 1, 99, GFP_KERNEL); + if (port_nr < 0) + goto err_out; + + port_data = kzalloc(sizeof(struct sfp_data), GFP_KERNEL); + + port_dev = device_create(cpld_class, &client->dev, MKDEV(0,0), port_data, CPLD_ID_FORMAT, port_nr); + if (IS_ERR(port_dev)) { + err = PTR_ERR(port_dev); + printk("err_status\n"); + } + + data->port_dev[i] = port_dev; + data->port_data[i] = port_data; + + strcpy(port_data->type, type); + + dev_info(&client->dev, "Register %s port-%d\n", port_data->type , port_nr); + + /* FIXME: implement Logical/Physical port remapping */ + //port_data->cpld_port = i; + port_data->cpld_port = port_remapping(i); + sprintf(port_data->name, "port-%d", port_nr); + port_data->port_id = port_nr; + dev_set_drvdata(port_dev, port_data); + port_dev->init_name = port_data->name; + port_data->cpld_client = client; + + err = sysfs_create_group(&port_dev->kobj, &sfp_attr_group); + // if (status) printk("err status\n"); + } + + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + dev_info(&client->dev, "%s device found\n", client->name); + + + return 0; + +err_out: + return port_nr; +} + +/* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if 0 +static int idr_has_entry(int id, void *p, void *data) +{ + return 1; +} + +static bool cpld_idr_is_empty(struct idr *idp) +{ + return !idr_for_each(idp, idr_has_entry, NULL); +} +#endif + +static int cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + int i, max_port_num; +// int id; + + if(!strcmp(client->name, "CPLD-QSFP28")){ + max_port_num = 16; + } + else{ + max_port_num = 4; + } + + for (i = (max_port_num - 1); i >= 0; i--) + { + dev_info(data->port_dev[i], "Remove %s port-%d\n", data->port_data[i]->type , data->port_data[i]->port_id); + device_unregister(data->port_dev[i]); + ida_simple_remove(&cpld_ida, data->port_data[i]->port_id); + kfree(data->port_data[i]); + } + + if (ida_is_empty(&cpld_ida)) + { + class_destroy(cpld_class); + cpld_class = NULL; + } + + return 0; +} + +module_i2c_driver(cpld_driver); + +MODULE_AUTHOR("Luffy Cheng "); +MODULE_DESCRIPTION("Quanta Switch QSFP28 CPLD driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/qci_cpld_led.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/qci_cpld_led.c new file mode 100644 index 0000000000..d924f51ebc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/qci_cpld_led.c @@ -0,0 +1,284 @@ +/* + * A LED CPLD driver for Quanta Switch Platform + * + * The CPLD is customize by Quanta for decode led bit stream, + * This driver modify from Quanta CPLD I/O driver. + * + * Copyright (C) 2015 Quanta Inc. + * + * Author: Luffy Cheng + * Author: Roger Chang + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDA(cpld_led_ida); + +enum platform_type { + IX7 = 0, + IX8, + IX7_BWDE, + IX8A_BWDE, + NONE +}; + +static struct class *cpld_class = NULL; + +struct cpld_data { + struct i2c_client *cpld_client; + char name[8]; + u8 cpld_id; +}; + +struct cpld_led_data { + struct mutex lock; + struct device *port_dev; + struct cpld_data *cpld_data; +}; + +static int cpld_led_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int cpld_led_remove(struct i2c_client *client); + +static const struct i2c_device_id cpld_led_id[] = { + { "CPLDLED_IX7", IX7 }, + { "CPLDLED_IX8", IX8 }, + { "CPLDLED_IX7_BWDE", IX7_BWDE }, + { "CPLDLED_IX8A_BWDE", IX8A_BWDE }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cpld_led_id); + +static struct i2c_driver cpld_led_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "qci_cpld_led", + }, + .probe = cpld_led_probe, + .remove = cpld_led_remove, + .id_table = cpld_led_id, +// .address_list = normal_i2c, +}; + +#define CPLD_LED_ID_PREFIX "CPLDLED-" +#define CPLD_LED_ID_FORMAT CPLD_LED_ID_PREFIX "%d" + +#define CPLD_DECODER_OFFSET 0x4 +#define CPLD_DECODER_MASK 0x1 +#define CPLD_USERCODE_START_OFFSET 0x0 + +static ssize_t get_led_decode(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 offset = (u8)(CPLD_DECODER_OFFSET); + s32 value; + + value = i2c_smbus_read_byte_data(client, offset); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read led decode value= %x\n", value); + + value &= CPLD_DECODER_MASK; + + return sprintf(buf, "%d\n", (value == 0) ? 1 : 0); +} + +static ssize_t get_usercode(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 i = 0; + s32 value = 0, reading = 0; + + for (i = 0; i < 4; i++) + { + reading = i2c_smbus_read_byte_data(client, CPLD_USERCODE_START_OFFSET + i); + if (reading < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read led usercode reg %d value= %x\n", i, reading); + + value |= reading << (24 - 8 * i); + } + + return sprintf(buf, "%X\n", value); +} + +static ssize_t set_led_decode(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + s32 value; + long enable; + + if (kstrtol(buf, 0, &enable)) + return -EINVAL; + + if ((enable != 1) && (enable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_byte_data(client, CPLD_DECODER_OFFSET); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read led decode value= %x\n", value); + + value |= CPLD_DECODER_MASK; + if (enable) + value &= ~CPLD_DECODER_MASK; + + dev_dbg(&client->dev, "write led decode value= %x\n", value); + + i2c_smbus_write_byte_data(client, CPLD_DECODER_OFFSET, (u8)value); +// mutex_unlock(&data->lock); + + return count; +} + +static DEVICE_ATTR(led_decode, S_IWUSR | S_IRUGO, get_led_decode, set_led_decode); +static DEVICE_ATTR(usercode, S_IRUGO, get_usercode, NULL); + +static const struct attribute *led_attrs[] = { + &dev_attr_usercode.attr, + &dev_attr_led_decode.attr, + NULL, +}; + +static const struct attribute_group led_attr_group = { + .attrs = (struct attribute **) led_attrs, +}; + +static int cpld_led_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cpld_led_data *data; + struct cpld_data *led_data; + struct device *port_dev; + int nr, err; + + if (!cpld_class) + { + cpld_class = class_create(THIS_MODULE, "cpld-led"); + if (IS_ERR(cpld_class)) { + pr_err("couldn't create sysfs class\n"); + return PTR_ERR(cpld_class); + } + } + + data = devm_kzalloc(&client->dev, sizeof(struct cpld_led_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* Test */ + nr = ida_simple_get(&cpld_led_ida, 1, 99, GFP_KERNEL); + if (nr < 0) + goto err_out; + + led_data = kzalloc(sizeof(struct cpld_led_data), GFP_KERNEL); + + port_dev = device_create(cpld_class, &client->dev, MKDEV(0,0), led_data, CPLD_LED_ID_FORMAT, nr); + if (IS_ERR(port_dev)) { + err = PTR_ERR(port_dev); + // printk("err_status\n"); + } + + data->port_dev = port_dev; + data->cpld_data = led_data; + + dev_info(&client->dev, "Register CPLDLED %d\n", nr); + + sprintf(led_data->name, "LED%d-data", nr); + led_data->cpld_id = nr; + dev_set_drvdata(port_dev, led_data); + port_dev->init_name = led_data->name; + led_data->cpld_client = client; + + err = sysfs_create_group(&port_dev->kobj, &led_attr_group); + // if (status) printk("err status\n"); + /* end */ + + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + dev_info(&client->dev, "%s device found\n", client->name); + + + return 0; + +err_out: + return nr; +} + +#if 0 +/* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +static int idr_has_entry(int id, void *p, void *data) +{ + return 1; +} + +static bool cpld_idr_is_empty(struct idr *idp) +{ + return !idr_for_each(idp, idr_has_entry, NULL); +} +#endif + +static int cpld_led_remove(struct i2c_client *client) +{ + struct cpld_led_data *data = i2c_get_clientdata(client); + + dev_info(data->port_dev, "Remove CPLDLED-%d\n", data->cpld_data->cpld_id); + device_unregister(data->port_dev); + ida_simple_remove(&cpld_led_ida, data->cpld_data->cpld_id); + kfree(data->cpld_data); + + if (ida_is_empty(&cpld_led_ida)) + { + class_destroy(cpld_class); + cpld_class = NULL; + } + + return 0; +} + +module_i2c_driver(cpld_led_driver); + +MODULE_AUTHOR("Luffy Cheng "); +MODULE_AUTHOR("Roger Chang "); +MODULE_DESCRIPTION("Quanta Switch LED CPLD driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/quanta_hwmon_ipmi.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/quanta_hwmon_ipmi.c new file mode 100644 index 0000000000..08d6a97d9a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/quanta_hwmon_ipmi.c @@ -0,0 +1,1908 @@ +/* +* +* A hwmon driver for the Quanta switch BMC hwmon +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define enable_debug_msg 0 +#define DEBUGUSE_SHIFT 0 + +#define DRVNAME "quanta_hwmon_ipmi" + +#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & (1<<((bits)-1))) | (val)) : (val)) +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) +#define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) +#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & 0xff000000) >> 24) | ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) +#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4), 4)) +#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) + +#define SENSOR_ATTR_MAX 19 +#define SENSOR_ATTR_NAME_LENGTH 20 + +#define SENSOR_GET_CAP_LABEL 0x001 +#define SENSOR_GET_CAP_ALARM 0x002 +#define SENSOR_GET_CAP_INPUT 0x004 + +#define SENSOR_GET_CAP_LNC 0x008 +#define SENSOR_GET_CAP_LCR 0x010 +#define SENSOR_GET_CAP_LNR 0x020 + +#define SENSOR_GET_CAP_UNC 0x040 +#define SENSOR_GET_CAP_UCR 0x080 +#define SENSOR_GET_CAP_UNR 0x100 + +#define SENSOR_GET_CAP_MODEL 0x200 +#define SENSOR_GET_CAP_SN 0x400 +#define SENSOR_GET_CAP_PWM 0x800 + +#define SENSOR_GET_CAP_CONMODE 0x1000 +#define SENSOR_GET_CAP_DIRECTION 0x2000 +#define SENSOR_GET_CAP_FAN_PRESENT 0x4000 +#define SENSOR_GET_CAP_PSU_PRESENT 0x8000 + +#define SENSOR_GET_CAP_MFRID 0x10000 +#define SENSOR_GET_CAP_VIN_TYPE 0x20000 +#define SENSOR_GET_CAP_POUT_MAX 0x40000 + +#define SDR_SENSOR_TYPE_TEMP 0x01 +#define SDR_SENSOR_TYPE_VOLT 0x02 +#define SDR_SENSOR_TYPE_CURR 0x03 +#define SDR_SENSOR_TYPE_FAN 0x04 +#define SDR_SENSOR_TYPE_PS 0x08 +#define SDR_SENSOR_TYPE_OTHER 0x0b + +#define BMC_GET_DEVICE_ID 0x01 + +#define IPMI_NETFN_SE 0x04 +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_STORAGE 0x0a +#define IPMI_NETFN_TSOL 0x30 + +#define GET_SDR_REPO_INFO 0x20 +#define GET_DEVICE_SDR 0x21 +#define GET_SDR_RESERVE_REPO 0x22 +#define GET_SDR 0x23 +#define GET_SENSOR_THRESHOLDS 0x27 +#define GET_SENSOR_EVENT_ENABLE 0x29 +#define GET_SENSOR_EVENT_STATUS 0x2b +#define GET_SENSOR_READING 0x2d +#define GET_PSU_READING 0x52 +#define GET_FAN_INFO 0xd6 +#define GET_FRU_INFO 0x11 + +#define IPM_DEV_DEVICE_ID_SDR_MASK (0x80) /* 1 = provides SDRs */ +#define IPMI_TIMEOUT (4 * HZ) +#define IPMI_MAX_WAIT_QUEUE 1 + +struct quanta_hwmon_ipmi_data +{ + struct platform_device *ipmi_platform_dev; + struct device *ipmi_hwmon_dev; + /*struct mutex ipmi_lock; */ + + int32_t total_sensor_id; + int32_t total_suport_sensor; + int32_t total_create_sysfs; +} *data; + +static struct mutex ipmi_lock; +static struct completion g_read_complete; + +static ipmi_user_t ipmi_mh_user = NULL; + +static int8_t g_fan_control_mode = 3; +static int32_t g_use_built_in = 0; +static int32_t ipmi_wait_queue = 0; + +struct ipmi_sensor_data +{ + uint8_t addr; + uint8_t sensor_type; + uint8_t sensor_idstring[SENSOR_ATTR_NAME_LENGTH]; + + uint32_t capability; + + struct header_info + { + uint8_t header_type; + uint8_t header_byte; + } headerinfo; + + struct record_info + { + uint8_t record_analog; + uint8_t record_linearization; + + int32_t record_m; + int32_t record_b; + int32_t record_k1; + int32_t record_k2; + } recordinfo; + + struct threshold_upper_info + { + uint8_t unr; + uint8_t ucr; + uint8_t unc; + } upperinfo; + + struct threshold_lower_info + { + uint8_t lnr; + uint8_t lcr; + uint8_t lnc; + } lowerinfo; + + struct attr_info + { + bool attr_exist; + char attr_name[SENSOR_ATTR_MAX][SENSOR_ATTR_NAME_LENGTH]; + char attr_type_str[SENSOR_ATTR_NAME_LENGTH]; + + struct attribute *attrs[SENSOR_ATTR_MAX + 1]; + struct attribute_group attr_group; + struct sensor_device_attribute sd_attrs[SENSOR_ATTR_MAX + 1]; + } attrinfo; + +} *g_sensor_data; + +struct ipmi_comm_data +{ + int32_t tx_id; + + int32_t rx_result; + int64_t rx_len; + void *rx_data; + struct completion *rx_read_complete; +}; + +struct ipmi_sdr_iterator +{ + uint16_t reservation; + int32_t total; + int32_t next; +}; + +struct ipm_devid_rsp +{ + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +} __attribute__((packed)); + +struct sdr_repo_info_rs +{ + uint8_t version; /* SDR version (51h) */ + uint16_t count; /* number of records */ + uint16_t free; /* free space in SDR */ + uint32_t add_stamp; /* last add timestamp */ + uint32_t erase_stamp; /* last del timestamp */ + uint8_t op_support; /* supported operations */ +} __attribute__((packed)); + +struct sdr_device_info_rs +{ + uint8_t count; /* number of records */ + uint8_t flags; /* flags */ + uint8_t popChangeInd[3]; /* free space in SDR */ +} __attribute__((packed)); + +struct sdr_get_rs +{ + uint16_t next; /* next record id */ + uint16_t id; /* record ID */ + uint8_t version; /* SDR version (51h) */ +#define SDR_RECORD_TYPE_FULL_SENSOR 0x01 +#define SDR_RECORD_TYPE_COMPACT_SENSOR 0x02 +#define SDR_RECORD_TYPE_EVENTONLY_SENSOR 0x03 +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC 0x09 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 +#define SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR 0x11 +#define SDR_RECORD_TYPE_MC_DEVICE_LOCATOR 0x12 +#define SDR_RECORD_TYPE_MC_CONFIRMATION 0x13 +#define SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO 0x14 +#define SDR_RECORD_TYPE_OEM 0xc0 + uint8_t type; /* record type */ + uint8_t length; /* remaining record bytes */ +} __attribute__((packed)); + +struct sdr_get_rq +{ + uint16_t reserve_id; /* reservation ID */ + uint16_t id; /* record ID */ + uint8_t offset; /* offset into SDR */ +#define GET_SDR_ENTIRE_RECORD 0xff + uint8_t length; /* length to read */ +} __attribute__((packed)); + +struct entity_id +{ + uint8_t id; /* physical entity id */ +#ifdef WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} __attribute__((packed)); + +struct sdr_record_mask +{ + union + { + struct + { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event mask */ + uint16_t read; /* discrete reading mask */ + } discrete; + struct + { +#ifdef WORDS_BIGENDIAN + uint16_t reserved : 1; + uint16_t status_lnr : 1; + uint16_t status_lcr : 1; + uint16_t status_lnc : 1; + uint16_t assert_unr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lnc_low : 1; +#else + uint16_t assert_lnc_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_unr_high : 1; + uint16_t status_lnc : 1; + uint16_t status_lcr : 1; + uint16_t status_lnr : 1; + uint16_t reserved : 1; +#endif +#ifdef WORDS_BIGENDIAN + uint16_t reserved_2 : 1; + uint16_t status_unr : 1; + uint16_t status_ucr : 1; + uint16_t status_unc : 1; + uint16_t deassert_unr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lnc_low : 1; +#else + uint16_t deassert_lnc_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_unr_high : 1; + uint16_t status_unc : 1; + uint16_t status_ucr : 1; + uint16_t status_unr : 1; + uint16_t reserved_2 : 1; +#endif + union + { + struct + { +#ifdef WORDS_BIGENDIAN /* settable threshold mask */ + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; + /* padding lower 8 bits */ + uint16_t readable : 8; +#else + uint16_t readable : 8; + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; +#endif + } set; + struct + { +#ifdef WORDS_BIGENDIAN /* readable threshold mask */ + /* padding upper 8 bits */ + uint16_t settable : 8; + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; +#else + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; + uint16_t settable : 8; +#endif + } read; + }; + } threshold; + } type; +} __attribute__((packed)); + +struct sdr_record_full_sensor +{ + struct + { + uint8_t owner_id; +#ifdef WORDS_BIGENDIAN + uint8_t channel : 4; /* channel number */ + uint8_t __reserved : 2; + uint8_t lun : 2; /* sensor owner lun */ +#else + uint8_t lun : 2; /* sensor owner lun */ + uint8_t __reserved : 2; + uint8_t channel : 4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } keys; + + struct entity_id entity; + + struct + { + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 1; + uint8_t scanning : 1; + uint8_t events : 1; + uint8_t thresholds : 1; + uint8_t hysteresis : 1; + uint8_t type : 1; + uint8_t event_gen : 1; + uint8_t sensor_scan : 1; +#else + uint8_t sensor_scan : 1; + uint8_t event_gen : 1; + uint8_t type : 1; + uint8_t hysteresis : 1; + uint8_t thresholds : 1; + uint8_t events : 1; + uint8_t scanning : 1; + uint8_t __reserved : 1; +#endif + } init; + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t ignore : 1; + uint8_t rearm : 1; + uint8_t hysteresis : 2; + uint8_t threshold : 2; + uint8_t event_msg : 2; +#else + uint8_t event_msg : 2; + uint8_t threshold : 2; + uint8_t hysteresis : 2; + uint8_t rearm : 1; + uint8_t ignore : 1; +#endif + } capabilities; + uint8_t type; + } sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t analog : 2; + uint8_t rate : 3; + uint8_t modifier : 2; + uint8_t pct : 1; +#else + uint8_t pct : 1; + uint8_t modifier : 2; + uint8_t rate : 3; + uint8_t analog : 2; +#endif + struct + { + uint8_t base; + uint8_t modifier; + } type; + } unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 5; + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t nominal_read : 1; /* nominal reading field specified */ +#else + uint8_t nominal_read : 1; /* nominal reading field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t __reserved : 5; +#endif + } analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct + { + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } upper; + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } lower; + struct + { + uint8_t positive; + uint8_t negative; + } hysteresis; + } threshold; + uint8_t __reserved[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} __attribute__((packed)); + +int32_t pow_convert(int32_t *a, int32_t b) +{ + /* function input parameter (a * 10 ^ b) */ + int32_t i = 0, r = 1, temp_b = 0; + + temp_b = (b > 0) ? b : -b; + + for (i = 0; i < temp_b; i++) + { + r = r * 10; + } + + if (b > 0) + { + *a = (*a) * r; + r = 1; + } + /* function return parameter calc_result = *a, decimal_point = r */ + return r; +} + +void simple_atoi(const char *buf, int8_t *output_val) +{ + while (*buf >= '0' && *buf <= '9') + { + *output_val = *output_val * 10 + *buf - '0'; + buf++; + } +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) +{ + int32_t rv = -IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + struct ipmi_comm_data *comm_data = msg->user_msg_data; + + ipmi_wait_queue--; + + if (msg->msg.data[0] != 0) + { + if ((msg->msg.data[0] != 0x83) && (msg->msg.netfn != 0x07) + && (msg->msg.cmd != 0x52)) + { + /*skip master r/w cmd return code */ + printk("ipmi: Error 0x%x on cmd 0x%x/0x%x\n", msg->msg.data[0], msg->msg.netfn, + msg->msg.cmd); + rv = msg->msg.data[0]; + goto get_BMC_response_fail; + } + } + + if (msg->msgid != comm_data->tx_id) + { + printk("ipmi: rx msgid %d mismatch tx msgid %d\n", (int32_t)msg->msgid, + comm_data->tx_id); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len <= 0) + { + printk("ipmi: Data len too low (%d)\n", msg->msg.data_len); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len > 1) + { + if (comm_data->rx_len) + { + comm_data->rx_len = msg->msg.data_len - 1; + memcpy(comm_data->rx_data, msg->msg.data + 1, comm_data->rx_len); + } + else + { + printk("ipmi: rx len = 0, it should be not retrun ?\n"); + goto get_BMC_response_fail; + } + } + + rv = 0; + +get_BMC_response_fail: + ipmi_free_recv_msg(msg); + + if (ipmi_wait_queue == 0) + { + comm_data->rx_result = rv; + if (rv == 0) + { + complete(comm_data->rx_read_complete); + } + } +} +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_msg_handler, }; + +int32_t ipmi_request_wait_for_response(struct kernel_ipmi_msg msg, + struct ipmi_comm_data *comm_data) +{ + int32_t rv = 0; + int32_t escape_time = 0; + + struct ipmi_addr ipmi_address; + + if (ipmi_wait_queue >= IPMI_MAX_WAIT_QUEUE) + { + /* printk("msg queue full, cannot send ipmi cmd\n"); */ + return -EBUSY; + } + ipmi_wait_queue++; + + ipmi_address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi_address.channel = IPMI_BMC_CHANNEL; + ipmi_address.data[0] = 0; + + rv = ipmi_validate_addr(&ipmi_address, sizeof(ipmi_address)); + if (rv) + { + printk("ipmi_validate_addr fail, err code : %d\n", rv); + return rv; + } + + ipmi_request_settime(ipmi_mh_user, &ipmi_address, comm_data->tx_id, &msg, + comm_data, 0, 0, 0); + + escape_time = wait_for_completion_timeout(comm_data->rx_read_complete, + IPMI_TIMEOUT); + + rv = comm_data->rx_result; + if (escape_time == 0) + { + printk("BMC not response (%d)\n", escape_time); + } + + return rv; +} + +int32_t ipmi_send_system_cmd(uint8_t *msg_tx_data, int32_t msg_tx_len, + void *msg_rx_data, int32_t msg_rx_len) +{ + int32_t i = 0; + int32_t rv = 0; + + static uint64_t tx_msgid = 1; + + struct kernel_ipmi_msg msg; + struct ipmi_comm_data *comm_data = NULL; + struct completion read_complete; + + init_completion(&read_complete); + + /* prepare transfer message */ + msg.netfn = msg_tx_data[0]; + msg.cmd = msg_tx_data[1]; + msg.data_len = msg_tx_len - 2; + + msg.data = kzalloc(msg.data_len, GFP_KERNEL); + if (msg.data == NULL) + { + printk("%s(%d): malloc [msg.data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + comm_data = kzalloc(sizeof(struct ipmi_comm_data), GFP_KERNEL); + if (comm_data == NULL) + { + printk("%s(%d): malloc [comm_data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + for (i = 2; i < msg_tx_len; i++) + { + msg.data[i - 2] = msg_tx_data[i]; + } + + comm_data->tx_id = tx_msgid++; + + /* prepare recive message */ + comm_data->rx_data = msg_rx_data; + comm_data->rx_len = msg_rx_len; + comm_data->rx_result = -1; + comm_data->rx_read_complete = &read_complete; + + rv = ipmi_request_wait_for_response(msg, comm_data); + +alloc_mem_fail: + if (msg.data) + { + kfree(msg.data); + } + if (comm_data) + { + kfree(comm_data); + } + if (tx_msgid > UINT_MAX) + { + tx_msgid = 1; + } + + return rv; +} + +int32_t ipmi_sdr_get_reservation(uint16_t *reserve_id) +{ + int32_t rv = 0; + uint8_t msg_data[] = { 0x00, GET_SDR_RESERVE_REPO }; /*netfn = 0x00; cmd = GET_SDR_RESERVE_REPO; */ + + msg_data[0] = (g_use_built_in == 0) ? IPMI_NETFN_STORAGE : IPMI_NETFN_SE; + + /* obtain reservation ID */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), reserve_id, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + +#if enable_debug_msg + printk("SDR reservation ID %04x\n", *reserve_id); +#endif + + return rv; +} + +int32_t ipmi_sdr_start(struct ipmi_sdr_iterator *itr) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { IPMI_NETFN_APP, BMC_GET_DEVICE_ID }; /*netfn = IPMI_NETFN_APP; cmd = BMC_GET_DEVICE_ID; */ + + struct ipm_devid_rsp devid; + + /* check SDRR capability */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &devid, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return rv; + } + + if (devid.device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) + { + if ((devid.adtl_device_support & 0x02) == 0) + { + if ((devid.adtl_device_support & 0x01)) + { + printk("Using Device SDRs\n"); + g_use_built_in = 1; + } + else + { + printk("Error obtaining SDR info\n"); + } + } + } + + if (g_use_built_in == 0) + { + struct sdr_repo_info_rs sdr_info; + /* get sdr repository info */ + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + +#if enable_debug_msg + printk("SDR version: 0x%x\n", sdr_info.version); + printk("SDR free space: %d\n", sdr_info.free); +#endif + } + else + { + struct sdr_device_info_rs sdr_info; + /* get device sdr info */ + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + } + +#if enable_debug_msg + printk("SDR records : %d\n", sdr_info.count); +#endif + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + itr->next = 0; + rv = ipmi_sdr_get_reservation(&(itr->reservation)); + } + + return rv; +} + +int32_t ipmi_sdr_get_header(struct ipmi_sdr_iterator *itr, + struct sdr_get_rs *sdr_rs) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = itr->next; + sdr_rq.offset = 0; + sdr_rq.length = 5; /* only get the header */ + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), sdr_rs, 1); + if ((rv) || (sdr_rs->length == 0)) + { + printk("SDR record id 0x%04x: invalid length %d", itr->next, sdr_rs->length); + return -1; + } + + if (sdr_rs->id != itr->next) + { +#if enable_debug_msg + printk("SDR record id mismatch: 0x%04x\n", sdr_rs->id); +#endif + sdr_rs->id = itr->next; + } +#if enable_debug_msg + printk("\nSDR record ID : 0x%04x", itr->next); + printk("SDR record type : 0x%02x\n", sdr_rs->type); + printk("SDR record next : 0x%04x\n", sdr_rs->next); + printk("SDR record bytes: %d\n", sdr_rs->length); +#endif + + return rv; +} + +int32_t ipmi_sdr_get_record(struct sdr_get_rs *header, + struct ipmi_sdr_iterator *itr, uint8_t *ret_data) +{ + int32_t rv = 0, len = 0; + + uint8_t buff[128] = ""; + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + len = header->length; + if (len > 0) + { + memset(&sdr_rq, 0, sizeof(sdr_rq)); + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = header->id; + sdr_rq.offset = 5; + sdr_rq.length = len; + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), ret_data, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + memset(buff, 0, sizeof(buff)); + memcpy(buff, ret_data + 2, sdr_rq.length); + memcpy(ret_data, buff, sdr_rq.length + 2); + } + } + + return rv; +} + +void ipmi_sdr_set_sensor_threshold(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + + /* lower threshold info */ + if (sensor->mask.type.threshold.read.lnc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNC; + } + if (sensor->mask.type.threshold.read.lcr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LCR; + } + if (sensor->mask.type.threshold.read.lnr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNR; + } + g_sensor_data[idx].lowerinfo.lnc = sensor->threshold.lower.non_critical; + g_sensor_data[idx].lowerinfo.lcr = sensor->threshold.lower.critical; + g_sensor_data[idx].lowerinfo.lnr = sensor->threshold.lower.non_recover; + + /* upper threshold info */ + if (sensor->mask.type.threshold.read.unc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNC; + } + if (sensor->mask.type.threshold.read.ucr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UCR; + } + if (sensor->mask.type.threshold.read.unr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNR; + } + g_sensor_data[idx].upperinfo.unc = sensor->threshold.upper.non_critical; + g_sensor_data[idx].upperinfo.ucr = sensor->threshold.upper.critical; + g_sensor_data[idx].upperinfo.unr = sensor->threshold.upper.non_recover; +} + +void ipmi_sdr_set_sensor_factor(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + char *loc = NULL; + + g_sensor_data[idx].sensor_type = sensor->sensor.type; + sprintf(g_sensor_data[idx].sensor_idstring, "%s", sensor->id_string); + + g_sensor_data[idx].recordinfo.record_m = __TO_M(sensor->mtol); + g_sensor_data[idx].recordinfo.record_b = __TO_B(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k1 = __TO_B_EXP(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k2 = __TO_R_EXP(sensor->bacc); + + g_sensor_data[idx].recordinfo.record_analog = sensor->unit.analog; + g_sensor_data[idx].recordinfo.record_linearization = sensor->linearization; + + memset(g_sensor_data[idx].attrinfo.attr_type_str, 0x00, + SENSOR_ATTR_NAME_LENGTH); + + switch (g_sensor_data[idx].sensor_type) + { + case SDR_SENSOR_TYPE_TEMP: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "temp"); + break; + case SDR_SENSOR_TYPE_VOLT: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + break; + case SDR_SENSOR_TYPE_FAN: + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PWM; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_CONMODE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_DIRECTION; + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "fan"); + break; + case SDR_SENSOR_TYPE_PS: + loc = strstr(g_sensor_data[idx].sensor_idstring, "POWER"); + if (loc) + { + if ((strncmp(g_sensor_data[idx].sensor_idstring + 11, "OUT", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MODEL; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_SN; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MFRID; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PSU_PRESENT; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_VIN_TYPE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_POUT_MAX; + } + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "power"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "VOLTAGE"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "CURRENT"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + } + + break; + case SDR_SENSOR_TYPE_CURR: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + break; + case SDR_SENSOR_TYPE_OTHER: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "other"); + break; + default: + printk("not support sensor type !! [%d]\n", g_sensor_data[idx].sensor_type); + break; + } + + if ((strncmp(g_sensor_data[idx].sensor_idstring, "Fan", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_FAN_PRESENT; + } + +#if enable_debug_msg + { + printk("\n********************\n"); + + printk("m[%d], b[%d], k1[%d], k2[%d]\n", g_sensor_data[idx].recordinfo.record_m, + g_sensor_data[idx].recordinfo.record_b + , g_sensor_data[idx].recordinfo.record_k1, + g_sensor_data[idx].recordinfo.record_k2); + + printk("sensor [%s] type[%d], analog[%d], linearization[%d]\n", + g_sensor_data[idx].sensor_idstring, g_sensor_data[idx].sensor_type + , g_sensor_data[idx].recordinfo.record_analog, + g_sensor_data[idx].recordinfo.record_linearization); + + printk("\n********************\n"); + } +#endif + +} + +int32_t sdr_convert_sensor_reading(uint8_t idx, uint8_t val, + int32_t *point_result) +{ + int32_t m = g_sensor_data[idx].recordinfo.record_m; + int32_t b = g_sensor_data[idx].recordinfo.record_b; + int32_t k1 = g_sensor_data[idx].recordinfo.record_k1; + int32_t k2 = g_sensor_data[idx].recordinfo.record_k2; + int32_t decimal_point = 0; + int32_t result = 0; + + decimal_point = pow_convert(&b, k1); + + switch (g_sensor_data[idx].recordinfo.record_analog) + { + case 0: + result = m * val * decimal_point + b; + break; + case 1: + if (val & 0x80) + { + val++; + } + case 2: + result = (m * (int16_t)val) * decimal_point + b; + break; + default: + return result; + } + + pow_convert(&result, k2); + if (k1 < 0) + { + *point_result += -k1; + } + if (k2 < 0) + { + *point_result += -k2; + } + + if (g_sensor_data[idx].sensor_type != SDR_SENSOR_TYPE_FAN) + { + result = result * 1000; /*shift for lm-sensors */ + } + + return result; +} + +int32_t ipmi_sdr_parsing_value(int32_t idx, uint8_t input_value, + int8_t *ret_str) +{ + int32_t calc_result = 0, point_result = 0; + int32_t temp_len = 0; + + uint8_t temp_str[16] = ""; + + calc_result = sdr_convert_sensor_reading(idx, input_value, &point_result); + + temp_len = sprintf(temp_str, "%d", calc_result); + temp_len = temp_len - point_result; + + /* int part */ + if (temp_len <= 0) + { + sprintf(ret_str, "0"); + } + else + { + snprintf(ret_str, temp_len + 1, "%s", + temp_str); /* +1 for snprintf reserve space'\0' */ + } + + /* point part */ + strcat(ret_str, "."); + + /* float part */ + if ((point_result == 0) || (temp_len < 0)) + { + strcat(ret_str, "0"); + } + else + { + strcat(ret_str, temp_str + temp_len); + } + + /* EOL part */ + strcat(ret_str, "\n\0"); + + return (temp_len + 1 + point_result + + 2); /*integer + point + float + EOL + \0 */ +} + + +uint8_t ipmi_check_psu_present(uint8_t psu_slot) +{ + uint8_t slot_mask = 0x0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x03 }; /*netfn = 0x36; cmd = 0xB9; */ + /*uint8_t msg_data[] = { 0x06, 0x52, 0x1B, 0x4C, 0x01, 0x00 }; //netfn = IPMI_NETFN_APP; cmd = GET_PSU_READING; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return 0; + } + else + { + slot_mask = (psu_slot == 1) ? 0x01 : 0x02; + return (returnData[0] & slot_mask) ? 0 : 1; + } +} + +int32_t ipmi_get_psu_info(uint8_t idx, uint8_t cmd, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xBB, 0x4C, 0x1C, 0x00, cmd, 0x00 }; /*netfn = 0x36; cmd = 0xBB; */ + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) + { + psu_slot = 1; + } + else + { + psu_slot = 2; + } + + if (ipmi_check_psu_present(psu_slot)) + { + msg_data[6] = psu_slot; + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + return sprintf(retbuf, "%s\n", returnData); + } + } + else + { + /*printk("Error ! cannot detect PSU%d\n", psu_slot); */ + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_vin_type(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData = 0; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x01, 0xd8 }; // read line status + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + switch (returnData) + { + case 0x7: //LVDC + case 0x3: //HVDC + return sprintf(retbuf, "DC\n"); + default: + return sprintf(retbuf, "AC\n"); + } + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_pout_max(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0, pout_max = 0; + + uint8_t returnData[2] = { 0 }; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x02, 0xa7 }; + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + /* MFR_POUT_MAX has 2 data format: Direct and Linear Data (see PMbus spec). + Query command is needed to tell the data format, but since we have not use PSU + whose output power is over 0x07ff (2047), just check the first 5 bits*/ + if ((returnData[1] & 0xf8) == 0) // Direct + pout_max = (returnData[1] << 8) | returnData[0]; + else // Linear Data + pout_max = (((returnData[1] & 0x07) << 8) | returnData[0]) << ((returnData[1] & 0xf8) >> 3); + return sprintf(retbuf, "%d\n", pout_max); + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +void ipmi_fan_control(uint8_t cmd_data1, uint8_t cmd_data2, uint8_t *retbuf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_TSOL, GET_FAN_INFO, cmd_data1, cmd_data2 }; /*netfn = IPMI_NETFN_TSOL; cmd = GET_FAN_INFO; */ + + mutex_lock(&ipmi_lock); + if (cmd_data1) + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), NULL, 0); + } + else + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + } + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + sprintf(retbuf, "N/A\n"); + } + else + { + sprintf(retbuf, "%s", returnData); + } +} + +static ssize_t show_label(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%s\n", + g_sensor_data[attr->index + DEBUGUSE_SHIFT].sensor_idstring); +} + +static ssize_t show_crit_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%d\n", attr->index); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int32_t rv = 0; + + uint8_t returnData[4] = ""; + uint8_t msg_data[] = { IPMI_NETFN_SE, GET_SENSOR_READING, 0x00 }; /*netfn = IPMI_NETFN_SE; cmd = GET_SENSOR_READING; */ + + mutex_lock(&ipmi_lock); + msg_data[2] = g_sensor_data[attr->index + DEBUGUSE_SHIFT].addr; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "0.0\n"); + } + else + { + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, returnData[0], buf); + } +} + +static ssize_t show_lnr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnr, buf); +} + +static ssize_t show_lcr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lcr, buf); +} + +static ssize_t show_lnc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnc, buf); +} + +static ssize_t show_unr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unr, buf); +} + +static ssize_t show_ucr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.ucr, buf); +} + +static ssize_t show_unc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unc, buf); +} + +static ssize_t show_model(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9a, buf); +} + +static ssize_t show_sn(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9e, buf); +} + +static ssize_t show_mfrid(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x99, buf); +} + +static ssize_t show_vin_type(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_vin_type(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pout_max(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_pout_max(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + uint8_t returnData[10] = { 0 }; + ipmi_fan_control(0x00, 0x00, returnData); + return sprintf(buf, "%d\n", returnData[0]); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + if (g_fan_control_mode == 1) + { + ipmi_fan_control(0x01, store_input, returnData); + } + + return count; +} + +static ssize_t show_controlmode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%d\n", g_fan_control_mode); +} + +static ssize_t store_controlmode(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + g_fan_control_mode = store_input; + if (g_fan_control_mode == 3) + { + ipmi_fan_control(0x7f, 0xff, returnData); + } + + return count; +} + +static ssize_t show_direction(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_STORAGE, GET_FRU_INFO, 0x00, 0x19, 0x00, 0x01 }; /*netfn = IPMI_NETFN_STORAGE; cmd = GET_FRU_INFO; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "N/A\n"); + } + else + { + return sprintf(buf, "%c\n", returnData[1]); + } +} + +static ssize_t show_fanpresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + int32_t fan_idx = 0, fan_present = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x02 }; /*netfn = 0x36; cmd = 0xB9; */ + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + fan_idx = (g_sensor_data[attr->index].sensor_idstring[8] - '0') - 1; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + fan_present = ((returnData[0] >> fan_idx) & 0x1) ? 0 : 1; + + return sprintf(buf, "%d\n", fan_present); +} + +static ssize_t show_psupresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t psu_idx = 0; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + psu_idx = g_sensor_data[attr->index].sensor_idstring[3] - '0'; + + return sprintf(buf, "%d\n", ipmi_check_psu_present(psu_idx)); +} + +static ssize_t(*const attr_show_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, char *buf) = +{ + show_label, show_crit_alarm, show_input + , show_lnc, show_lcr, show_lnr + , show_unc, show_ucr, show_unr + , show_model, show_sn, show_pwm + , show_controlmode, show_direction, show_fanpresent + , show_psupresent, show_mfrid, show_vin_type + , show_pout_max +}; + +static ssize_t(*const attr_store_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) = +{ + NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, store_pwm + , store_controlmode, NULL, NULL + , NULL, NULL, NULL + , NULL +}; + +static const char *const sensor_attrnames[SENSOR_ATTR_MAX] = +{ + "%s%d_label", "%s%d_crit_alarm", "%s%d_input" + , "%s%d_lncrit", "%s%d_lcrit", "%s%d_min" + , "%s%d_ncrit", "%s%d_crit", "%s%d_max" + , "%s%d_model", "%s%d_sn", "%s%d_pwm" + , "%s%d_controlmode", "%s%d_direction", "%s%d_present" + , "%s%d_present", "%s%d_mfrid", "%s%d_vin_type" + , "%s%d_pout_max" +}; + +static int32_t create_sensor_attrs(int32_t attr_no) +{ + int32_t i = 0, j = 0; + + struct attr_info *attrdata = &g_sensor_data[attr_no].attrinfo; + +#if enable_debug_msg + printk("##### %s:%d attr_no %d\n", __FUNCTION__, __LINE__, attr_no); +#endif + + for (i = 0; i < SENSOR_ATTR_MAX; i++) + { + if ((g_sensor_data[attr_no].capability >> i) & 0x01) + { + snprintf(attrdata->attr_name[j], SENSOR_ATTR_NAME_LENGTH, sensor_attrnames[i], + attrdata->attr_type_str, attr_no - DEBUGUSE_SHIFT); + + sysfs_attr_init(&attrdata->sd_attrs[j].dev_attr.attr); + attrdata->sd_attrs[j].dev_attr.attr.name = attrdata->attr_name[j]; + attrdata->sd_attrs[j].dev_attr.show = attr_show_func_ptr[i]; + attrdata->sd_attrs[j].dev_attr.store = attr_store_func_ptr[i]; + + attrdata->sd_attrs[j].dev_attr.attr.mode = S_IRUGO; + if (attrdata->sd_attrs[j].dev_attr.store) + { + attrdata->sd_attrs[j].dev_attr.attr.mode |= S_IWUSR; + } + + attrdata->sd_attrs[j].index = attr_no - DEBUGUSE_SHIFT; + attrdata->attrs[j] = &attrdata->sd_attrs[j].dev_attr.attr; + j++; + + data->total_create_sysfs++; + } + } + + attrdata->attrs[j] = NULL; + attrdata->attr_group.attrs = attrdata->attrs; + + g_sensor_data[attr_no].attrinfo.attr_exist = 1; + + return sysfs_create_group(&data->ipmi_hwmon_dev->kobj, &attrdata->attr_group); +} + +static int32_t remove_sensor_attrs(void) +{ + int32_t i = 0; + + for (i = 0; i < data->total_sensor_id; i++) + { + if (g_sensor_data[i].attrinfo.attr_exist) + { + sysfs_remove_group(&data->ipmi_hwmon_dev->kobj, + &g_sensor_data[i].attrinfo.attr_group); + } + } + return 0; +} + +int32_t ipmi_init_sdr_sensors_data(void) +{ + int32_t sdr_idx = 0; + int32_t err = 0; + + struct ipmi_sdr_iterator *itr = NULL; + struct sdr_get_rs *header = NULL; + + uint8_t *rec = NULL; + + mutex_lock(&ipmi_lock); + + itr = kzalloc(sizeof(struct ipmi_sdr_iterator), GFP_KERNEL); + if (itr == NULL) + { + printk("%s(%d): kzalloc failure.\n", __func__, __LINE__); + goto itr_malloc_fail; + } + + header = kzalloc(sizeof(struct sdr_get_rs), GFP_KERNEL); + if (header == NULL) + { + printk("%s(%d): malloc failure.\n", __func__, __LINE__); + goto header_malloc_fail; + } + + err = ipmi_sdr_start(itr); + if (err) + { + printk("%s(%d): ipmi_sdr_start fail.\n", __func__, __LINE__); + goto ipmi_sdr_start_fail; + } + + data->total_sensor_id = itr->total; + rec = kzalloc(GET_SDR_ENTIRE_RECORD, GFP_KERNEL); + if (rec == NULL) + { + printk("%s(%d): kzalloc failure\n", __func__, __LINE__); + goto rec_malloc_fail; + } + + g_sensor_data = kzalloc(itr->total * sizeof(struct ipmi_sensor_data), + GFP_KERNEL); + if (g_sensor_data == NULL) + { + printk("%s(%d): malloc failure", __func__, __LINE__); + goto g_sensor_data_malloc_fail; + } + + memset(g_sensor_data, 0x0, itr->total * sizeof(struct ipmi_sensor_data)); + + for (sdr_idx = 0; sdr_idx < itr->total; sdr_idx++) + { + err = ipmi_sdr_get_header(itr, header); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_header_fail; + } + + + memset(rec, 0, GET_SDR_ENTIRE_RECORD); + err = ipmi_sdr_get_record(header, itr, rec); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_record_fail; + } + + itr->next = header->next; + + switch (header->type) + { + case SDR_RECORD_TYPE_FULL_SENSOR: + /* prepare (threshold, factor)data whilie init, for reduce reading step and improve operate speed */ + g_sensor_data[sdr_idx].addr = rec[2]; + g_sensor_data[sdr_idx].capability = + SENSOR_GET_CAP_LABEL /*| SENSOR_GET_CAP_ALARM */ | SENSOR_GET_CAP_INPUT; + g_sensor_data[sdr_idx].headerinfo.header_type = header->type; + g_sensor_data[sdr_idx].headerinfo.header_byte = header->length; + + ipmi_sdr_set_sensor_threshold(sdr_idx, (struct sdr_record_full_sensor *) rec); + ipmi_sdr_set_sensor_factor(sdr_idx, (struct sdr_record_full_sensor *) rec); + + if (sdr_idx >= DEBUGUSE_SHIFT) + { + err = create_sensor_attrs(sdr_idx); + if (err) + { + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; + printk("[err : %d]sysfs_create_group fail in [%d] %s\n", err, sdr_idx, + g_sensor_data[sdr_idx].sensor_idstring); + goto create_sysfs_fail; + } + } + + data->total_suport_sensor++; + + break; + case SDR_RECORD_TYPE_COMPACT_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_EVENTONLY_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR: /* not supporrt now */ + default: + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; +#if enable_debug_msg + printk("ID[%d] : not support type [%d]\n", sdr_idx, header->type); +#endif + break; + } + } + + printk("quanta_hwmon_ipmi : detected [%d] sensor, create [%d] sysfs\n", + data->total_suport_sensor, data->total_create_sysfs); + +create_sysfs_fail: +ipmi_sdr_get_header_fail: +ipmi_sdr_get_record_fail: +g_sensor_data_malloc_fail: + if (header) + { + kfree(header); + header = NULL; + } + if (rec) + { + kfree(rec); + rec = NULL; + } + +rec_malloc_fail: +ipmi_sdr_start_fail: +header_malloc_fail: + if (itr) + { + kfree(itr); + itr = NULL; + } + +itr_malloc_fail: + mutex_unlock(&ipmi_lock); + + return err; +} + +static int32_t __init quanta_hwmon_ipmi_init(void) +{ + int32_t err = 0; + + init_completion(&g_read_complete); + + data = kzalloc(sizeof(struct quanta_hwmon_ipmi_data), GFP_KERNEL); + if (NULL == data) + { + printk("alloc data fail\n"); + goto alloc_err; + } + + data->ipmi_platform_dev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + err = IS_ERR(data->ipmi_platform_dev); + if (err) + { + printk("platform device register fail (err : %d)\n", err); + goto device_reg_err; + } + + data->ipmi_hwmon_dev = hwmon_device_register_with_groups(NULL, DRVNAME, NULL, + NULL); + err = IS_ERR(data->ipmi_hwmon_dev); + if (err) + { + printk("hwmon register fail\n"); + goto hwmon_register_err; + } + + err = ipmi_create_user(0, &ipmi_hndlrs, NULL, &ipmi_mh_user); + if (err) + { + printk("warning: create user fail, watchdog broken (err : %d)\n", err); + goto ipmi_create_err; + } + + mutex_init(&ipmi_lock); + err = ipmi_init_sdr_sensors_data(); + if (err) + { + printk("init sensor data fail (err : %d)\n", err); + goto init_sensor_err; + } + + return 0; + +init_sensor_err: + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } +ipmi_create_err: + hwmon_device_unregister(data->ipmi_hwmon_dev); +hwmon_register_err: + platform_device_unregister(data->ipmi_platform_dev); +device_reg_err: + if (data) + { + kfree(data); + data = NULL; + } +alloc_err: + return err; +} + +static void __exit quanta_hwmon_ipmi_exit(void) +{ + remove_sensor_attrs(); + hwmon_device_unregister(data->ipmi_hwmon_dev); + + mutex_lock(&ipmi_lock); + ipmi_destroy_user(ipmi_mh_user); + mutex_unlock(&ipmi_lock); + + platform_device_unregister(data->ipmi_platform_dev); + + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } + + if (data) + { + kfree(data); + data = NULL; + } +} + +module_init(quanta_hwmon_ipmi_init); +module_exit(quanta_hwmon_ipmi_exit); + +MODULE_AUTHOR("Charcar~~Charcar~Charlie li li"); +MODULE_VERSION("2.0"); +MODULE_DESCRIPTION("Quanta BMC hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/quanta_platform_ix7_bwde.c b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/quanta_platform_ix7_bwde.c new file mode 100644 index 0000000000..4658cee285 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/modules/quanta_platform_ix7_bwde.c @@ -0,0 +1,303 @@ +/* + * Quanta IX7-bwde platform driver + * + * + * Copyright (C) 2014 Quanta Computer inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)) +#include +#else +#include +#endif + +//MB Board Data +static struct pca953x_platform_data pca9555_1_data = { + .gpio_base = 0x10, +}; +//CPU Board pca9555 +static struct pca953x_platform_data pca9555_CPU_data = { + .gpio_base = 0x20, +}; + +static struct i2c_board_info ix7_bwde_i2c_devices[] = { + { + I2C_BOARD_INFO("pca9546", 0x72), // 0 + }, + { + I2C_BOARD_INFO("pca9548", 0x77), // 1 + }, + { + I2C_BOARD_INFO("24c02", 0x54), // 2 0x72 ch2 eeprom + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 3 0x77 ch0 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 4 0x77 ch1 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 5 0x77 ch2 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 6 0x77 ch3 + }, + { + I2C_BOARD_INFO("pca9555", 0x23), // 7 0x72 ch3 pca9555 MB Board Data + .platform_data = &pca9555_1_data, + }, + { + I2C_BOARD_INFO("CPLD-QSFP28", 0x38), // 8 0x72 ch0 + }, + { + I2C_BOARD_INFO("CPLD-QSFP28", 0x38), // 9 0x72 ch1 + }, + { + I2C_BOARD_INFO("pca9555", 0x22), // 10 0x71 ch0 CPU Board Data + .platform_data = &pca9555_CPU_data, + }, + { + I2C_BOARD_INFO("optoe1", 0x50), // 11 0x50 QSFP EEPROM + }, + { + I2C_BOARD_INFO("CPLDLED_IX7_BWDE", 0x39), // 12 0x72 ch0 CPLD_led_1 + }, + { + I2C_BOARD_INFO("CPLDLED_IX7_BWDE", 0x39), // 13 0x72 ch1 CPLD_led_1 + }, +}; + +static struct platform_driver ix7_bwde_platform_driver = { + .driver = { + .name = "qci-ix7-bwde", + .owner = THIS_MODULE, + }, +}; + +static struct platform_device *ix7_bwde_device; + +static struct i2c_client **g_client; +static struct i2c_client **g_client_port; +int numof_i2c_devices = 13; // num of ix7_bwde_i2c_devices - 1 (for optoe1) +int numof_ports = 32; + +static int __init ix7_bwde_platform_init(void) +{ + struct i2c_adapter *adapter; + int ret, i; + + ret = platform_driver_register(&ix7_bwde_platform_driver); + if (ret < 0) + return ret; + + /* Register platform stuff */ + ix7_bwde_device = platform_device_alloc("qci-ix7_bwde", -1); + if (!ix7_bwde_device) { + ret = -ENOMEM; + goto fail_platform_driver; + } + + ret = platform_device_add(ix7_bwde_device); + if (ret) + goto fail_platform_device; + + g_client = kmalloc(sizeof(*g_client) * numof_i2c_devices, GFP_KERNEL); + for (i = 0; i < numof_i2c_devices; i++) g_client[i] = NULL; + + g_client_port = kmalloc(sizeof(*g_client_port) * numof_ports, GFP_KERNEL); + for (i = 0; i < numof_ports; i++) g_client_port[i] = NULL; + + adapter = i2c_get_adapter(0); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[0] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[0]); // pca9546 + g_client[1] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[1]); // pca9548 + g_client[2] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[10]); // CPU Board Data + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x01); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[3] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[8]); // CPLD2 + g_client[4] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[12]); // CPLD_led_1 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x02); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[5] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[9]); // CPLD3 + g_client[6] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[13]); // CPLD_led_2 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x03); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[7] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[2]); // MB_BOARDINFO_EEPROM + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x04); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[8] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[7]); // pca9555 MB Board Data + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x05); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[9] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[3]); // pca9548_1 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x06); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[10] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[4]); // pca9548_2 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x07); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[11] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[5]); // pca9548_3 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x08); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[12] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[6]); // pca9548_4 SFP + i2c_put_adapter(adapter); + } + + for(i = 13; i < 45; i ++){ // QSFP 1~32 EEPROM + adapter = i2c_get_adapter(i); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client_port[i - 13] = i2c_new_device(adapter, &ix7_bwde_i2c_devices[11]); + i2c_put_adapter(adapter); + } + } + + return 0; + +fail_platform_device: + platform_device_put(ix7_bwde_device); + +fail_platform_driver: + platform_driver_unregister(&ix7_bwde_platform_driver); + return ret; +} + +static void __exit ix7_bwde_platform_exit(void) +{ + int i = 0; + + for (i = numof_ports - 1; i >= 0; i--) + { + if (g_client_port[i]) + { + i2c_unregister_device(g_client_port[i]); + g_client_port[i] = NULL; + } + } + + for (i = numof_i2c_devices - 1; i >= 0; i--) + { + if (g_client[i]) + { + i2c_unregister_device(g_client[i]); + g_client[i] = NULL; + } + } + + platform_device_unregister(ix7_bwde_device); + platform_driver_unregister(&ix7_bwde_platform_driver); +} + +module_init(ix7_bwde_platform_init); +module_exit(ix7_bwde_platform_exit); + + +MODULE_AUTHOR("Robert Hong "); +MODULE_VERSION("1.0"); +MODULE_DESCRIPTION("Quanta IX7-bwde Platform Driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/service/ix7-bwde-platform-init.service b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/service/ix7-bwde-platform-init.service new file mode 100644 index 0000000000..e1067d45c5 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/service/ix7-bwde-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Quanta IX7-BWDE-32X Platform initialization service +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/quanta_ix7_bwde_util.py install +ExecStop=/usr/local/bin/quanta_ix7_bwde_util.py clean +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/setup.py new file mode 100644 index 0000000000..fa6203d436 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='ix7_bwde_32x', + version='1.0', + description='Module to initialize Quanta IX7-BWDE-32X platforms', + + packages=['ix7_bwde_32x'], + package_dir={'ix7_bwde_32x': 'ix7-bwde-32x/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/__init__.py new file mode 100644 index 0000000000..4bfefa0fb6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/chassis.py new file mode 100644 index 0000000000..92a8c433ce --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/chassis.py @@ -0,0 +1,210 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import sys + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 32 + self.__num_of_sfps = 0 + self.__num_of_fan_drawers = 6 + self.__fan_per_drawer = 2 + self.__num_of_thermals = 18 + self.__xcvr_presence = {} + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + fan_index = 1 + for drawer_index in range(1, self.__num_of_fan_drawers + 1): + drawer_fan_list = [] + for index in range(0, self.__fan_per_drawer): + fan = Fan(fan_index, False) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(1, self.__num_of_ports + 1): + if index in range(1, self.__num_of_sfps + 1): + sfp = Sfp(index, 'SFP') + else: + sfp = Sfp(index, 'QSFP') + + self._sfp_list.append(sfp) + + for index in range(1, self.__num_of_ports + 1): + self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() + +############################################## +# Device methods +############################################## + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + For Quanta the index in sfputil.py starts from 1, so override + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + if (index == 0): + raise IndexError + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("override: SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_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 + +############################################## +# Chassis methods +############################################## + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + return self._eeprom.system_eeprom_info() + + def get_change_event(self, timeout=0): + """ + Currently only support transceiver change events + """ + + start_ms = time.time() * 1000 + xcvr_change_event_dict = {} + event = False + + while True: + time.sleep(0.5) + for index in range(1, self.__num_of_ports + 1): + cur_xcvr_presence = self._sfp_list[index-1].get_presence() + if cur_xcvr_presence != self.__xcvr_presence[index]: + if cur_xcvr_presence is True: + xcvr_change_event_dict[str(index)] = '1' + self.__xcvr_presence[index] = True + elif cur_xcvr_presence is False: + xcvr_change_event_dict[str(index)] = '0' + self.__xcvr_presence[index] = False + event = True + + if event is True: + return True, {'sfp':xcvr_change_event_dict} + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, {'sfp':xcvr_change_event_dict} + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/eeprom.py new file mode 100644 index 0000000000..d154a8a0c4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/eeprom.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.__eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + 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] + + if tlv[0] == self._TLV_CODE_VENDOR_EXT: + value = str((tlv[2] << 24) | (tlv[3] << 16) | + (tlv[4] << 8) | tlv[5]) + value += tlv[6:6 + tlv[1]].decode('ascii') + else: + value = self.decoder(None, tlv)[30:] + + 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): + (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): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in results[2]]).upper() + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/fan.py new file mode 100644 index 0000000000..5567eaff93 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/fan.py @@ -0,0 +1,220 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta IX7 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import logging + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +HWMON_DIR = "/sys/class/hwmon/hwmon2/" +FAN_INDEX_START = 18 +NUM_FANTRAYS = 6 +FANS_PERTRAY = 2 + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + self.fan_index = index + self.psu_fan_index_mapping = { + 1:37, + 2:47, + } + self.psu_index_mapping = { + 1:39, + 2:49, + } + if self.is_psu_fan: + self.fan_presence_attr = "power{}_present".format(self.psu_index_mapping[index]) + self.fan_pwm_attr = "fan{}_pwm".format(self.psu_fan_index_mapping[index]) + self.fan_rpm_attr = "fan{}_input".format(self.psu_fan_index_mapping[index]) + self.fan_direction_attr = "fan{}_direction".format(self.psu_fan_index_mapping[index]) + else: + self.fan_presence_attr = "fan{}_present".format(FAN_INDEX_START+(index-1)) + self.fan_pwm_attr = "fan{}_pwm".format(FAN_INDEX_START+(index-1)) + self.fan_rpm_attr = "fan{}_input".format(FAN_INDEX_START+(index-1)) + self.fan_direction_attr = "fan{}_direction".format(FAN_INDEX_START+(index-1)) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + 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.fan_index) + else: + fantray_index = (self.fan_index-1)//FANS_PERTRAY+1 + fan_index_intray = self.fan_index - ((fantray_index-1)*FANS_PERTRAY) + return "Fantray{}_{}".format(fantray_index, fan_index_intray) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.fan_presence_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == '1'): + return True + else: + return False + + return None + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR' and attr_rv != '0.0'): + return True + else: + return False + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + attr_path = HWMON_DIR + self.fan_direction_attr + attr_rv = self.__get_attr_value(attr_path) + + if attr_rv == '2': + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 25 + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + + Args: + color: A string representing the color with which to set the + fan module status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return True + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..75e954576a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/fan_drawer.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/platform.py new file mode 100644 index 0000000000..c4f945277f --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +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): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/psu.py new file mode 100644 index 0000000000..3fcb9e979a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/psu.py @@ -0,0 +1,320 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import logging + 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") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + + +class Psu(PsuBase): + def __init__(self, index): + PsuBase.__init__(self) + fan = Fan(index, True) + self._fan_list.append(fan) + + self.psu_index_mapping = { + 1:39, + 2:49, + } + self.psu_powerin_index_mapping = { + 1:38, + 2:48, + } + self.psu_currentout_index_mapping = { + 1:36, + 2:46, + } + self.psu_currentin_index_mapping = { + 1:35, + 2:45, + } + self.psu_voltageout_index_mapping = { + 1:44, + 2:54, + } + self.psu_voltagein_index_mapping = { + 1:43, + 2:53, + } + self.index = index + self.psu_presence_attr = "power{}_present".format(self.psu_index_mapping[self.index]) + self.psu_status_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_power_in_attr = "power{}_input".format(self.psu_powerin_index_mapping[self.index]) + self.psu_power_out_attr = "power{}_input".format(self.psu_index_mapping[self.index]) + self.psu_voltage_out_attr = "in{}_input".format(self.psu_voltageout_index_mapping[self.index]) + self.psu_current_out_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_voltage_in_attr = "in{}_input".format(self.psu_voltagein_index_mapping[self.index]) + self.psu_current_in_attr = "curr{}_input".format(self.psu_currentin_index_mapping[self.index]) + self.psu_serial_attr = "power{}_sn".format(self.psu_index_mapping[self.index]) + self.psu_model_attr = "power{}_model".format(self.psu_index_mapping[self.index]) + self.psu_mfr_id_attr = "power{}_mfrid".format(self.psu_index_mapping[self.index]) + self.psu_capacity_attr = "power{}_pout_max".format(self.psu_index_mapping[self.index]) + self.psu_type_attr = "power{}_vin_type".format(self.psu_index_mapping[self.index]) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + fd.close() + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = HWMON_DIR+self.psu_presence_attr + attr_normal = '1' + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = HWMON_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_mfr_id(self): + """ + Retrieves the manufacturer's name (or id) of the device + + Returns: + string: Manufacturer's id of device + """ + mfr_id = "N/A" + attr_path = HWMON_DIR+self.psu_mfr_id_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + mfr_id = attr_rv + + return mfr_id + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = HWMON_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = HWMON_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = HWMON_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_out = float(attr_rv) / 1000 + + return current_out + + def get_input_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_in = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_in = float(attr_rv) / 1000 + + return voltage_in + + def get_input_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_in = 0.0 + attr_path = HWMON_DIR+self.psu_current_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_in = float(attr_rv) / 1000 + + return current_in + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = HWMON_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + power_out = float(attr_rv) / 1000 + + return power_out + + 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. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + type = "AC" + attr_path = HWMON_DIR+self.psu_type_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + type = attr_rv + + return type + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + capacity = 0 + attr_path = HWMON_DIR+self.psu_capacity_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + try: + capacity = int(attr_rv) + except ValueError: + capacity = 0 + + return capacity + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/sfp.py new file mode 100644 index 0000000000..d06ae5cabe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/sfp.py @@ -0,0 +1,1596 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +#import subprocess +#import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase +# from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_MODULE_THRESHOLD_OFFSET = 512 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 560 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +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_TYPE = "SFP" +QSFP_TYPE = "QSFP" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 32 + QSFP_START = 1 + QSFP_END = 32 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-quanta_ix7_bwde-r0" + HWSKU = "Quanta-IX7-BWDE-32X" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + #self.dom_supported = False + self.sfp_type = sfp_type + self.lpmode_path = "/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/lpmode" + self.reset_path = "/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/reset" + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44 + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self.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', 'vendor_date', + 'application_advertisement', 'vendor_oui'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', + 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the SFP module + Returns: + bool: True if SFP module is present, False if not + """ + # Check for invalid port_num + if self.port_num < self.PORT_START or self.port_num > self.PORT_END: + return False + + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/module_present") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + reg_file.close() + if reg_value == '1': + return True + + return False + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + eeprom_raw = None + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability = int(qsfp_dom_capability_raw[0], 16) + + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + if qsfp_version_compliance_raw is not None: + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qsfp_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qsfp_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qsfp_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + self.dom_tx_disable_supported = True + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ======================================================================== + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + if not self.get_presence(): + return transceiver_info_dict + + if self.sfp_type == QSFP_TYPE: + offset = QSFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == SFP_TYPE: + offset = SFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + else: + return transceiver_info_dict + + # Add retry for xcvr eeprom to get ready + max_retry = 10 + for i in range(0,max_retry): + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is not None: + break + else: + if not self.get_presence(): + return transceiver_info_dict + elif i == max_retry-1: + pass + else: + time.sleep(0.5) + + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + transceiver_info_dict['type'] = sfp_interface_bulk_data \ + ['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data \ + ['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data \ + ['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data \ + ['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data \ + ['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data \ + ['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data \ + ['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data \ + ['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data \ + ['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data \ + ['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data \ + ['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = 'N/A' + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = QSFP_DOM_OFFSET + offset_xcvr = QSFP_INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability_data = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qsfp_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + if not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + else: + return None + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + if not self.get_presence() or not sfpd_obj: + return {} + DOM_OFFSET = 0 + transceiver_dom_threshold_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + offset = DOM_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + module_threshold_values = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_channel_thres_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNEL_THRESHOLD_OFFSET), QSFP_CHANNEL_THRESHOLD_WIDTH) + if dom_channel_thres_raw is not None: + channel_threshold_values = sfpd_obj.parse_channel_threshold_values(dom_channel_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + else: + channel_threshold_data = None + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + DOM_OFFSET = 256 + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + else: + return None + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.reset_path) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return True + else: + return False + else: + return None + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + else: + return None + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + else: + return None + + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + else: + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return 0 + elif self.sfp_type == QSFP_TYPE: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + else: + return None + + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this QSFP module + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.lpmode_path) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return False + else: + return True + else: + return None + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_POWEROVERRIDE_OFFSET), QSFP_POWEROVERRIDE_WIDTH) + if dom_control_raw is not None: + if int(dom_control_raw[0],16) & (0x01 << QSFP_POWEROVERRIDE_BIT): + return True + else: + return False + else: + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( \ + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default state. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.reset_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open("/sys/class/cpld-qsfp28/port-"+str(self.port_num)+"/reset", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + offset = 256 + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( + status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(offset + SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + else: + return None + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + else: + return False + else: + return None + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open(self.lpmode_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + else: + return None + + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings(self.__get_path_to_port_config_file()) + print("self.index{}".format(self.index)) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/thermal.py new file mode 100644 index 0000000000..a80a07a999 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform/thermal.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import logging +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +thermal_index_mapping = { + 1:40, + 2:41, + 3:42, + 4:50, + 5:51, + 6:52, + 7:73, + 8:74, + 9:75, + 10:76, + 11:77, + 12:78, + 13:79, + 14:80, + 15:81, + 16:82, + 17:83, + 18:84 +} + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index + self.temp_attr = "temp{}_input".format(thermal_index_mapping[self.index]) + self.high_th_attr = "temp{}_ncrit".format(thermal_index_mapping[self.index]) + self.high_crit_th_attr = "temp{}_crit".format(thermal_index_mapping[self.index]) + self.name_attr = "temp{}_label".format(thermal_index_mapping[self.index]) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return attr_rv + else: + return None + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if (self.get_temperature() != None): + return True + else: + return False + + 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 + """ + attr_path = HWMON_DIR + self.temp_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + 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 + """ + attr_path = HWMON_DIR + self.high_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + def get_high_critical_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 + """ + attr_path = HWMON_DIR + self.high_crit_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform_setup.py new file mode 100644 index 0000000000..a4899c6183 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/sonic_platform_setup.py @@ -0,0 +1,24 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Quanta Platforms', + license='Apache 2.0', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/utils/quanta_ix7_bwde_util.py b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/utils/quanta_ix7_bwde_util.py new file mode 100755 index 0000000000..952fc11a68 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix7-bwde-32x/utils/quanta_ix7_bwde_util.py @@ -0,0 +1,241 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Quanta Computer Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes +""" + +import os +import commands +import sys, getopt +import logging + +DEBUG = False +args = [] +FORCE = 0 +i2c_prefix = '/sys/bus/i2c/devices/' + + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv)<2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + install() + elif arg == 'clean': + uninstall() + else: + show_help() + + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_log(txt): + if DEBUG == True: + print "[IX7-BWDE-32X]"+txt + return + +def exec_cmd(cmd, show): + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) + show_log (cmd +"with result:" + str(status)) + show_log (" output:"+output) + if status: + logging.info('Failed :'+cmd) + if show: + print('Failed :'+cmd) + return status, output + +instantiate =[ +#Enable front-ports LED decoding +'echo 1 > /sys/class/cpld-led/CPLDLED-1/led_decode', +'echo 1 > /sys/class/cpld-led/CPLDLED-2/led_decode', +#Update System LED +'echo 39 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio39/direction', +'echo 0 > /sys/class/gpio/gpio39/value', +'echo 40 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio40/direction', +'echo 1 > /sys/class/gpio/gpio40/value', +] + +drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', +'i2c-mux-pca954x force_deselect_on_exit=1', +'gpio-pca953x', +'optoe', +'qci_cpld', +'qci_cpld_led', +'quanta_platform_ix7_bwde', +'ipmi_devintf', +'quanta_hwmon_ipmi' +] + +un_drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', +'i2c-mux-pca954x', +'gpio-pca953x', +'optoe', +'qci_cpld', +'qci_cpld_led', +'quanta_platform_ix7_bwde', +'ipmi_devintf', +'quanta_hwmon_ipmi' +] + +def system_install(): + global FORCE + + #setup driver dependency + exec_cmd("depmod -a ", 1) + #install drivers + for i in range(0,len(drivers)): + status, output = exec_cmd("modprobe "+drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + + #reload ethernet drivers for correct order + exec_cmd("rmmod ixgbe ", 1) + exec_cmd("rmmod igb ", 1) + exec_cmd("modprobe igb ", 1) + exec_cmd("modprobe ixgbe ", 1) + + #turn on module power + exec_cmd("echo 21 > /sys/class/gpio/export ", 1) + exec_cmd("echo high > /sys/class/gpio/gpio21/direction ", 1) + + #Reset fron-ports LED CPLD + exec_cmd("echo 33 > /sys/class/gpio/export ", 1) + status, output = exec_cmd("cat /sys/class/gpio/gpio33/value", 1) + if output != '1': + exec_cmd("echo out > /sys/class/gpio/gpio33/direction ", 1) + exec_cmd("echo 0 >/sys/class/gpio/gpio33/value", 1) + exec_cmd("echo 1 >/sys/class/gpio/gpio33/value", 1) + + #instantiate devices + for i in range(0,len(instantiate)): + status, output = exec_cmd(instantiate[i], 1) + if status: + print output + if FORCE == 0: + return status + + #QSFP for 1~32 port + for port_number in range(1,33): + bus_number = port_number + 12 + os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) + + status, output = exec_cmd("pip3 install /usr/share/sonic/device/x86_64-quanta_ix7_bwde-r0/sonic_platform-1.0-py3-none-any.whl",1) + if status: + print output + if FORCE == 0: + return status + + return + + +def system_ready(): + if not device_found(): + return False + return True + +def install(): + if not device_found(): + print "No device, installing...." + status = system_install() + if status: + if FORCE == 0: + return status + else: + print " ix7-bwde driver already installed...." + return + +def uninstall(): + global FORCE + #uninstall drivers + for i in range(len(un_drivers)-1,-1,-1): + status, output = exec_cmd("rmmod "+un_drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + status, output = exec_cmd("pip3 uninstall sonic-platform -y ",1) + if status: + print output + if FORCE == 0: + return status + return + +def device_found(): + ret1, log1 = exec_cmd("cat /proc/modules | grep ix7_bwde > /tmp/chkdriver.log", 0) + ret2, log2 = exec_cmd("cat /tmp/chkdriver.log | grep ix7_bwde", 0) + + if ret1 == 0 and len(log2) > 0: + return True + else: + return False + +if __name__ == "__main__": + main() + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/classes/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/classes/__init__.py old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/Makefile b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/Makefile old mode 100755 new mode 100644 index 011cd52d67..8ea865a8b5 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/Makefile @@ -1,3 +1,3 @@ -obj-m:=qci_cpld_sfp28.o qci_cpld_led.o qci_platform_ix8.o +obj-m:=qci_cpld_sfp28.o qci_cpld_led.o qci_platform_ix8.o quanta_hwmon_ipmi.o diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_led.c b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_led.c old mode 100755 new mode 100644 index 37fc2e0724..64841e8538 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_led.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_led.c @@ -241,6 +241,7 @@ err_out: return nr; } +#if 0 /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ static int idr_has_entry(int id, void *p, void *data) { @@ -251,6 +252,7 @@ static bool cpld_idr_is_empty(struct idr *idp) { return !idr_for_each(idp, idr_has_entry, NULL); } +#endif static int cpld_led_remove(struct i2c_client *client) { @@ -261,8 +263,11 @@ static int cpld_led_remove(struct i2c_client *client) ida_simple_remove(&cpld_led_ida, data->cpld_data->cpld_id); kfree(data->cpld_data); - if (cpld_idr_is_empty(&cpld_led_ida.idr)) + if (ida_is_empty(&cpld_led_ida)) + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_sfp28.c b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_sfp28.c old mode 100755 new mode 100644 index dac76667c6..61350cdd8c --- a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_sfp28.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_cpld_sfp28.c @@ -298,7 +298,7 @@ static int cpld_probe(struct i2c_client *client, if (!cpld_class) { - cpld_class = class_create(THIS_MODULE, name); + cpld_class = class_create(THIS_MODULE, "cpld-sfp28"); if (IS_ERR(cpld_class)) { pr_err("couldn't create sysfs class\n"); return PTR_ERR(cpld_class); @@ -358,7 +358,7 @@ err_out: } /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ -#if 1 +#if 0 static int idr_has_entry(int id, void *p, void *data) { return 1; @@ -384,8 +384,11 @@ static int cpld_remove(struct i2c_client *client) kfree(data->port_data[i]); } - if (cpld_idr_is_empty(&cpld_ida.idr)) + if (ida_is_empty(&cpld_ida)) + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_platform_ix8.c b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_platform_ix8.c old mode 100755 new mode 100644 index d35a56641e..51876246e1 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_platform_ix8.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/qci_platform_ix8.c @@ -39,170 +39,13 @@ #include #include #include -#include +#include #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)) #include #else #include #endif -#define MUX_INFO(bus, deselect) \ - {.adap_id = bus, .deselect_on_exit = deselect} - -static struct pca954x_platform_mode pca9548sfp1_modes[] = { - MUX_INFO(0x20, 1), - MUX_INFO(0x21, 1), - MUX_INFO(0x22, 1), - MUX_INFO(0x23, 1), - MUX_INFO(0x24, 1), - MUX_INFO(0x25, 1), - MUX_INFO(0x26, 1), - MUX_INFO(0x27, 1), -}; - -static struct pca954x_platform_data pca9548sfp1_data = { - .modes = pca9548sfp1_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp2_modes[] = { - MUX_INFO(0x28, 1), - MUX_INFO(0x29, 1), - MUX_INFO(0x2a, 1), - MUX_INFO(0x2b, 1), - MUX_INFO(0x2c, 1), - MUX_INFO(0x2d, 1), - MUX_INFO(0x2e, 1), - MUX_INFO(0x2f, 1), -}; - -static struct pca954x_platform_data pca9548sfp2_data = { - .modes = pca9548sfp2_modes, - .num_modes = 8, -}; -static struct pca954x_platform_mode pca9548sfp3_modes[] = { - MUX_INFO(0x30, 1), - MUX_INFO(0x31, 1), - MUX_INFO(0x32, 1), - MUX_INFO(0x33, 1), - MUX_INFO(0x34, 1), - MUX_INFO(0x35, 1), - MUX_INFO(0x36, 1), - MUX_INFO(0x37, 1), -}; - -static struct pca954x_platform_data pca9548sfp3_data = { - .modes = pca9548sfp3_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp4_modes[] = { - MUX_INFO(0x38, 1), - MUX_INFO(0x39, 1), - MUX_INFO(0x3a, 1), - MUX_INFO(0x3b, 1), - MUX_INFO(0x3c, 1), - MUX_INFO(0x3d, 1), - MUX_INFO(0x3e, 1), - MUX_INFO(0x3f, 1), -}; - -static struct pca954x_platform_data pca9548sfp4_data = { - .modes = pca9548sfp4_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp5_modes[] = { - MUX_INFO(0x40, 1), - MUX_INFO(0x41, 1), - MUX_INFO(0x42, 1), - MUX_INFO(0x43, 1), - MUX_INFO(0x44, 1), - MUX_INFO(0x45, 1), - MUX_INFO(0x46, 1), - MUX_INFO(0x47, 1), -}; - -static struct pca954x_platform_data pca9548sfp5_data = { - .modes = pca9548sfp5_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp6_modes[] = { - MUX_INFO(0x48, 1), - MUX_INFO(0x49, 1), - MUX_INFO(0x4a, 1), - MUX_INFO(0x4b, 1), - MUX_INFO(0x4c, 1), - MUX_INFO(0x4d, 1), - MUX_INFO(0x4e, 1), - MUX_INFO(0x4f, 1), -}; - -static struct pca954x_platform_data pca9548sfp6_data = { - .modes = pca9548sfp6_modes, - .num_modes = 8, -}; - -//ZQSFP -static struct pca954x_platform_mode pca9548sfp7_modes[] = { - MUX_INFO(0x50, 1), - MUX_INFO(0x51, 1), - MUX_INFO(0x52, 1), - MUX_INFO(0x53, 1), - MUX_INFO(0x54, 1), - MUX_INFO(0x55, 1), - MUX_INFO(0x56, 1), - MUX_INFO(0x57, 1), -}; - -static struct pca954x_platform_data pca9548sfp7_data = { - .modes = pca9548sfp7_modes, - .num_modes = 8, -}; - -// end port - -static struct pca954x_platform_mode pca9546_modes[] = { - MUX_INFO(0x10, 1), - MUX_INFO(0x11, 1), - MUX_INFO(0x12, 1), - MUX_INFO(0x13, 1), -}; - -static struct pca954x_platform_data pca9546_data = { - .modes = pca9546_modes, - .num_modes = 4, -}; - -static struct pca954x_platform_mode pca9548_modes[] = { - MUX_INFO(0x14, 1), - MUX_INFO(0x15, 1), - MUX_INFO(0x16, 1), - MUX_INFO(0x17, 1), - MUX_INFO(0x18, 1), - MUX_INFO(0x19, 1), - MUX_INFO(0x1a, 1), - MUX_INFO(0x1b, 1), -}; - -static struct pca954x_platform_data pca9548_data = { - .modes = pca9548_modes, - .num_modes = 8, -}; - -/* CPU Board i2c device */ -static struct pca954x_platform_mode pca9546_cpu_modes[] = { - MUX_INFO(0x02, 1), - MUX_INFO(0x03, 1), - MUX_INFO(0x04, 1), - MUX_INFO(0x05, 1), -}; - -static struct pca954x_platform_data pca9546_cpu_data = { - .modes = pca9546_cpu_modes, - .num_modes = 4, -}; //MB Board Data static struct pca953x_platform_data pca9555_1_data = { .gpio_base = 0x10, @@ -218,42 +61,33 @@ static struct pca953x_platform_data pca9555_CPU_data = { static struct i2c_board_info ix8_i2c_devices[] = { { I2C_BOARD_INFO("pca9546", 0x72), // 0 - .platform_data = &pca9546_data, }, { I2C_BOARD_INFO("pca9548", 0x77), // 1 - .platform_data = &pca9548_data, }, { I2C_BOARD_INFO("24c02", 0x54), // 2 eeprom }, { I2C_BOARD_INFO("pca9548", 0x73), // 3 0x77 ch0 - .platform_data = &pca9548sfp1_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 4 0x77 ch1 - .platform_data = &pca9548sfp2_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 5 0x77 ch2 - .platform_data = &pca9548sfp3_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 6 0x77 ch3 - .platform_data = &pca9548sfp4_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 7 0x77 ch4 - .platform_data = &pca9548sfp5_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 8 0x77 ch5 - .platform_data = &pca9548sfp6_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 9 0x77 ch6 - .platform_data = &pca9548sfp7_data, }, { I2C_BOARD_INFO("CPLD-SFP28", 0x38), // 10 0x72 ch0 CPLD1_:SFP28 1~16 @@ -277,7 +111,6 @@ static struct i2c_board_info ix8_i2c_devices[] = { }, { I2C_BOARD_INFO("pca9546", 0x71), // 16 - .platform_data = &pca9546_cpu_data, }, { I2C_BOARD_INFO("pca9555", 0x20), // 17 0x71 ch0 CPU Board Data @@ -301,11 +134,33 @@ static struct platform_driver ix8_platform_driver = { }, }; +static struct i2c_adapter *i2c_get_adapter_wait(int nr) +{ + struct i2c_adapter *adap = NULL; + int i = 0; + + for (i = 0; i < 300; ++i) { + adap = i2c_get_adapter(nr); + if (adap) + break; + msleep(10); + } + + if (adap == NULL) + printk(KERN_ERR "%s: unable to get i2c adapter for bus %d\n", __FILE__, nr); + + return adap; +} + static struct platform_device *ix8_device; +static struct i2c_client **g_client; +static struct i2c_client **g_client_port; +int numof_i2c_devices = 19; // num of ix8_i2c_devices - 2 (for optoe1, optoe2) +int numof_ports = 56; + static int __init ix8_platform_init(void) { - struct i2c_client *client; struct i2c_adapter *adapter; int ret, i; @@ -324,76 +179,187 @@ static int __init ix8_platform_init(void) if (ret) goto fail_platform_device; - adapter = i2c_get_adapter(0); - client = i2c_new_device(adapter, &ix8_i2c_devices[0]); // pca9546 - client = i2c_new_device(adapter, &ix8_i2c_devices[1]); // pca9548 - client = i2c_new_device(adapter, &ix8_i2c_devices[16]); // pca9546cpu - i2c_put_adapter(adapter); + g_client = kmalloc(sizeof(*g_client) * numof_i2c_devices, GFP_KERNEL); + for (i = 0; i < numof_i2c_devices; i++) g_client[i] = NULL; - adapter = i2c_get_adapter(0x02); - client = i2c_new_device(adapter, &ix8_i2c_devices[17]); // CPU Board Data - i2c_put_adapter(adapter); + g_client_port = kmalloc(sizeof(*g_client_port) * numof_ports, GFP_KERNEL); + for (i = 0; i < numof_ports; i++) g_client_port[i] = NULL; - adapter = i2c_get_adapter(0x10); - client = i2c_new_device(adapter, &ix8_i2c_devices[10]); // CPLD_1 - client = i2c_new_device(adapter, &ix8_i2c_devices[18]); // CPLD_4 - client = i2c_new_device(adapter, &ix8_i2c_devices[19]); // CPLD_6 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x11); - client = i2c_new_device(adapter, &ix8_i2c_devices[11]); // CPLD_2 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x12); - client = i2c_new_device(adapter, &ix8_i2c_devices[12]); // CPLD_3 - client = i2c_new_device(adapter, &ix8_i2c_devices[2]); // MB_BOARDINFO_EEPROM - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x13); - client = i2c_new_device(adapter, &ix8_i2c_devices[13]); // MB Board Data - client = i2c_new_device(adapter, &ix8_i2c_devices[14]); // QSFP:49~52 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x14); - client = i2c_new_device(adapter, &ix8_i2c_devices[3]); // pca9548_1 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x15); - client = i2c_new_device(adapter, &ix8_i2c_devices[4]); // pca9548_2 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x16); - client = i2c_new_device(adapter, &ix8_i2c_devices[5]); // pca9548_3 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x17); - client = i2c_new_device(adapter, &ix8_i2c_devices[6]); // pca9548_4 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x18); - client = i2c_new_device(adapter, &ix8_i2c_devices[7]); // pca9548_5 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x19); - client = i2c_new_device(adapter, &ix8_i2c_devices[8]); // pca9548_6 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x1a); - client = i2c_new_device(adapter, &ix8_i2c_devices[9]); // pca9548_7 QSFP - i2c_put_adapter(adapter); - - for(i = 80; i < 88; i ++){ // QSFP 49~56 EEPROM - adapter = i2c_get_adapter(i); - client = i2c_new_device(adapter, &ix8_i2c_devices[15]); + adapter = i2c_get_adapter_wait(0); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[0] = i2c_new_device(adapter, &ix8_i2c_devices[0]); // pca9546 + g_client[1] = i2c_new_device(adapter, &ix8_i2c_devices[1]); // pca9548 + g_client[2] = i2c_new_device(adapter, &ix8_i2c_devices[16]); // pca9546cpu i2c_put_adapter(adapter); } - for(i = 32; i < 80; i ++){ // SFP28 1~48 EEPROM - adapter = i2c_get_adapter(i); - client = i2c_new_device(adapter, &ix8_i2c_devices[20]); + adapter = i2c_get_adapter_wait(13); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[3] = i2c_new_device(adapter, &ix8_i2c_devices[17]); // CPU Board Data i2c_put_adapter(adapter); } + adapter = i2c_get_adapter_wait(1); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[4] = i2c_new_device(adapter, &ix8_i2c_devices[10]); // CPLD_1 + g_client[5] = i2c_new_device(adapter, &ix8_i2c_devices[18]); // CPLD_4 + g_client[6] = i2c_new_device(adapter, &ix8_i2c_devices[19]); // CPLD_6 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(2); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[7] = i2c_new_device(adapter, &ix8_i2c_devices[11]); // CPLD_2 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(3); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[8] = i2c_new_device(adapter, &ix8_i2c_devices[12]); // CPLD_3 + g_client[9] = i2c_new_device(adapter, &ix8_i2c_devices[2]); // MB_BOARDINFO_EEPROM + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(4); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[10] = i2c_new_device(adapter, &ix8_i2c_devices[13]); // MB Board Data + g_client[11] = i2c_new_device(adapter, &ix8_i2c_devices[14]); // QSFP:49~52 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(5); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[12] = i2c_new_device(adapter, &ix8_i2c_devices[3]); // pca9548_1 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(6); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[13] = i2c_new_device(adapter, &ix8_i2c_devices[4]); // pca9548_2 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(7); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[14] = i2c_new_device(adapter, &ix8_i2c_devices[5]); // pca9548_3 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(8); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[15] = i2c_new_device(adapter, &ix8_i2c_devices[6]); // pca9548_4 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(9); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[16] = i2c_new_device(adapter, &ix8_i2c_devices[7]); // pca9548_5 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(10); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[17] = i2c_new_device(adapter, &ix8_i2c_devices[8]); // pca9548_6 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter_wait(11); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[18] = i2c_new_device(adapter, &ix8_i2c_devices[9]); // pca9548_7 QSFP + i2c_put_adapter(adapter); + } + + for(i = 65; i < 73; i ++){ // QSFP 49~56 EEPROM + adapter = i2c_get_adapter_wait(i); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client_port[i - 17] = i2c_new_device(adapter, &ix8_i2c_devices[15]); + i2c_put_adapter(adapter); + } + } + + for(i = 17; i < 65; i ++){ // SFP28 1~48 EEPROM + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + adapter = i2c_get_adapter_wait(i); + g_client_port[i - 17] = i2c_new_device(adapter, &ix8_i2c_devices[20]); + i2c_put_adapter(adapter); + } + } + return 0; fail_platform_device: @@ -406,6 +372,26 @@ fail_platform_driver: static void __exit ix8_platform_exit(void) { + int i = 0; + + for (i = numof_ports - 1; i >= 0; i--) + { + if (g_client_port[i]) + { + i2c_unregister_device(g_client_port[i]); + g_client_port[i] = NULL; + } + } + + for (i = numof_i2c_devices - 1; i >= 0; i--) + { + if (g_client[i]) + { + i2c_unregister_device(g_client[i]); + g_client[i] = NULL; + } + } + platform_device_unregister(ix8_device); platform_driver_unregister(&ix8_platform_driver); } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/quanta_hwmon_ipmi.c b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/quanta_hwmon_ipmi.c new file mode 100644 index 0000000000..5c9570c103 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/modules/quanta_hwmon_ipmi.c @@ -0,0 +1,1909 @@ +/* +* +* A hwmon driver for the Quanta switch BMC hwmon +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define enable_debug_msg 0 +#define DEBUGUSE_SHIFT 0 + +#define DRVNAME "quanta_hwmon_ipmi" + +#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & (1<<((bits)-1))) | (val)) : (val)) +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) +#define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) +#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & 0xff000000) >> 24) | ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) +#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4), 4)) +#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) + +#define SENSOR_ATTR_MAX 19 +#define SENSOR_ATTR_NAME_LENGTH 20 + +#define SENSOR_GET_CAP_LABEL 0x001 +#define SENSOR_GET_CAP_ALARM 0x002 +#define SENSOR_GET_CAP_INPUT 0x004 + +#define SENSOR_GET_CAP_LNC 0x008 +#define SENSOR_GET_CAP_LCR 0x010 +#define SENSOR_GET_CAP_LNR 0x020 + +#define SENSOR_GET_CAP_UNC 0x040 +#define SENSOR_GET_CAP_UCR 0x080 +#define SENSOR_GET_CAP_UNR 0x100 + +#define SENSOR_GET_CAP_MODEL 0x200 +#define SENSOR_GET_CAP_SN 0x400 +#define SENSOR_GET_CAP_PWM 0x800 + +#define SENSOR_GET_CAP_CONMODE 0x1000 +#define SENSOR_GET_CAP_DIRECTION 0x2000 +#define SENSOR_GET_CAP_FAN_PRESENT 0x4000 +#define SENSOR_GET_CAP_PSU_PRESENT 0x8000 + +#define SENSOR_GET_CAP_MFRID 0x10000 +#define SENSOR_GET_CAP_VIN_TYPE 0x20000 +#define SENSOR_GET_CAP_POUT_MAX 0x40000 + +#define SDR_SENSOR_TYPE_TEMP 0x01 +#define SDR_SENSOR_TYPE_VOLT 0x02 +#define SDR_SENSOR_TYPE_CURR 0x03 +#define SDR_SENSOR_TYPE_FAN 0x04 +#define SDR_SENSOR_TYPE_PS 0x08 +#define SDR_SENSOR_TYPE_OTHER 0x0b + +#define BMC_GET_DEVICE_ID 0x01 + +#define IPMI_NETFN_SE 0x04 +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_STORAGE 0x0a +#define IPMI_NETFN_TSOL 0x30 + +#define GET_SDR_REPO_INFO 0x20 +#define GET_DEVICE_SDR 0x21 +#define GET_SDR_RESERVE_REPO 0x22 +#define GET_SDR 0x23 +#define GET_SENSOR_THRESHOLDS 0x27 +#define GET_SENSOR_EVENT_ENABLE 0x29 +#define GET_SENSOR_EVENT_STATUS 0x2b +#define GET_SENSOR_READING 0x2d +#define GET_PSU_READING 0x52 +#define GET_FAN_INFO 0xd6 +#define GET_FRU_INFO 0x11 + +#define IPM_DEV_DEVICE_ID_SDR_MASK (0x80) /* 1 = provides SDRs */ +#define IPMI_TIMEOUT (4 * HZ) +#define IPMI_MAX_WAIT_QUEUE 1 + +struct quanta_hwmon_ipmi_data +{ + struct platform_device *ipmi_platform_dev; + struct device *ipmi_hwmon_dev; + /*struct mutex ipmi_lock; */ + + int32_t total_sensor_id; + int32_t total_suport_sensor; + int32_t total_create_sysfs; +} *data; + +static struct mutex ipmi_lock; +static struct completion g_read_complete; + +static ipmi_user_t ipmi_mh_user = NULL; + +static int8_t g_fan_control_mode = 3; +static int32_t g_use_built_in = 0; +static int32_t ipmi_wait_queue = 0; + +struct ipmi_sensor_data +{ + uint8_t addr; + uint8_t sensor_type; + uint8_t sensor_idstring[SENSOR_ATTR_NAME_LENGTH]; + + uint32_t capability; + + struct header_info + { + uint8_t header_type; + uint8_t header_byte; + } headerinfo; + + struct record_info + { + uint8_t record_analog; + uint8_t record_linearization; + + int32_t record_m; + int32_t record_b; + int32_t record_k1; + int32_t record_k2; + } recordinfo; + + struct threshold_upper_info + { + uint8_t unr; + uint8_t ucr; + uint8_t unc; + } upperinfo; + + struct threshold_lower_info + { + uint8_t lnr; + uint8_t lcr; + uint8_t lnc; + } lowerinfo; + + struct attr_info + { + bool attr_exist; + char attr_name[SENSOR_ATTR_MAX][SENSOR_ATTR_NAME_LENGTH]; + char attr_type_str[SENSOR_ATTR_NAME_LENGTH]; + + struct attribute *attrs[SENSOR_ATTR_MAX + 1]; + struct attribute_group attr_group; + struct sensor_device_attribute sd_attrs[SENSOR_ATTR_MAX + 1]; + } attrinfo; + +} *g_sensor_data; + +struct ipmi_comm_data +{ + int32_t tx_id; + + int32_t rx_result; + int64_t rx_len; + void *rx_data; + struct completion *rx_read_complete; +}; + +struct ipmi_sdr_iterator +{ + uint16_t reservation; + int32_t total; + int32_t next; +}; + +struct ipm_devid_rsp +{ + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +} __attribute__((packed)); + +struct sdr_repo_info_rs +{ + uint8_t version; /* SDR version (51h) */ + uint16_t count; /* number of records */ + uint16_t free; /* free space in SDR */ + uint32_t add_stamp; /* last add timestamp */ + uint32_t erase_stamp; /* last del timestamp */ + uint8_t op_support; /* supported operations */ +} __attribute__((packed)); + +struct sdr_device_info_rs +{ + uint8_t count; /* number of records */ + uint8_t flags; /* flags */ + uint8_t popChangeInd[3]; /* free space in SDR */ +} __attribute__((packed)); + +struct sdr_get_rs +{ + uint16_t next; /* next record id */ + uint16_t id; /* record ID */ + uint8_t version; /* SDR version (51h) */ +#define SDR_RECORD_TYPE_FULL_SENSOR 0x01 +#define SDR_RECORD_TYPE_COMPACT_SENSOR 0x02 +#define SDR_RECORD_TYPE_EVENTONLY_SENSOR 0x03 +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC 0x09 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 +#define SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR 0x11 +#define SDR_RECORD_TYPE_MC_DEVICE_LOCATOR 0x12 +#define SDR_RECORD_TYPE_MC_CONFIRMATION 0x13 +#define SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO 0x14 +#define SDR_RECORD_TYPE_OEM 0xc0 + uint8_t type; /* record type */ + uint8_t length; /* remaining record bytes */ +} __attribute__((packed)); + +struct sdr_get_rq +{ + uint16_t reserve_id; /* reservation ID */ + uint16_t id; /* record ID */ + uint8_t offset; /* offset into SDR */ +#define GET_SDR_ENTIRE_RECORD 0xff + uint8_t length; /* length to read */ +} __attribute__((packed)); + +struct entity_id +{ + uint8_t id; /* physical entity id */ +#ifdef WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} __attribute__((packed)); + +struct sdr_record_mask +{ + union + { + struct + { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event mask */ + uint16_t read; /* discrete reading mask */ + } discrete; + struct + { +#ifdef WORDS_BIGENDIAN + uint16_t reserved : 1; + uint16_t status_lnr : 1; + uint16_t status_lcr : 1; + uint16_t status_lnc : 1; + uint16_t assert_unr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lnc_low : 1; +#else + uint16_t assert_lnc_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_unr_high : 1; + uint16_t status_lnc : 1; + uint16_t status_lcr : 1; + uint16_t status_lnr : 1; + uint16_t reserved : 1; +#endif +#ifdef WORDS_BIGENDIAN + uint16_t reserved_2 : 1; + uint16_t status_unr : 1; + uint16_t status_ucr : 1; + uint16_t status_unc : 1; + uint16_t deassert_unr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lnc_low : 1; +#else + uint16_t deassert_lnc_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_unr_high : 1; + uint16_t status_unc : 1; + uint16_t status_ucr : 1; + uint16_t status_unr : 1; + uint16_t reserved_2 : 1; +#endif + union + { + struct + { +#ifdef WORDS_BIGENDIAN /* settable threshold mask */ + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; + /* padding lower 8 bits */ + uint16_t readable : 8; +#else + uint16_t readable : 8; + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; +#endif + } set; + struct + { +#ifdef WORDS_BIGENDIAN /* readable threshold mask */ + /* padding upper 8 bits */ + uint16_t settable : 8; + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; +#else + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; + uint16_t settable : 8; +#endif + } read; + }; + } threshold; + } type; +} __attribute__((packed)); + +struct sdr_record_full_sensor +{ + struct + { + uint8_t owner_id; +#ifdef WORDS_BIGENDIAN + uint8_t channel : 4; /* channel number */ + uint8_t __reserved : 2; + uint8_t lun : 2; /* sensor owner lun */ +#else + uint8_t lun : 2; /* sensor owner lun */ + uint8_t __reserved : 2; + uint8_t channel : 4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } keys; + + struct entity_id entity; + + struct + { + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 1; + uint8_t scanning : 1; + uint8_t events : 1; + uint8_t thresholds : 1; + uint8_t hysteresis : 1; + uint8_t type : 1; + uint8_t event_gen : 1; + uint8_t sensor_scan : 1; +#else + uint8_t sensor_scan : 1; + uint8_t event_gen : 1; + uint8_t type : 1; + uint8_t hysteresis : 1; + uint8_t thresholds : 1; + uint8_t events : 1; + uint8_t scanning : 1; + uint8_t __reserved : 1; +#endif + } init; + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t ignore : 1; + uint8_t rearm : 1; + uint8_t hysteresis : 2; + uint8_t threshold : 2; + uint8_t event_msg : 2; +#else + uint8_t event_msg : 2; + uint8_t threshold : 2; + uint8_t hysteresis : 2; + uint8_t rearm : 1; + uint8_t ignore : 1; +#endif + } capabilities; + uint8_t type; + } sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t analog : 2; + uint8_t rate : 3; + uint8_t modifier : 2; + uint8_t pct : 1; +#else + uint8_t pct : 1; + uint8_t modifier : 2; + uint8_t rate : 3; + uint8_t analog : 2; +#endif + struct + { + uint8_t base; + uint8_t modifier; + } type; + } unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 5; + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t nominal_read : 1; /* nominal reading field specified */ +#else + uint8_t nominal_read : 1; /* nominal reading field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t __reserved : 5; +#endif + } analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct + { + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } upper; + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } lower; + struct + { + uint8_t positive; + uint8_t negative; + } hysteresis; + } threshold; + uint8_t __reserved[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} __attribute__((packed)); + +int32_t pow_convert(int32_t *a, int32_t b) +{ + /* function input parameter (a * 10 ^ b) */ + int32_t i = 0, r = 1, temp_b = 0; + + temp_b = (b > 0) ? b : -b; + + for (i = 0; i < temp_b; i++) + { + r = r * 10; + } + + if (b > 0) + { + *a = (*a) * r; + r = 1; + } + /* function return parameter calc_result = *a, decimal_point = r */ + return r; +} + +void simple_atoi(const char *buf, int8_t *output_val) +{ + while (*buf >= '0' && *buf <= '9') + { + *output_val = *output_val * 10 + *buf - '0'; + buf++; + } +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) +{ + int32_t rv = -IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + struct ipmi_comm_data *comm_data = msg->user_msg_data; + + ipmi_wait_queue--; + + if (msg->msg.data[0] != 0) + { + if ((msg->msg.data[0] != 0x83) && (msg->msg.netfn != 0x07) + && (msg->msg.cmd != 0x52)) + { + /*skip master r/w cmd return code */ + printk("ipmi: Error 0x%x on cmd 0x%x/0x%x\n", msg->msg.data[0], msg->msg.netfn, + msg->msg.cmd); + rv = msg->msg.data[0]; + goto get_BMC_response_fail; + } + } + + if (msg->msgid != comm_data->tx_id) + { + printk("ipmi: rx msgid %d mismatch tx msgid %d\n", (int32_t)msg->msgid, + comm_data->tx_id); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len <= 0) + { + printk("ipmi: Data len too low (%d)\n", msg->msg.data_len); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len > 1) + { + if (comm_data->rx_len) + { + comm_data->rx_len = msg->msg.data_len - 1; + memcpy(comm_data->rx_data, msg->msg.data + 1, comm_data->rx_len); + } + else + { + printk("ipmi: rx len = 0, it should be not retrun ?\n"); + goto get_BMC_response_fail; + } + } + + rv = 0; + +get_BMC_response_fail: + ipmi_free_recv_msg(msg); + + if (ipmi_wait_queue == 0) + { + comm_data->rx_result = rv; + if (rv == 0) + { + complete(comm_data->rx_read_complete); + } + } +} +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_msg_handler, }; + +int32_t ipmi_request_wait_for_response(struct kernel_ipmi_msg msg, + struct ipmi_comm_data *comm_data) +{ + int32_t rv = 0; + int32_t escape_time = 0; + + struct ipmi_addr ipmi_address; + + if (ipmi_wait_queue >= IPMI_MAX_WAIT_QUEUE) + { + /* printk("msg queue full, cannot send ipmi cmd\n"); */ + return -EBUSY; + } + ipmi_wait_queue++; + + ipmi_address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi_address.channel = IPMI_BMC_CHANNEL; + ipmi_address.data[0] = 0; + + rv = ipmi_validate_addr(&ipmi_address, sizeof(ipmi_address)); + if (rv) + { + printk("ipmi_validate_addr fail, err code : %d\n", rv); + return rv; + } + + ipmi_request_settime(ipmi_mh_user, &ipmi_address, comm_data->tx_id, &msg, + comm_data, 0, 0, 0); + + escape_time = wait_for_completion_timeout(comm_data->rx_read_complete, + IPMI_TIMEOUT); + + rv = comm_data->rx_result; + if (escape_time == 0) + { + printk("BMC not response (%d)\n", escape_time); + } + + return rv; +} + +int32_t ipmi_send_system_cmd(uint8_t *msg_tx_data, int32_t msg_tx_len, + void *msg_rx_data, int32_t msg_rx_len) +{ + int32_t i = 0; + int32_t rv = 0; + + static uint64_t tx_msgid = 1; + + struct kernel_ipmi_msg msg; + struct ipmi_comm_data *comm_data = NULL; + struct completion read_complete; + + init_completion(&read_complete); + + /* prepare transfer message */ + msg.netfn = msg_tx_data[0]; + msg.cmd = msg_tx_data[1]; + msg.data_len = msg_tx_len - 2; + + msg.data = kzalloc(msg.data_len, GFP_KERNEL); + if (msg.data == NULL) + { + printk("%s(%d): malloc [msg.data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + comm_data = kzalloc(sizeof(struct ipmi_comm_data), GFP_KERNEL); + if (comm_data == NULL) + { + printk("%s(%d): malloc [comm_data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + for (i = 2; i < msg_tx_len; i++) + { + msg.data[i - 2] = msg_tx_data[i]; + } + + comm_data->tx_id = tx_msgid++; + + /* prepare recive message */ + comm_data->rx_data = msg_rx_data; + comm_data->rx_len = msg_rx_len; + comm_data->rx_result = -1; + comm_data->rx_read_complete = &read_complete; + + rv = ipmi_request_wait_for_response(msg, comm_data); + +alloc_mem_fail: + if (msg.data) + { + kfree(msg.data); + } + if (comm_data) + { + kfree(comm_data); + } + if (tx_msgid > UINT_MAX) + { + tx_msgid = 1; + } + + return rv; +} + +int32_t ipmi_sdr_get_reservation(uint16_t *reserve_id) +{ + int32_t rv = 0; + uint8_t msg_data[] = { 0x00, GET_SDR_RESERVE_REPO }; /*netfn = 0x00; cmd = GET_SDR_RESERVE_REPO; */ + + msg_data[0] = (g_use_built_in == 0) ? IPMI_NETFN_STORAGE : IPMI_NETFN_SE; + + /* obtain reservation ID */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), reserve_id, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + +#if enable_debug_msg + printk("SDR reservation ID %04x\n", *reserve_id); +#endif + + return rv; +} + +int32_t ipmi_sdr_start(struct ipmi_sdr_iterator *itr) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { IPMI_NETFN_APP, BMC_GET_DEVICE_ID }; /*netfn = IPMI_NETFN_APP; cmd = BMC_GET_DEVICE_ID; */ + + struct ipm_devid_rsp devid; + + /* check SDRR capability */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &devid, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return rv; + } + + if (devid.device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) + { + if ((devid.adtl_device_support & 0x02) == 0) + { + if ((devid.adtl_device_support & 0x01)) + { + printk("Using Device SDRs\n"); + g_use_built_in = 1; + } + else + { + printk("Error obtaining SDR info\n"); + } + } + } + + if (g_use_built_in == 0) + { + struct sdr_repo_info_rs sdr_info; + /* get sdr repository info */ + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + +#if enable_debug_msg + printk("SDR version: 0x%x\n", sdr_info.version); + printk("SDR free space: %d\n", sdr_info.free); +#endif + } + else + { + struct sdr_device_info_rs sdr_info; + /* get device sdr info */ + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + } + +#if enable_debug_msg + printk("SDR records : %d\n", sdr_info.count); +#endif + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + itr->next = 0; + rv = ipmi_sdr_get_reservation(&(itr->reservation)); + } + + return rv; +} + +int32_t ipmi_sdr_get_header(struct ipmi_sdr_iterator *itr, + struct sdr_get_rs *sdr_rs) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = itr->next; + sdr_rq.offset = 0; + sdr_rq.length = 5; /* only get the header */ + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), sdr_rs, 1); + if ((rv) || (sdr_rs->length == 0)) + { + printk("SDR record id 0x%04x: invalid length %d", itr->next, sdr_rs->length); + return -1; + } + + if (sdr_rs->id != itr->next) + { +#if enable_debug_msg + printk("SDR record id mismatch: 0x%04x\n", sdr_rs->id); +#endif + sdr_rs->id = itr->next; + } +#if enable_debug_msg + printk("\nSDR record ID : 0x%04x", itr->next); + printk("SDR record type : 0x%02x\n", sdr_rs->type); + printk("SDR record next : 0x%04x\n", sdr_rs->next); + printk("SDR record bytes: %d\n", sdr_rs->length); +#endif + + return rv; +} + +int32_t ipmi_sdr_get_record(struct sdr_get_rs *header, + struct ipmi_sdr_iterator *itr, uint8_t *ret_data) +{ + int32_t rv = 0, len = 0; + + uint8_t buff[128] = ""; + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + len = header->length; + if (len > 0) + { + memset(&sdr_rq, 0, sizeof(sdr_rq)); + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = header->id; + sdr_rq.offset = 5; + sdr_rq.length = len; + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), ret_data, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + memset(buff, 0, sizeof(buff)); + memcpy(buff, ret_data + 2, sdr_rq.length); + memcpy(ret_data, buff, sdr_rq.length + 2); + } + } + + return rv; +} + +void ipmi_sdr_set_sensor_threshold(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + + /* lower threshold info */ + if (sensor->mask.type.threshold.read.lnc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNC; + } + if (sensor->mask.type.threshold.read.lcr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LCR; + } + if (sensor->mask.type.threshold.read.lnr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNR; + } + g_sensor_data[idx].lowerinfo.lnc = sensor->threshold.lower.non_critical; + g_sensor_data[idx].lowerinfo.lcr = sensor->threshold.lower.critical; + g_sensor_data[idx].lowerinfo.lnr = sensor->threshold.lower.non_recover; + + /* upper threshold info */ + if (sensor->mask.type.threshold.read.unc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNC; + } + if (sensor->mask.type.threshold.read.ucr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UCR; + } + if (sensor->mask.type.threshold.read.unr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNR; + } + g_sensor_data[idx].upperinfo.unc = sensor->threshold.upper.non_critical; + g_sensor_data[idx].upperinfo.ucr = sensor->threshold.upper.critical; + g_sensor_data[idx].upperinfo.unr = sensor->threshold.upper.non_recover; +} + +void ipmi_sdr_set_sensor_factor(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + char *loc = NULL; + + g_sensor_data[idx].sensor_type = sensor->sensor.type; + sprintf(g_sensor_data[idx].sensor_idstring, "%s", sensor->id_string); + + g_sensor_data[idx].recordinfo.record_m = __TO_M(sensor->mtol); + g_sensor_data[idx].recordinfo.record_b = __TO_B(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k1 = __TO_B_EXP(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k2 = __TO_R_EXP(sensor->bacc); + + g_sensor_data[idx].recordinfo.record_analog = sensor->unit.analog; + g_sensor_data[idx].recordinfo.record_linearization = sensor->linearization; + + memset(g_sensor_data[idx].attrinfo.attr_type_str, 0x00, + SENSOR_ATTR_NAME_LENGTH); + + switch (g_sensor_data[idx].sensor_type) + { + case SDR_SENSOR_TYPE_TEMP: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "temp"); + break; + case SDR_SENSOR_TYPE_VOLT: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + break; + case SDR_SENSOR_TYPE_FAN: + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PWM; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_CONMODE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_DIRECTION; + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "fan"); + break; + case SDR_SENSOR_TYPE_PS: + loc = strstr(g_sensor_data[idx].sensor_idstring, "POWER"); + if (loc) + { + if ((strncmp(g_sensor_data[idx].sensor_idstring + 11, "OUT", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MODEL; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_SN; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MFRID; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PSU_PRESENT; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_VIN_TYPE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_POUT_MAX; + } + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "power"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "VOLTAGE"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "CURRENT"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + } + + break; + case SDR_SENSOR_TYPE_CURR: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + break; + case SDR_SENSOR_TYPE_OTHER: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "other"); + break; + default: + printk("not support sensor type !! [%d]\n", g_sensor_data[idx].sensor_type); + break; + } + + if ((strncmp(g_sensor_data[idx].sensor_idstring, "Fan", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_FAN_PRESENT; + } + +#if enable_debug_msg + { + printk("\n********************\n"); + + printk("m[%d], b[%d], k1[%d], k2[%d]\n", g_sensor_data[idx].recordinfo.record_m, + g_sensor_data[idx].recordinfo.record_b + , g_sensor_data[idx].recordinfo.record_k1, + g_sensor_data[idx].recordinfo.record_k2); + + printk("sensor [%s] type[%d], analog[%d], linearization[%d]\n", + g_sensor_data[idx].sensor_idstring, g_sensor_data[idx].sensor_type + , g_sensor_data[idx].recordinfo.record_analog, + g_sensor_data[idx].recordinfo.record_linearization); + + printk("\n********************\n"); + } +#endif + +} + +int32_t sdr_convert_sensor_reading(uint8_t idx, uint8_t val, + int32_t *point_result) +{ + int32_t m = g_sensor_data[idx].recordinfo.record_m; + int32_t b = g_sensor_data[idx].recordinfo.record_b; + int32_t k1 = g_sensor_data[idx].recordinfo.record_k1; + int32_t k2 = g_sensor_data[idx].recordinfo.record_k2; + int32_t decimal_point = 0; + int32_t result = 0; + + decimal_point = pow_convert(&b, k1); + + switch (g_sensor_data[idx].recordinfo.record_analog) + { + case 0: + result = m * val * decimal_point + b; + break; + case 1: + if (val & 0x80) + { + val++; + } + case 2: + result = (m * (int16_t)val) * decimal_point + b; + break; + default: + return; + } + + pow_convert(&result, k2); + if (k1 < 0) + { + *point_result += -k1; + } + if (k2 < 0) + { + *point_result += -k2; + } + + if (g_sensor_data[idx].sensor_type != SDR_SENSOR_TYPE_FAN) + { + result = result * 1000; /*shift for lm-sensors */ + } + + return result; +} + +int32_t ipmi_sdr_parsing_value(int32_t idx, uint8_t input_value, + int8_t *ret_str) +{ + int32_t calc_result = 0, point_result = 0; + int32_t temp_len = 0; + + uint8_t temp_str[16] = ""; + + calc_result = sdr_convert_sensor_reading(idx, input_value, &point_result); + + temp_len = sprintf(temp_str, "%d", calc_result); + temp_len = temp_len - point_result; + + /* int part */ + if (temp_len <= 0) + { + sprintf(ret_str, "0"); + } + else + { + snprintf(ret_str, temp_len + 1, "%s", + temp_str); /* +1 for snprintf reserve space'\0' */ + } + + /* point part */ + strcat(ret_str, "."); + + /* float part */ + if ((point_result == 0) || (temp_len < 0)) + { + strcat(ret_str, "0"); + } + else + { + strcat(ret_str, temp_str + temp_len); + } + + /* EOL part */ + strcat(ret_str, "\n\0"); + + return (temp_len + 1 + point_result + + 2); /*integer + point + float + EOL + \0 */ +} + + +uint8_t ipmi_check_psu_present(uint8_t psu_slot) +{ + uint8_t slot_mask = 0x0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x03 }; /*netfn = 0x36; cmd = 0xB9; */ + /*uint8_t msg_data[] = { 0x06, 0x52, 0x1B, 0x4C, 0x01, 0x00 }; //netfn = IPMI_NETFN_APP; cmd = GET_PSU_READING; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return 0; + } + else + { + slot_mask = (psu_slot == 1) ? 0x01 : 0x02; + return (returnData[0] & slot_mask) ? 0 : 1; + } +} + +int32_t ipmi_get_psu_info(uint8_t idx, uint8_t cmd, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xBB, 0x4C, 0x1C, 0x00, cmd, 0x00 }; /*netfn = 0x36; cmd = 0xBB; */ + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) + { + psu_slot = 1; + } + else + { + psu_slot = 2; + } + + if (ipmi_check_psu_present(psu_slot)) + { + msg_data[6] = psu_slot; + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + return sprintf(retbuf, "%s\n", returnData); + } + } + else + { + /*printk("Error ! cannot detect PSU%d\n", psu_slot); */ + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_vin_type(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData = 0; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x01, 0xd8 }; // read line status + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + switch (returnData) + { + case 0x7: //LVDC + case 0x3: //HVDC + return sprintf(retbuf, "DC\n"); + default: + return sprintf(retbuf, "AC\n"); + } + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_pout_max(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0, pout_max = 0; + + uint8_t returnData[2] = { 0 }, tempData[2] = { 0 }; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x02, 0xa7 }; + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + /* MFR_POUT_MAX has 2 data format: Direct and Linear Data (see PMbus spec). + Query command is needed to tell the data format, but since we have not use PSU + whose output power is over 0x07ff (2047), just check the first 5 bits*/ + if (returnData[1] & 0xf8 == 0) // Direct + pout_max = (returnData[1] << 8) | returnData[0]; + else // Linear Data + pout_max = (((returnData[1] & 0x07) << 8) | returnData[0]) << ((returnData[1] & 0xf8) >> 3); + return sprintf(retbuf, "%d\n", pout_max); + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +void ipmi_fan_control(uint8_t cmd_data1, uint8_t cmd_data2, uint8_t *retbuf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_TSOL, GET_FAN_INFO, cmd_data1, cmd_data2 }; /*netfn = IPMI_NETFN_TSOL; cmd = GET_FAN_INFO; */ + + mutex_lock(&ipmi_lock); + if (cmd_data1) + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), NULL, 0); + } + else + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + } + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + sprintf(retbuf, "N/A\n"); + } + else + { + sprintf(retbuf, "%s", returnData); + } +} + +static ssize_t show_label(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%s\n", + g_sensor_data[attr->index + DEBUGUSE_SHIFT].sensor_idstring); +} + +static ssize_t show_crit_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%d\n", attr->index); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int32_t rv = 0; + + uint8_t returnData[4] = ""; + uint8_t msg_data[] = { IPMI_NETFN_SE, GET_SENSOR_READING, 0x00 }; /*netfn = IPMI_NETFN_SE; cmd = GET_SENSOR_READING; */ + + mutex_lock(&ipmi_lock); + msg_data[2] = g_sensor_data[attr->index + DEBUGUSE_SHIFT].addr; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "0.0\n"); + } + else + { + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, returnData[0], buf); + } +} + +static ssize_t show_lnr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnr, buf); +} + +static ssize_t show_lcr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lcr, buf); +} + +static ssize_t show_lnc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnc, buf); +} + +static ssize_t show_unr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unr, buf); +} + +static ssize_t show_ucr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.ucr, buf); +} + +static ssize_t show_unc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unc, buf); +} + +static ssize_t show_model(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9a, buf); +} + +static ssize_t show_sn(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9e, buf); +} + +static ssize_t show_mfrid(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x99, buf); +} + +static ssize_t show_vin_type(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_vin_type(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pout_max(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_pout_max(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + uint8_t returnData[10] = { 0 }; + ipmi_fan_control(0x00, 0x00, returnData); + return sprintf(buf, "%d\n", returnData[0]); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + if (g_fan_control_mode == 1) + { + ipmi_fan_control(0x01, store_input, returnData); + } + + return count; +} + +static ssize_t show_controlmode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%d\n", g_fan_control_mode); +} + +static ssize_t store_controlmode(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + g_fan_control_mode = store_input; + if (g_fan_control_mode == 3) + { + ipmi_fan_control(0x7f, 0xff, returnData); + } + + return count; +} + +static ssize_t show_direction(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_STORAGE, GET_FRU_INFO, 0x00, 0x19, 0x00, 0x01 }; /*netfn = IPMI_NETFN_STORAGE; cmd = GET_FRU_INFO; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "N/A\n"); + } + else + { + return sprintf(buf, "%c\n", returnData[1]); + } +} + +static ssize_t show_fanpresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + int32_t fan_idx = 0, fan_present = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x02 }; /*netfn = 0x36; cmd = 0xB9; */ + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct kernel_ipmi_msg msg; + + fan_idx = (g_sensor_data[attr->index].sensor_idstring[8] - '0') - 1; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + fan_present = ((returnData[0] >> fan_idx) & 0x1) ? 0 : 1; + + return sprintf(buf, "%d\n", fan_present); +} + +static ssize_t show_psupresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t psu_idx = 0; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + psu_idx = g_sensor_data[attr->index].sensor_idstring[3] - '0'; + + return sprintf(buf, "%d\n", ipmi_check_psu_present(psu_idx)); +} + +static ssize_t(*const attr_show_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, char *buf) = +{ + show_label, show_crit_alarm, show_input + , show_lnc, show_lcr, show_lnr + , show_unc, show_ucr, show_unr + , show_model, show_sn, show_pwm + , show_controlmode, show_direction, show_fanpresent + , show_psupresent, show_mfrid, show_vin_type + , show_pout_max +}; + +static ssize_t(*const attr_store_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) = +{ + NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, store_pwm + , store_controlmode, NULL, NULL + , NULL, NULL, NULL + , NULL +}; + +static const char *const sensor_attrnames[SENSOR_ATTR_MAX] = +{ + "%s%d_label", "%s%d_crit_alarm", "%s%d_input" + , "%s%d_lncrit", "%s%d_lcrit", "%s%d_min" + , "%s%d_ncrit", "%s%d_crit", "%s%d_max" + , "%s%d_model", "%s%d_sn", "%s%d_pwm" + , "%s%d_controlmode", "%s%d_direction", "%s%d_present" + , "%s%d_present", "%s%d_mfrid", "%s%d_vin_type" + , "%s%d_pout_max" +}; + +static int32_t create_sensor_attrs(int32_t attr_no) +{ + int32_t i = 0, j = 0; + + struct attr_info *attrdata = &g_sensor_data[attr_no].attrinfo; + +#if enable_debug_msg + printk("##### %s:%d attr_no %d\n", __FUNCTION__, __LINE__, attr_no); +#endif + + for (i = 0; i < SENSOR_ATTR_MAX; i++) + { + if ((g_sensor_data[attr_no].capability >> i) & 0x01) + { + snprintf(attrdata->attr_name[j], SENSOR_ATTR_NAME_LENGTH, sensor_attrnames[i], + attrdata->attr_type_str, attr_no - DEBUGUSE_SHIFT); + + sysfs_attr_init(&attrdata->sd_attrs[j].dev_attr.attr); + attrdata->sd_attrs[j].dev_attr.attr.name = attrdata->attr_name[j]; + attrdata->sd_attrs[j].dev_attr.show = attr_show_func_ptr[i]; + attrdata->sd_attrs[j].dev_attr.store = attr_store_func_ptr[i]; + + attrdata->sd_attrs[j].dev_attr.attr.mode = S_IRUGO; + if (attrdata->sd_attrs[j].dev_attr.store) + { + attrdata->sd_attrs[j].dev_attr.attr.mode |= S_IWUSR; + } + + attrdata->sd_attrs[j].index = attr_no - DEBUGUSE_SHIFT; + attrdata->attrs[j] = &attrdata->sd_attrs[j].dev_attr.attr; + j++; + + data->total_create_sysfs++; + } + } + + attrdata->attrs[j] = NULL; + attrdata->attr_group.attrs = attrdata->attrs; + + g_sensor_data[attr_no].attrinfo.attr_exist = 1; + + return sysfs_create_group(&data->ipmi_hwmon_dev->kobj, &attrdata->attr_group); +} + +static int32_t remove_sensor_attrs(void) +{ + int32_t i = 0; + + for (i = 0; i < data->total_sensor_id; i++) + { + if (g_sensor_data[i].attrinfo.attr_exist) + { + sysfs_remove_group(&data->ipmi_hwmon_dev->kobj, + &g_sensor_data[i].attrinfo.attr_group); + } + } + return 0; +} + +int32_t ipmi_init_sdr_sensors_data(void) +{ + int32_t sdr_idx = 0; + int32_t err = 0; + + struct ipmi_sdr_iterator *itr = NULL; + struct sdr_get_rs *header = NULL; + + uint8_t *rec = NULL; + + mutex_lock(&ipmi_lock); + + itr = kzalloc(sizeof(struct ipmi_sdr_iterator), GFP_KERNEL); + if (itr == NULL) + { + printk("%s(%d): kzalloc failure.\n", __func__, __LINE__); + goto itr_malloc_fail; + } + + header = kzalloc(sizeof(struct sdr_get_rs), GFP_KERNEL); + if (header == NULL) + { + printk("%s(%d): malloc failure.\n", __func__, __LINE__); + goto header_malloc_fail; + } + + err = ipmi_sdr_start(itr); + if (err) + { + printk("%s(%d): ipmi_sdr_start fail.\n", __func__, __LINE__); + goto ipmi_sdr_start_fail; + } + + data->total_sensor_id = itr->total; + rec = kzalloc(GET_SDR_ENTIRE_RECORD, GFP_KERNEL); + if (rec == NULL) + { + printk("%s(%d): kzalloc failure\n", __func__, __LINE__); + goto rec_malloc_fail; + } + + g_sensor_data = kzalloc(itr->total * sizeof(struct ipmi_sensor_data), + GFP_KERNEL); + if (g_sensor_data == NULL) + { + printk("%s(%d): malloc failure", __func__, __LINE__); + goto g_sensor_data_malloc_fail; + } + + memset(g_sensor_data, 0x0, itr->total * sizeof(struct ipmi_sensor_data)); + + for (sdr_idx = 0; sdr_idx < itr->total; sdr_idx++) + { + err = ipmi_sdr_get_header(itr, header); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_header_fail; + } + + + memset(rec, 0, GET_SDR_ENTIRE_RECORD); + err = ipmi_sdr_get_record(header, itr, rec); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_record_fail; + } + + itr->next = header->next; + + switch (header->type) + { + case SDR_RECORD_TYPE_FULL_SENSOR: + /* prepare (threshold, factor)data whilie init, for reduce reading step and improve operate speed */ + g_sensor_data[sdr_idx].addr = rec[2]; + g_sensor_data[sdr_idx].capability = + SENSOR_GET_CAP_LABEL /*| SENSOR_GET_CAP_ALARM */ | SENSOR_GET_CAP_INPUT; + g_sensor_data[sdr_idx].headerinfo.header_type = header->type; + g_sensor_data[sdr_idx].headerinfo.header_byte = header->length; + + ipmi_sdr_set_sensor_threshold(sdr_idx, (struct sdr_record_full_sensor *) rec); + ipmi_sdr_set_sensor_factor(sdr_idx, (struct sdr_record_full_sensor *) rec); + + if (sdr_idx >= DEBUGUSE_SHIFT) + { + err = create_sensor_attrs(sdr_idx); + if (err) + { + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; + printk("[err : %d]sysfs_create_group fail in [%d] %s\n", err, sdr_idx, + g_sensor_data[sdr_idx].sensor_idstring); + goto create_sysfs_fail; + } + } + + data->total_suport_sensor++; + + break; + case SDR_RECORD_TYPE_COMPACT_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_EVENTONLY_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR: /* not supporrt now */ + default: + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; +#if enable_debug_msg + printk("ID[%d] : not support type [%d]\n", sdr_idx, header->type); +#endif + break; + } + } + + printk("quanta_hwmon_ipmi : detected [%d] sensor, create [%d] sysfs\n", + data->total_suport_sensor, data->total_create_sysfs); + +create_sysfs_fail: +ipmi_sdr_get_header_fail: +ipmi_sdr_get_record_fail: +g_sensor_data_malloc_fail: + if (header) + { + kfree(header); + header = NULL; + } + if (rec) + { + kfree(rec); + rec = NULL; + } + +rec_malloc_fail: +ipmi_sdr_start_fail: +header_malloc_fail: + if (itr) + { + kfree(itr); + itr = NULL; + } + +itr_malloc_fail: + mutex_unlock(&ipmi_lock); + + return err; +} + +static int32_t __init quanta_hwmon_ipmi_init(void) +{ + int32_t err = 0; + + init_completion(&g_read_complete); + + data = kzalloc(sizeof(struct quanta_hwmon_ipmi_data), GFP_KERNEL); + if (NULL == data) + { + printk("alloc data fail\n"); + goto alloc_err; + } + + data->ipmi_platform_dev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + err = IS_ERR(data->ipmi_platform_dev); + if (err) + { + printk("platform device register fail (err : %d)\n", err); + goto device_reg_err; + } + + data->ipmi_hwmon_dev = hwmon_device_register_with_groups(NULL, DRVNAME, NULL, + NULL); + err = IS_ERR(data->ipmi_hwmon_dev); + if (err) + { + printk("hwmon register fail\n"); + goto hwmon_register_err; + } + + err = ipmi_create_user(0, &ipmi_hndlrs, NULL, &ipmi_mh_user); + if (err) + { + printk("warning: create user fail, watchdog broken (err : %d)\n", err); + goto ipmi_create_err; + } + + mutex_init(&ipmi_lock); + err = ipmi_init_sdr_sensors_data(); + if (err) + { + printk("init sensor data fail (err : %d)\n", err); + goto init_sensor_err; + } + + return 0; + +init_sensor_err: + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } +ipmi_create_err: + hwmon_device_unregister(data->ipmi_hwmon_dev); +hwmon_register_err: + platform_device_unregister(data->ipmi_platform_dev); +device_reg_err: + if (data) + { + kfree(data); + data = NULL; + } +alloc_err: + return err; +} + +static void __exit quanta_hwmon_ipmi_exit(void) +{ + remove_sensor_attrs(); + hwmon_device_unregister(data->ipmi_hwmon_dev); + + mutex_lock(&ipmi_lock); + ipmi_destroy_user(ipmi_mh_user); + mutex_unlock(&ipmi_lock); + + platform_device_unregister(data->ipmi_platform_dev); + + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } + + if (data) + { + kfree(data); + data = NULL; + } +} + +module_init(quanta_hwmon_ipmi_init); +module_exit(quanta_hwmon_ipmi_exit); + +MODULE_AUTHOR("Charcar~~Charcar~Charlie li li"); +MODULE_VERSION("2.0"); +MODULE_DESCRIPTION("Quanta BMC hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/service/ix8-platform-init.service b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/service/ix8-platform-init.service old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/setup.py old mode 100755 new mode 100644 index 76c5eacbee..1f6a99b1a7 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/setup.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import sys from setuptools import setup os.listdir diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/__init__.py new file mode 100644 index 0000000000..4bfefa0fb6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/chassis.py new file mode 100644 index 0000000000..b959d66780 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/chassis.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import sys + import time + import syslog + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 56 + self.__num_of_sfps = 48 + self.__num_of_fan_drawers = 6 + self.__fan_per_drawer = 2 + self.__num_of_thermals = 15 + self.__xcvr_presence = {} + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + fan_index = 1 + for drawer_index in range(1, self.__num_of_fan_drawers + 1): + drawer_fan_list = [] + for index in range(0, self.__fan_per_drawer): + fan = Fan(fan_index, False) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(1, self.__num_of_ports + 1): + if index in range(1, self.__num_of_sfps + 1): + sfp = Sfp(index, 'SFP') + else: + sfp = Sfp(index, 'QSFP') + + self._sfp_list.append(sfp) + + for index in range(1, self.__num_of_ports + 1): + self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() + +############################################## +# Device methods +############################################## + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + For Quanta IX8 the index in sfputil.py starts from 1, so override + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + if (index == 0): + raise IndexError + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("override: SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_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 + +############################################## +# Chassis methods +############################################## + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + return self._eeprom.system_eeprom_info() + + ############################################## + # Other methods + ############################################## + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + """ + try: + if self._watchdog is None: + from sonic_platform.watchdog import Watchdog + # Create the watchdog Instance + self._watchdog = Watchdog() + + except Exception as e: + syslog.syslog(syslog.LOG_ERR, "Fail to load watchdog due to {}".format(e)) + return self._watchdog + + def get_change_event(self, timeout=0): + """ + Currently only support transceiver change events + """ + + start_ms = time.time() * 1000 + xcvr_change_event_dict = {} + event = False + + while True: + time.sleep(0.5) + for index in range(1, self.__num_of_ports + 1): + cur_xcvr_presence = self._sfp_list[index-1].get_presence() + if cur_xcvr_presence != self.__xcvr_presence[index]: + if cur_xcvr_presence is True: + xcvr_change_event_dict[str(index)] = '1' + self.__xcvr_presence[index] = True + elif cur_xcvr_presence is False: + xcvr_change_event_dict[str(index)] = '0' + self.__xcvr_presence[index] = False + event = True + + if event is True: + return True, {'sfp':xcvr_change_event_dict} + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, {'sfp':xcvr_change_event_dict} + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/eeprom.py new file mode 100644 index 0000000000..1c044638ed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/eeprom.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + # Display vendor extension for Quanta platforms + _TLV_DISPLAY_VENDOR_EXT = True + + def __init__(self): + self.__eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + 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] + + if tlv[0] == self._TLV_CODE_VENDOR_EXT: + value = str((tlv[2] << 24) | (tlv[3] << 16) | + (tlv[4] << 8) | tlv[5]) + value += tlv[6:6 + tlv[1]].decode('ascii') + else: + value = self.decoder(None, tlv)[30:] + + 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): + (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): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in results[2]]).upper() + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + + def decoder(self, s, t): + ''' + Return a string representing the contents of the TLV field. The format of + the string is: + 1. The name of the field left justified in 20 characters + 2. The type code in hex right justified in 5 characters + 3. The length in decimal right justified in 4 characters + 4. The value, left justified in however many characters it takes + The vailidity of EEPROM contents and the TLV field has been verified + prior to calling this function. The 's' parameter is unused + ''' + if t[0] == self._TLV_CODE_PRODUCT_NAME: + name = "Product Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PART_NUMBER: + name = "Part Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERIAL_NUMBER: + name = "Serial Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_BASE: + name = "Base MAC Address" + value = ":".join(["{:02x}".format(T) for T in t[2:8]]).upper() + elif t[0] == self._TLV_CODE_MANUF_DATE: + name = "Manufacture Date" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DEVICE_VERSION: + name = "Device Version" + value = str(t[2]) + elif t[0] == self._TLV_CODE_LABEL_REVISION: + name = "Label Revision" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PLATFORM_NAME: + name = "Platform Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_ONIE_VERSION: + name = "ONIE Version" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_SIZE: + name = "MAC Addresses" + value = str((t[2] << 8) | t[3]) + elif t[0] == self._TLV_CODE_MANUF_NAME: + name = "Manufacturer" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MANUF_COUNTRY: + name = "Manufacture Country" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_NAME: + name = "Vendor Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DIAG_VERSION: + name = "Diag Version" + # Quanta legacy format of diag version + if t[1] == 4: + value = "{}.{}.{}.{}".format('{:02x}'.format(t[2])[0], '{:02x}'.format(t[2])[1], + '{:02x}'.format(t[3])[0], '{:02x}'.format(t[3])[1]) + else: + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERVICE_TAG: + name = "Service Tag" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_EXT: + name = "Vendor Extension" + value = "" + if self._TLV_DISPLAY_VENDOR_EXT: + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + elif t[0] == self._TLV_CODE_CRC_32 and len(t) == 6: + name = "CRC-32" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + # Quanta specific codes below here. + # These decodes are lifted from their U-Boot codes + elif t[0] == self._TLV_CODE_QUANTA_MAGIC and len(t) == 3: + name = "Magic Number" + value = "0x%02X" % t[2] + elif t[0] == self._TLV_CODE_QUANTA_CRC and len(t) == 4: + name = "QUANTA-CRC" + value = "0x%04X" % ((t[2] << 8) + t[3]) + elif t[0] == self._TLV_CODE_QUANTA_CARD_TYPE and len(t) == 6: + name = "Card Type" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + elif t[0] == self._TLV_CODE_QUANTA_HW_VERSION and len(t) == 6: + name = "Hardware Version" + value = "%d.%d" % (t[2], t[3]) + elif t[0] == self._TLV_CODE_QUANTA_SW_VERSION and len(t) == 6: + name = "Software Version" + value = "%d.%d.%d.%d" % ((t[2] >> 4), (t[2] & 0xF), (t[3] >> 4), (t[3] & 0xF)) + elif t[0] == self._TLV_CODE_QUANTA_MANUF_DATE and len(t) == 6: + name = "Manufacture Date" + value = "%04d/%d/%d" % (((t[2] << 8) | t[3]), t[4], t[5]) + elif t[0] == self._TLV_CODE_QUANTA_MODEL_NAME: + name = "Model Name" + value = t[2:2 + t[1]].decode("ascii") + else: + name = "Unknown" + value = "" + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + return name, value + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/fan.py new file mode 100644 index 0000000000..97797df673 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/fan.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta IX8 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import logging + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +HWMON_DIR = "/sys/class/hwmon/hwmon1/" +FAN_INDEX_START = 21 +NUM_FANTRAYS = 6 +FANS_PERTRAY = 2 + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + self.fan_index = index + self.psu_fan_index_mapping = { + 1:41, + 2:52, + } + self.psu_index_mapping = { + 1:43, + 2:54, + } + if self.is_psu_fan: + self.fan_presence_attr = "power{}_present".format(self.psu_index_mapping[index]) + self.fan_pwm_attr = "fan{}_pwm".format(self.psu_fan_index_mapping[index]) + self.fan_rpm_attr = "fan{}_input".format(self.psu_fan_index_mapping[index]) + self.fan_direction_attr = "fan{}_direction".format(self.psu_fan_index_mapping[index]) + else: + self.fan_presence_attr = "fan{}_present".format(FAN_INDEX_START+(index-1)) + self.fan_pwm_attr = "fan{}_pwm".format(FAN_INDEX_START+(index-1)) + self.fan_rpm_attr = "fan{}_input".format(FAN_INDEX_START+(index-1)) + self.fan_direction_attr = "fan{}_direction".format(FAN_INDEX_START+(index-1)) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + 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.fan_index) + else: + fantray_index = (self.fan_index-1)//FANS_PERTRAY+1 + fan_index_intray = self.fan_index - ((fantray_index-1)*FANS_PERTRAY) + return "Fantray{}_{}".format(fantray_index, fan_index_intray) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.fan_presence_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == '1'): + return True + else: + return False + + return None + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR' and attr_rv != '0.0'): + return True + else: + return False + else: + return False + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + attr_path = HWMON_DIR + self.fan_direction_attr + attr_rv = self.__get_attr_value(attr_path) + + if attr_rv == '2': + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + else: + return 0 + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 25 + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + + Args: + color: A string representing the color with which to set the + fan module status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return True + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..75e954576a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/fan_drawer.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/platform.py new file mode 100644 index 0000000000..8d20abef90 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +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): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/psu.py new file mode 100644 index 0000000000..60e0f29740 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/psu.py @@ -0,0 +1,316 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import logging + 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") + +HWMON_DIR = "/sys/class/hwmon/hwmon1/" + +class Psu(PsuBase): + def __init__(self, index): + PsuBase.__init__(self) + fan = Fan(index, True) + self._fan_list.append(fan) + + self.psu_index_mapping = { + 1:43, + 2:54, + } + self.psu_powerin_index_mapping = { + 1:42, + 2:53, + } + self.psu_currentout_index_mapping = { + 1:40, + 2:51, + } + self.psu_currentin_index_mapping = { + 1:39, + 2:50, + } + self.psu_voltageout_index_mapping = { + 1:48, + 2:59, + } + self.psu_voltagein_index_mapping = { + 1:47, + 2:58, + } + self.index = index + self.psu_presence_attr = "power{}_present".format(self.psu_index_mapping[self.index]) + self.psu_status_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_power_in_attr = "power{}_input".format(self.psu_powerin_index_mapping[self.index]) + self.psu_power_out_attr = "power{}_input".format(self.psu_index_mapping[self.index]) + self.psu_voltage_out_attr = "in{}_input".format(self.psu_voltageout_index_mapping[self.index]) + self.psu_current_out_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_voltage_in_attr = "in{}_input".format(self.psu_voltagein_index_mapping[self.index]) + self.psu_current_in_attr = "curr{}_input".format(self.psu_currentin_index_mapping[self.index]) + self.psu_serial_attr = "power{}_sn".format(self.psu_index_mapping[self.index]) + self.psu_model_attr = "power{}_model".format(self.psu_index_mapping[self.index]) + self.psu_mfr_id_attr = "power{}_mfrid".format(self.psu_index_mapping[self.index]) + self.psu_capacity_attr = "power{}_pout_max".format(self.psu_index_mapping[self.index]) + self.psu_type_attr = "power{}_vin_type".format(self.psu_index_mapping[self.index]) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + fd.close() + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = HWMON_DIR+self.psu_presence_attr + attr_normal = '1' + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = HWMON_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_mfr_id(self): + """ + Retrieves the manufacturer's name (or id) of the device + + Returns: + string: Manufacturer's id of device + """ + mfr_id = "N/A" + attr_path = HWMON_DIR+self.psu_mfr_id_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + mfr_id = attr_rv + + return mfr_id + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = HWMON_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = HWMON_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = HWMON_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_out = float(attr_rv) / 1000 + + return current_out + + def get_input_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_in = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_in = float(attr_rv) / 1000 + + return voltage_in + + def get_input_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_in = 0.0 + attr_path = HWMON_DIR+self.psu_current_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_in = float(attr_rv) / 1000 + + return current_in + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = HWMON_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + power_out = float(attr_rv) / 1000 + + return power_out + + 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. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + type = "AC" + attr_path = HWMON_DIR+self.psu_type_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + type = attr_rv + + return type + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + capacity = 0 + attr_path = HWMON_DIR+self.psu_capacity_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + capacity = int(attr_rv) + + return capacity + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/sfp.py new file mode 100644 index 0000000000..6679e96a7e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/sfp.py @@ -0,0 +1,1625 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +#import subprocess +#import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase +# from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_MODULE_THRESHOLD_OFFSET = 512 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 560 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +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_TYPE = "SFP" +QSFP_TYPE = "QSFP" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 56 + QSFP_START = 49 + QSFP_END = 56 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-quanta_ix8_rglbmc-r0" + HWSKU = "Quanta-IX8-56X" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + #self.dom_supported = False + self.sfp_type = sfp_type + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 1 : 17, + 2 : 18, + 3 : 19, + 4 : 20, + 5 : 21, + 6 : 22, + 7 : 23, + 8 : 24, + 9 : 25, + 10 : 26, + 11 : 27, + 12 : 28, + 13 : 29, + 14 : 30, + 15 : 31, + 16 : 32, + 17 : 33, + 18 : 34, + 19 : 35, + 20 : 36, + 21 : 37, + 22 : 38, + 23 : 39, + 24 : 40, + 25 : 41, + 26 : 42, + 27 : 43, + 28 : 44, + 29 : 45, + 30 : 46, + 31 : 47, + 32 : 48, + 33 : 49, + 34 : 50, + 35 : 51, + 36 : 52, + 37 : 53, + 38 : 54, + 39 : 55, + 40 : 56, + 41 : 57, + 42 : 58, + 43 : 59, + 44 : 60, + 45 : 61, + 46 : 62, + 47 : 63, + 48 : 64, + 49 : 65,#QSFP49 + 50 : 66,#QSFP50 + 51 : 67,#QSFP51 + 52 : 68,#QSFP52 + 53 : 69,#QSFP53 + 54 : 70,#QSFP54 + 55 : 71,#QSFP55 + 56 : 72,#QSFP56 + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self.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', 'vendor_date', + 'vendor_oui', 'application_advertisement'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', + 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the SFP module + Returns: + bool: True if SFP module is present, False if not + """ + # Check for invalid port_num + if self.port_num < self.PORT_START or self.port_num > self.PORT_END: + return False + + try: + if self.sfp_type == SFP_TYPE: + reg_file = open("/sys/class/cpld-sfp28/port-"+str(self.port_num)+"/pre_n") + else: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+34)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + reg_file.close() + if self.sfp_type == SFP_TYPE: + if reg_value == '1': + return True + else: + if reg_value == '0': + return True + + return False + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + eeprom_raw = None + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability = int(qsfp_dom_capability_raw[0], 16) + + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + if qsfp_version_compliance_raw is not None: + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qsfp_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qsfp_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qsfp_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + self.dom_tx_disable_supported = True + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ======================================================================== + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + if not self.get_presence(): + return transceiver_info_dict + + if self.sfp_type == QSFP_TYPE: + offset = QSFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == SFP_TYPE: + offset = SFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + else: + return transceiver_info_dict + + # Add retry for xcvr eeprom to get ready + max_retry = 10 + for i in range(0,max_retry): + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is not None: + break + else: + if not self.get_presence(): + return transceiver_info_dict + elif i == max_retry-1: + pass + else: + time.sleep(0.5) + + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + transceiver_info_dict['type'] = sfp_interface_bulk_data \ + ['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data \ + ['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data \ + ['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data \ + ['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data \ + ['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data \ + ['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data \ + ['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data \ + ['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data \ + ['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data \ + ['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data \ + ['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = 'N/A' + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = QSFP_DOM_OFFSET + offset_xcvr = QSFP_INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability_data = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qsfp_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + if not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + else: + return None + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + if not self.get_presence() or not sfpd_obj: + return {} + DOM_OFFSET = 0 + transceiver_dom_threshold_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + offset = DOM_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + module_threshold_values = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_channel_thres_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNEL_THRESHOLD_OFFSET), QSFP_CHANNEL_THRESHOLD_WIDTH) + if dom_channel_thres_raw is not None: + channel_threshold_values = sfpd_obj.parse_channel_threshold_values(dom_channel_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + else: + channel_threshold_data = None + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + DOM_OFFSET = 256 + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + else: + return None + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+32)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return True + else: + return False + else: + return None + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + else: + return None + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + else: + return None + + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + else: + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return 0 + elif self.sfp_type == QSFP_TYPE: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + else: + return None + + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this QSFP module + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+35)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return False + else: + return True + else: + return None + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_POWEROVERRIDE_OFFSET), QSFP_POWEROVERRIDE_WIDTH) + if dom_control_raw is not None: + if int(dom_control_raw[0],16) & (0x01 << QSFP_POWEROVERRIDE_BIT): + return True + else: + return False + else: + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( \ + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default state. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/direction", 'r+') as f: + f.write('out') + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/value", "r+") as f: + f.write('0') + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/value", "r+") as f: + f.write('1') + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + else: + return None + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + offset = 256 + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( + status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(offset + SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + else: + return None + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + else: + return False + else: + return None + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+35)+"/value", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + else: + return None + + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings(self.__get_path_to_port_config_file()) + print("self.index{}".format(self.index)) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/thermal.py new file mode 100644 index 0000000000..f2ba187547 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/thermal.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import logging +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +HWMON_DIR = "/sys/class/hwmon/hwmon1/" + +thermal_index_mapping = { + 1:44, + 2:45, + 3:46, + 4:55, + 5:56, + 6:57, + 7:70, + 8:71, + 9:72, + 10:73, + 11:74, + 12:75, + 13:76, + 14:77, + 15:78, +} + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index + self.temp_attr = "temp{}_input".format(thermal_index_mapping[self.index]) + self.high_th_attr = "temp{}_ncrit".format(thermal_index_mapping[self.index]) + self.high_crit_th_attr = "temp{}_crit".format(thermal_index_mapping[self.index]) + self.name_attr = "temp{}_label".format(thermal_index_mapping[self.index]) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return attr_rv + else: + return None + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if (self.get_temperature() != None): + return True + else: + return False + + 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 + """ + attr_path = HWMON_DIR + self.temp_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + 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 + """ + attr_path = HWMON_DIR + self.high_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + def get_high_critical_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 + """ + attr_path = HWMON_DIR + self.high_crit_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/watchdog.py new file mode 100644 index 0000000000..282f356f4e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform/watchdog.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python + +############################################################################# +# +# Watchdog contains an implementation of SONiC Platform Base Watchdog API +# +############################################################################# +import fcntl +import os +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +""" ioctl constants """ +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +""" Watchdog ioctl commands """ +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +""" Watchdog status constants """ +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +WDT_COMMON_ERROR = -1 +WD_MAIN_IDENTITY = "iTCO_wdt" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + +DEFAULT_TIMEOUT=180 + +class Watchdog(WatchdogBase): + + def __init__(self): + + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = DEFAULT_TIMEOUT + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WD_MAIN_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + self.watchdog = os.open(watchdog_device_path, os.O_RDWR) + return self.watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + return int(req[0]) + + def _gettimeout(self, timeout_path): + """ + Get watchdog timeout + @return watchdog timeout + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + ################################################################# + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of 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 , 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. + """ + + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._settimeout(seconds) + self._enable() + self.armed = True + ret = self.timeout + except IOError as e: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + Returns: + A boolean, True if watchdog is armed, False if not + """ + + return self.armed + + 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 thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + + os.close(self.watchdog) + + + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform_setup.py new file mode 100644 index 0000000000..1ec6ba4271 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/sonic_platform_setup.py @@ -0,0 +1,24 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Quanta Platforms', + license='Apache 2.0', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/utils/quanta_ix8_util.py b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/utils/quanta_ix8_util.py index fe93611b11..19dc24e370 100755 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/utils/quanta_ix8_util.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8-56x/utils/quanta_ix8_util.py @@ -21,19 +21,17 @@ Usage: %(scriptName)s [options] command object options: -h | --help : this help message -d | --debug : run with debug mode - -f | --force : ignore error during installation or clean + -f | --force : ignore error during installation or clean command: install : install drivers and generate related sysfs nodes - clean : uninstall drivers and remove related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes """ import os import commands import sys, getopt import logging -import re import time -from collections import namedtuple DEBUG = False args = [] @@ -43,72 +41,68 @@ i2c_prefix = '/sys/bus/i2c/devices/' if DEBUG == True: print sys.argv[0] - print 'ARGV :', sys.argv[1:] + print 'ARGV :', sys.argv[1:] def main(): global DEBUG global args global FORCE - + if len(sys.argv)<2: show_help() - + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', 'debug', 'force', ]) - if DEBUG == True: + if DEBUG == True: print options print args print len(sys.argv) - + for opt, arg in options: if opt in ('-h', '--help'): show_help() - elif opt in ('-d', '--debug'): + elif opt in ('-d', '--debug'): DEBUG = True logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): + elif opt in ('-f', '--force'): FORCE = 1 else: - logging.info('no option') - for arg in args: + logging.info('no option') + for arg in args: if arg == 'install': install() elif arg == 'clean': uninstall() else: show_help() - - - return 0 - + + + return 0 + def show_help(): print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} sys.exit(0) - + def show_log(txt): if DEBUG == True: print "[IX8-56X]"+txt return - + def exec_cmd(cmd, show): - logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) show_log (cmd +"with result:" + str(status)) - show_log (" output:"+output) + show_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: print('Failed :'+cmd) return status, output - + instantiate =[ -#turn on module power -'echo 21 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio21/direction', -'echo 1 >/sys/class/gpio/gpio21/value', #export pca9698 for qsfp present 'echo 34 > /sys/class/gpio/export', 'echo in > /sys/class/gpio/gpio34/direction', @@ -126,31 +120,6 @@ instantiate =[ 'echo in > /sys/class/gpio/gpio58/direction', 'echo 62 > /sys/class/gpio/export', 'echo in > /sys/class/gpio/gpio62/direction', -#export pca9698 for qsfp reset -'echo 32 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio32/direction', -'echo 1 >/sys/class/gpio/gpio32/value', -'echo 36 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio36/direction', -'echo 1 >/sys/class/gpio/gpio36/value', -'echo 40 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio40/direction', -'echo 1 >/sys/class/gpio/gpio40/value', -'echo 44 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio44/direction', -'echo 1 >/sys/class/gpio/gpio44/value', -'echo 48 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio48/direction', -'echo 1 >/sys/class/gpio/gpio48/value', -'echo 52 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio52/direction', -'echo 1 >/sys/class/gpio/gpio52/value', -'echo 56 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio56/direction', -'echo 1 >/sys/class/gpio/gpio56/value', -'echo 60 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio60/direction', -'echo 1 >/sys/class/gpio/gpio60/value', #export pca9698 for qsfp lpmode 'echo 35 > /sys/class/gpio/export', 'echo out > /sys/class/gpio/gpio35/direction', @@ -176,14 +145,6 @@ instantiate =[ 'echo 63 > /sys/class/gpio/export', 'echo out > /sys/class/gpio/gpio63/direction', 'echo 0 >/sys/class/gpio/gpio63/value', -#Reset fron-ports LED CPLD -'echo 73 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio73/direction', -'echo 0 >/sys/class/gpio/gpio73/value', -'echo 1 >/sys/class/gpio/gpio73/value', -#Enable front-ports LED decoding -'echo 1 > /sys/class/cpld-led/CPLDLED-1/led_decode', -'echo 1 > /sys/class/cpld-led/CPLDLED-2/led_decode', #SFP28 Module TxEnable 'echo 0 > /sys/class/cpld-sfp28/port-1/tx_dis', 'echo 0 > /sys/class/cpld-sfp28/port-2/tx_dis', @@ -246,27 +207,40 @@ drivers =[ 'lpc_ich', 'i2c-i801', 'i2c-dev', +'i2c-mux-pca954x force_deselect_on_exit=1', +'gpio-pca953x', +'optoe', +'qci_cpld_sfp28', +'qci_cpld_led', +'qci_platform_ix8', +'ipmi_devintf', +'quanta_hwmon_ipmi' +] + +un_drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', 'i2c-mux-pca954x', 'gpio-pca953x', 'optoe', 'qci_cpld_sfp28', 'qci_cpld_led', 'qci_platform_ix8', -'ipmi_devintf' +'ipmi_devintf', +'quanta_hwmon_ipmi' ] - - def system_install(): global FORCE - + #remove default drivers to avoid modprobe order conflicts - status, output = exec_cmd("echo 'blacklist i2c-ismt' > /etc/modprobe.d/blacklist.conf", 1) + exec_cmd("echo 'blacklist i2c-ismt' > /etc/modprobe.d/blacklist.conf", 1) time.sleep(1) - status, output = exec_cmd("modprobe -r i2c-ismt ", 1) - status, output = exec_cmd("modprobe -r i2c-i801 ", 1) + exec_cmd("modprobe -r i2c-ismt ", 1) + exec_cmd("modprobe -r i2c-i801 ", 1) #setup driver dependency - status, output = exec_cmd("depmod -a ", 1) + exec_cmd("depmod -a ", 1) #install drivers for i in range(0,len(drivers)): status, output = exec_cmd("modprobe "+drivers[i], 1) @@ -274,35 +248,62 @@ def system_install(): print output if FORCE == 0: return status - + + #turn on module power + exec_cmd("echo 21 > /sys/class/gpio/export ", 1) + exec_cmd("echo high > /sys/class/gpio/gpio21/direction ", 1) + + # qsfp reset gpio + time.sleep(1) + for qsfp_reset in [32, 36, 40, 44, 48, 52, 56, 60]: + exec_cmd("echo "+str(qsfp_reset)+" > /sys/class/gpio/export", 1) + exec_cmd("echo high > /sys/class/gpio/gpio"+str(qsfp_reset)+"/direction", 1) + + # Reset fron-ports LED CPLD + exec_cmd("echo 73 > /sys/class/gpio/export ", 1) + status, output = exec_cmd("cat /sys/class/gpio/gpio73/value", 1) + if output != '1': + exec_cmd("echo out > /sys/class/gpio/gpio73/direction ", 1) + exec_cmd("echo 0 >/sys/class/gpio/gpio73/value", 1) + exec_cmd("echo 1 >/sys/class/gpio/gpio73/value", 1) + #instantiate devices for i in range(0,len(instantiate)): - status, output = exec_cmd(instantiate[i], 1) + status, output = exec_cmd(instantiate[i], 1) if status: print output if FORCE == 0: return status - + #QSFP for 1~56 port for port_number in range(1,57): - bus_number = port_number + 31 + bus_number = port_number + 16 os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) - - return - - + + status, output = exec_cmd("pip3 install /usr/share/sonic/device/x86_64-quanta_ix8_rglbmc-r0/sonic_platform-1.0-py3-none-any.whl",1) + if status: + print output + if FORCE == 0: + return status + + #Enable front-ports LED decoding + exec_cmd('echo 1 > /sys/class/cpld-led/CPLDLED-1/led_decode', 1) + exec_cmd('echo 1 > /sys/class/cpld-led/CPLDLED-2/led_decode', 1) + + return + def system_ready(): - if not device_found(): + if not device_found(): return False return True - -def install(): + +def install(): if not device_found(): - print "No device, installing...." - status = system_install() + print "No device, installing...." + status = system_install() if status: - if FORCE == 0: - return status + if FORCE == 0: + return status else: print " ix8 driver already installed...." return @@ -310,17 +311,27 @@ def install(): def uninstall(): global FORCE #uninstall drivers - for i in range(len(drivers)-1,-1,-1): - status, output = exec_cmd("rmmod "+drivers[i], 1) + for i in range(len(un_drivers)-1,-1,-1): + status, output = exec_cmd("rmmod "+un_drivers[i], 1) if status: print output - if FORCE == 0: + if FORCE == 0: + return status + status, output = exec_cmd("pip3 uninstall sonic-platform -y ",1) + if status: + print output + if FORCE == 0: return status return def device_found(): - ret1, log = exec_cmd("ls "+i2c_prefix+"i2c-0", 0) - return ret1 + ret1, log1 = exec_cmd("cat /proc/modules | grep ix8 > /tmp/chkdriver.log", 0) + ret2, log2 = exec_cmd("cat /tmp/chkdriver.log | grep ix8", 0) + + if ret1 == 0 and len(log2) > 0: + return True + else: + return False if __name__ == "__main__": main() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/classes/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/classes/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/Makefile b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/Makefile new file mode 100644 index 0000000000..209ad8eaaf --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/Makefile @@ -0,0 +1 @@ +obj-m:=qci_cpld_sfp28.o qci_cpld_led.o qci_platform_ix8a_bwde.o quanta_hwmon_ipmi.o diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_cpld_led.c b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_cpld_led.c new file mode 100644 index 0000000000..9be8920f51 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_cpld_led.c @@ -0,0 +1,279 @@ +/* + * A LED CPLD driver for Quanta Switch Platform + * + * The CPLD is customize by Quanta for decode led bit stream, + * This driver modify from Quanta CPLD I/O driver. + * + * Copyright (C) 2015 Quanta Inc. + * + * Author: Luffy Cheng + * Author: Roger Chang + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDA(cpld_led_ida); + +enum platform_type { + IX7 = 0, + IX8A_BWDE, + NONE +}; + +static struct class *cpld_class = NULL; + +struct cpld_data { + struct i2c_client *cpld_client; + char name[8]; + u8 cpld_id; +}; + +struct cpld_led_data { + struct mutex lock; + struct device *port_dev; + struct cpld_data *cpld_data; +}; + +static int cpld_led_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int cpld_led_remove(struct i2c_client *client); + +static const struct i2c_device_id cpld_led_id[] = { + { "CPLDLED_IX7", IX7 }, + { "CPLDLED_IX8A_BWDE", IX8A_BWDE }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cpld_led_id); + +static struct i2c_driver cpld_led_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "qci_cpld_led", + }, + .probe = cpld_led_probe, + .remove = cpld_led_remove, + .id_table = cpld_led_id, +// .address_list = normal_i2c, +}; + +#define CPLD_LED_ID_PREFIX "CPLDLED-" +#define CPLD_LED_ID_FORMAT CPLD_LED_ID_PREFIX "%d" + +#define CPLD_DECODER_OFFSET 0x4 +#define CPLD_DECODER_MASK 0x1 +#define CPLD_USERCODE_START_OFFSET 0x0 + +static ssize_t get_led_decode(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 offset = (u8)(CPLD_DECODER_OFFSET); + s32 value; + + value = i2c_smbus_read_byte_data(client, offset); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read led decode value= %x\n", value); + + value &= CPLD_DECODER_MASK; + + return sprintf(buf, "%d\n", (value == 0) ? 1 : 0); +} + +static ssize_t get_usercode(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 i = 0; + s32 value = 0, reading = 0; + + for (i = 0; i < 4; i++) + { + reading = i2c_smbus_read_byte_data(client, CPLD_USERCODE_START_OFFSET + i); + if (reading < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read led usercode reg %d value= %x\n", i, reading); + + value |= reading << (24 - 8 * i); + } + + return sprintf(buf, "%X\n", value); +} + +static ssize_t set_led_decode(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct cpld_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + s32 value; + long enable; + + if (kstrtol(buf, 0, &enable)) + return -EINVAL; + + if ((enable != 1) && (enable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_byte_data(client, CPLD_DECODER_OFFSET); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read led decode value= %x\n", value); + + value |= CPLD_DECODER_MASK; + if (enable) + value &= ~CPLD_DECODER_MASK; + + dev_dbg(&client->dev, "write led decode value= %x\n", value); + + i2c_smbus_write_byte_data(client, CPLD_DECODER_OFFSET, (u8)value); +// mutex_unlock(&data->lock); + + return count; +} + +static DEVICE_ATTR(led_decode, S_IWUSR | S_IRUGO, get_led_decode, set_led_decode); +static DEVICE_ATTR(usercode, S_IRUGO, get_usercode, NULL); + +static const struct attribute *led_attrs[] = { + &dev_attr_usercode.attr, + &dev_attr_led_decode.attr, + NULL, +}; + +static const struct attribute_group led_attr_group = { + .attrs = (struct attribute **) led_attrs, +}; + +static int cpld_led_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cpld_led_data *data; + struct cpld_data *led_data; + struct device *port_dev; + int nr, err; + + if (!cpld_class) + { + cpld_class = class_create(THIS_MODULE, "cpld-led"); + if (IS_ERR(cpld_class)) { + pr_err("couldn't create sysfs class\n"); + return PTR_ERR(cpld_class); + } + } + + data = devm_kzalloc(&client->dev, sizeof(struct cpld_led_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* Test */ + nr = ida_simple_get(&cpld_led_ida, 1, 99, GFP_KERNEL); + if (nr < 0) + goto err_out; + + led_data = kzalloc(sizeof(struct cpld_led_data), GFP_KERNEL); + + port_dev = device_create(cpld_class, &client->dev, MKDEV(0,0), led_data, CPLD_LED_ID_FORMAT, nr); + if (IS_ERR(port_dev)) { + err = PTR_ERR(port_dev); + // printk("err_status\n"); + } + + data->port_dev = port_dev; + data->cpld_data = led_data; + + dev_info(&client->dev, "Register CPLDLED %d\n", nr); + + sprintf(led_data->name, "LED%d-data", nr); + led_data->cpld_id = nr; + dev_set_drvdata(port_dev, led_data); + port_dev->init_name = led_data->name; + led_data->cpld_client = client; + + err = sysfs_create_group(&port_dev->kobj, &led_attr_group); + // if (status) printk("err status\n"); + /* end */ + + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + dev_info(&client->dev, "%s device found\n", client->name); + + + return 0; + +err_out: + return nr; +} + +/* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if 0 +static int idr_has_entry(int id, void *p, void *data) +{ + return 1; +} + +static bool cpld_idr_is_empty(struct idr *idp) +{ + return !idr_for_each(idp, idr_has_entry, NULL); +} +#endif + +static int cpld_led_remove(struct i2c_client *client) +{ + struct cpld_led_data *data = i2c_get_clientdata(client); + + dev_info(data->port_dev, "Remove CPLDLED-%d\n", data->cpld_data->cpld_id); + device_unregister(data->port_dev); + ida_simple_remove(&cpld_led_ida, data->cpld_data->cpld_id); + kfree(data->cpld_data); + + if (ida_is_empty(&cpld_led_ida)) { + class_destroy(cpld_class); + cpld_class = NULL; + } + + return 0; +} + +module_i2c_driver(cpld_led_driver); + +MODULE_AUTHOR("Luffy Cheng "); +MODULE_AUTHOR("Roger Chang "); +MODULE_DESCRIPTION("Quanta Switch LED CPLD driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_cpld_sfp28.c b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_cpld_sfp28.c new file mode 100644 index 0000000000..a36bdf94bc --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_cpld_sfp28.c @@ -0,0 +1,381 @@ +/* + * A CPLD driver for monitor SFP28 module I/O + * + * The CPLD is customize by Quanta for controlling SFP28 module signals, + * they are TX_FAULT , TX_DIS , PRE_N , RX_LOS + * Each CPLD control 16 modules, each module use 4 bits in register. + * + * Copyright (C) 2015 Quanta Inc. + * + * Author: Luffy Cheng + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static DEFINE_IDA(cpld_ida); + +enum platform_type { + SFP = 0, + SFP28, + NONE +}; + +static struct class *cpld_class = NULL; + +struct sfp_data { + struct i2c_client *cpld_client; + char name[8]; + u8 port_id; + u8 cpld_port; +}; + +struct cpld_data { + struct mutex lock; + struct device *port_dev[16]; + struct sfp_data *port_data[16]; +}; + +static int cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id); +static int cpld_remove(struct i2c_client *client); + +static const struct i2c_device_id cpld_id[] = { + { "CPLD-SFP", SFP }, + { "CPLD-SFP28", SFP28 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, cpld_id); + +static struct i2c_driver cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "qci_cpld_sfp28", + }, + .probe = cpld_probe, + .remove = cpld_remove, + .id_table = cpld_id, +// .address_list = normal_i2c, +}; + +#define CPLD_ID_PREFIX "port-" +#define CPLD_ID_FORMAT CPLD_ID_PREFIX "%d" + +//SFP28 +#define TX_FAULT_MASK 0x08 +#define TX_DIS_MASK 0x04 +#define PRE_N_MASK 0x02 +#define RX_LOS_MASK 0x01 + +static inline u8 get_group_cmd(u8 group) +{ + //FIXME: if group cmd change + return (group + 1); +} + +static inline u8 port_remapping(u8 phy_port) +{ + /* FIXME: implement by hardware design */ + /* The CPLD register port mapping is weird : + * MSB -------- LSB (word data) + * P3 P4 P1 P2 (per port 4 bits) + * For easy coding bit shift, we treat it as hw port swap + */ + return (phy_port % 2) ? (phy_port - 1) : (phy_port + 1); +} + +//SFP +static ssize_t get_tx_fault(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= TX_FAULT_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t get_tx_dis(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= TX_DIS_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} + +static ssize_t get_pre_n(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= PRE_N_MASK; + + //FIXME: if present is not low active + return sprintf(buf, "%d\n", value ? 0 : 1); +} + +static ssize_t get_rx_los(struct device *dev, + struct device_attribute *devattr, + char *buf) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value >>= (group_port * 4); + value &= RX_LOS_MASK; + + return sprintf(buf, "%d\n", value ? 1 : 0); +} +static ssize_t set_tx_dis(struct device *dev, + struct device_attribute *devattr, + const char *buf, + size_t count) +{ + struct sfp_data *data = dev_get_drvdata(dev); + struct i2c_client *client = data->cpld_client; + u8 group = (u8)(data->cpld_port / 4); + u8 group_port = data->cpld_port % 4; + s32 value; + long disable; + + dev_dbg(&client->dev, "port_id %d => cpld_port %d, group %d(%d)\n", data->port_id, + data->cpld_port + 1, group + 1, group_port + 1); + + if (kstrtol(buf, 0, &disable)) + return -EINVAL; + + if ((disable != 1) && (disable != 0)) + return -EINVAL; + +// mutex_lock(&data->lock); + value = i2c_smbus_read_word_data(client, get_group_cmd(group)); + if (value < 0) + return -ENODEV; + + dev_dbg(&client->dev, "read group%d value= %x\n", group + 1, value); + + value &= ~(TX_DIS_MASK << (group_port * 4)); + if (disable) + value |= (TX_DIS_MASK << (group_port * 4)); + + dev_dbg(&client->dev, "write group%d value= %x\n", group + 1, value); + + i2c_smbus_write_word_data(client, get_group_cmd(group), (u16)value); +// mutex_unlock(&data->lock); + + return count; +} +//SFP + +//SFP +static DEVICE_ATTR(tx_fault, S_IRUGO, get_tx_fault, NULL); +static DEVICE_ATTR(tx_dis, S_IWUSR | S_IRUGO, get_tx_dis, set_tx_dis); +static DEVICE_ATTR(pre_n, S_IRUGO, get_pre_n, NULL); +static DEVICE_ATTR(rx_los, S_IRUGO, get_rx_los, NULL); + +static const struct attribute *sfp_attrs[] = { + &dev_attr_tx_fault.attr, + &dev_attr_tx_dis.attr, + &dev_attr_pre_n.attr, + &dev_attr_rx_los.attr, + NULL, +}; + +static const struct attribute_group sfp_attr_group = { + .attrs = (struct attribute **) sfp_attrs, +}; + +static int cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cpld_data *data; + struct sfp_data *port_data; + struct device *port_dev; + int port_nr, i=0, err; + + printk("cpld cpld_probe\n"); + + if (!cpld_class) + { + cpld_class = class_create(THIS_MODULE, "cpld-sfp28"); + if (IS_ERR(cpld_class)) { + pr_err("couldn't create sysfs class\n"); + return PTR_ERR(cpld_class); + } + } + + data = devm_kzalloc(&client->dev, sizeof(struct cpld_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + /* register sfp port data to sysfs */ + for (i = 0; i < 16; i++) + { + port_nr = ida_simple_get(&cpld_ida, 1, 99, GFP_KERNEL); + if (port_nr < 0) + goto err_out; + + port_data = kzalloc(sizeof(struct sfp_data), GFP_KERNEL); + + port_dev = device_create(cpld_class, &client->dev, MKDEV(0,0), port_data, CPLD_ID_FORMAT, port_nr); + if (IS_ERR(port_dev)) { + err = PTR_ERR(port_dev); + printk("err_status\n"); + } + + data->port_dev[i] = port_dev; + data->port_data[i] = port_data; + + dev_info(&client->dev, "Register port-%d\n", port_nr); + + /* FIXME: implement Logical/Physical port remapping */ + //port_data->cpld_port = i; + port_data->cpld_port = port_remapping(i); + sprintf(port_data->name, "port-%d", port_nr); + port_data->port_id = port_nr; + dev_set_drvdata(port_dev, port_data); + port_dev->init_name = port_data->name; + port_data->cpld_client = client; + + err = sysfs_create_group(&port_dev->kobj, &sfp_attr_group); + // if (status) printk("err status\n"); + } + + i2c_set_clientdata(client, data); + mutex_init(&data->lock); + + dev_info(&client->dev, "%s device found\n", client->name); + + + return 0; + +err_out: + return port_nr; +} + +/* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if 0 +static int idr_has_entry(int id, void *p, void *data) +{ + return 1; +} + +static bool cpld_idr_is_empty(struct idr *idp) +{ + return !idr_for_each(idp, idr_has_entry, NULL); +} +#endif + +static int cpld_remove(struct i2c_client *client) +{ + struct cpld_data *data = i2c_get_clientdata(client); + int i; + + for (i = 15; i >= 0; i--) + { + dev_info(data->port_dev[i], "Remove port-%d\n", data->port_data[i]->port_id); + device_unregister(data->port_dev[i]); + ida_simple_remove(&cpld_ida, data->port_data[i]->port_id); + kfree(data->port_data[i]); + } + + if (ida_is_empty(&cpld_ida)) + { + class_destroy(cpld_class); + cpld_class = NULL; + } + + return 0; +} + +module_i2c_driver(cpld_driver); + +MODULE_AUTHOR("Luffy Cheng "); +MODULE_DESCRIPTION("Quanta Switch SFP28 CPLD driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_platform_ix8a_bwde.c b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_platform_ix8a_bwde.c new file mode 100644 index 0000000000..e5f6a6529d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/qci_platform_ix8a_bwde.c @@ -0,0 +1,372 @@ +/* + * Quanta ix8a_bwde platform driver + * + * + * Copyright (C) 2014 Quanta Computer inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE > KERNEL_VERSION(3,12,0) +#include +#else +#include +#endif + +static struct pca953x_platform_data pca9539_1_data = { + .gpio_base = 0x10, +}; + +static struct pca953x_platform_data pca9698_data = { + .gpio_base = 0x20, +}; +//CPU Linking Board at CPU's I2C Bus +static struct pca953x_platform_data pca9555_CPU_data = { + .gpio_base = 0x48, +}; + +static struct i2c_board_info ix8a_bwde_i2c_devices[] = { + { + I2C_BOARD_INFO("pca9546", 0x72), // 0 + }, + { + I2C_BOARD_INFO("pca9548", 0x77), // 1 + }, + { + I2C_BOARD_INFO("pca9539", 0x74), // 2 + .platform_data = &pca9539_1_data, + }, + { + I2C_BOARD_INFO("24c02", 0x54), // 3 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 4 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 5 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 6 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 7 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 8 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 9 + }, + { + I2C_BOARD_INFO("pca9548", 0x73), // 10 + }, + { + I2C_BOARD_INFO("CPLD-SFP28", 0x38), // 11 + }, + { + I2C_BOARD_INFO("CPLD-SFP28", 0x38), // 12 + }, + { + I2C_BOARD_INFO("CPLD-SFP28", 0x38), // 13 + }, + { + I2C_BOARD_INFO("pca9698", 0x21), + .platform_data = &pca9698_data, // 14 + }, + { + I2C_BOARD_INFO("optoe1", 0x50), // 15 0x50 QSFP EEPROM + }, + { + I2C_BOARD_INFO("pca9555", 0x22), // 16 CPU Linking Board at CPU's I2C Bus + .platform_data = &pca9555_CPU_data, + }, + { + I2C_BOARD_INFO("CPLDLED_IX8A_BWDE", 0x3a), // 17 0x72 ch0 CPLD4 LED function of SFP28 & QSFP28 (Port27~56) + }, + { + I2C_BOARD_INFO("CPLDLED_IX8A_BWDE", 0x39), // 18 0x72 ch0 CPLD6 LED function of SFP28 & QSFP28 (Port1~26) + }, + { + I2C_BOARD_INFO("optoe2", 0x50), // 19 0x50 SFP28 EEPROM + }, +}; + +static struct platform_driver ix8a_bwde_platform_driver = { + .driver = { + .name = "qci-ix8a-bwde", + .owner = THIS_MODULE, + }, +}; + +static struct platform_device *ix8a_bwde_device; + +static struct i2c_client **g_client; +static struct i2c_client **g_client_port; +int numof_i2c_devices = 18; // num of ix8a_bwde_i2c_devices - 2 (for optoe1, optoe2) +int numof_ports = 56; + +static int __init ix8a_bwde_platform_init(void) +{ + struct i2c_adapter *adapter; + int ret, i; + + ret = platform_driver_register(&ix8a_bwde_platform_driver); + if (ret < 0) + return ret; + + /* Register platform stuff */ + ix8a_bwde_device = platform_device_alloc("qci-ix8a_bwde", -1); + if (!ix8a_bwde_device) { + ret = -ENOMEM; + goto fail_platform_driver; + } + + ret = platform_device_add(ix8a_bwde_device); + if (ret) + goto fail_platform_device; + + g_client = kmalloc(sizeof(*g_client) * numof_i2c_devices, GFP_KERNEL); + for (i = 0; i < numof_i2c_devices; i++) g_client[i] = NULL; + + g_client_port = kmalloc(sizeof(*g_client_port) * numof_ports, GFP_KERNEL); + for (i = 0; i < numof_ports; i++) g_client_port[i] = NULL; + + adapter = i2c_get_adapter(0); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[0] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[0]); // pca9546_1 + g_client[1] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[1]); // pca9548_1 + g_client[2] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[16]); // CPU Linking Board at CPU's I2C Bus // + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x01); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[3] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[11]); // CPLD_1 + g_client[4] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[17]); // CPLD_4 // + g_client[5] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[18]); // CPLD_6 // + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x02); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[6] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[12]); // CPLD_2 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x03); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[7] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[13]); // CPLD_3 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x04); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[8] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[2]); // pca9539_1 + g_client[9] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[14]); // pca9698_QSFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x05); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[10] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[4]); // pca9548_1 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x06); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[11] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[5]); // pca9548_2 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x07); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[12] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[6]); // pca9548_3 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x08); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[13] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[7]); // pca9548_4 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x09); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[14] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[8]); // pca9548_5 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x0a); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[15] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[9]); // pca9548_6 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x0b); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[16] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[10]); // pca9548_7 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x03); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[17] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[3]); // eeprom + i2c_put_adapter(adapter); + } + + for(i = 13; i < 69; i ++){ + adapter = i2c_get_adapter(i); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + if (i < 61) // SFP28 1~48 EEPROM + g_client_port[i - 13] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[19]); + else // QSFP 49~56 EEPROM + g_client_port[i - 13] = i2c_new_device(adapter, &ix8a_bwde_i2c_devices[15]); + i2c_put_adapter(adapter); + } + } + + return 0; + +fail_platform_device: + platform_device_put(ix8a_bwde_device); + +fail_platform_driver: + platform_driver_unregister(&ix8a_bwde_platform_driver); + return ret; +} + +static void __exit ix8a_bwde_platform_exit(void) +{ + int i = 0; + + for (i = numof_ports - 1; i >= 0; i--) + { + if (g_client_port[i]) + { + i2c_unregister_device(g_client_port[i]); + g_client_port[i] = NULL; + } + } + + for (i = numof_i2c_devices - 1; i >= 0; i--) + { + if (g_client[i]) + { + i2c_unregister_device(g_client[i]); + g_client[i] = NULL; + } + } + + platform_device_unregister(ix8a_bwde_device); + platform_driver_unregister(&ix8a_bwde_platform_driver); +} + +module_init(ix8a_bwde_platform_init); +module_exit(ix8a_bwde_platform_exit); + + +MODULE_AUTHOR("Robert Hong (robert.hong@qct.io)"); +MODULE_DESCRIPTION("Quanta ix8a-bwde Platform Driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/quanta_hwmon_ipmi.c b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/quanta_hwmon_ipmi.c new file mode 100644 index 0000000000..65517e5d91 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/modules/quanta_hwmon_ipmi.c @@ -0,0 +1,1814 @@ +/* +* +* A hwmon driver for the Quanta switch BMC hwmon +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define enable_debug_msg 0 +#define DEBUGUSE_SHIFT 0 + +#define DRVNAME "quanta_hwmon_ipmi" + +#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & (1<<((bits)-1))) | (val)) : (val)) +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) +#define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) +#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & 0xff000000) >> 24) | ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) +#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4), 4)) +#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) + +#define SENSOR_ATTR_MAX 17 +#define SENSOR_ATTR_NAME_LENGTH 20 + +#define SENSOR_GET_CAP_LABEL 0x001 +#define SENSOR_GET_CAP_ALARM 0x002 +#define SENSOR_GET_CAP_INPUT 0x004 + +#define SENSOR_GET_CAP_LNC 0x008 +#define SENSOR_GET_CAP_LCR 0x010 +#define SENSOR_GET_CAP_LNR 0x020 + +#define SENSOR_GET_CAP_UNC 0x040 +#define SENSOR_GET_CAP_UCR 0x080 +#define SENSOR_GET_CAP_UNR 0x100 + +#define SENSOR_GET_CAP_MODEL 0x200 +#define SENSOR_GET_CAP_SN 0x400 +#define SENSOR_GET_CAP_PWM 0x800 + +#define SENSOR_GET_CAP_CONMODE 0x1000 +#define SENSOR_GET_CAP_DIRECTION 0x2000 +#define SENSOR_GET_CAP_FAN_PRESENT 0x4000 +#define SENSOR_GET_CAP_PSU_PRESENT 0x8000 + +#define SENSOR_GET_CAP_MFRID 0x10000 + +#define SDR_SENSOR_TYPE_TEMP 0x01 +#define SDR_SENSOR_TYPE_VOLT 0x02 +#define SDR_SENSOR_TYPE_CURR 0x03 +#define SDR_SENSOR_TYPE_FAN 0x04 +#define SDR_SENSOR_TYPE_PS 0x08 +#define SDR_SENSOR_TYPE_OTHER 0x0b + +#define BMC_GET_DEVICE_ID 0x01 + +#define IPMI_NETFN_SE 0x04 +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_STORAGE 0x0a +#define IPMI_NETFN_TSOL 0x30 + +#define GET_SDR_REPO_INFO 0x20 +#define GET_DEVICE_SDR 0x21 +#define GET_SDR_RESERVE_REPO 0x22 +#define GET_SDR 0x23 +#define GET_SENSOR_THRESHOLDS 0x27 +#define GET_SENSOR_EVENT_ENABLE 0x29 +#define GET_SENSOR_EVENT_STATUS 0x2b +#define GET_SENSOR_READING 0x2d +#define GET_PSU_READING 0x52 +#define GET_FAN_INFO 0xd6 +#define GET_FRU_INFO 0x11 + +#define IPM_DEV_DEVICE_ID_SDR_MASK (0x80) /* 1 = provides SDRs */ +#define IPMI_TIMEOUT (4 * HZ) +#define IPMI_MAX_WAIT_QUEUE 1 + +struct quanta_hwmon_ipmi_data +{ + struct platform_device *ipmi_platform_dev; + struct device *ipmi_hwmon_dev; + /*struct mutex ipmi_lock; */ + + int32_t total_sensor_id; + int32_t total_suport_sensor; + int32_t total_create_sysfs; +} *data; + +static struct mutex ipmi_lock; +static struct completion g_read_complete; + +static ipmi_user_t ipmi_mh_user = NULL; + +static int8_t g_fan_control_mode = 3; +static int32_t g_use_built_in = 0; +static int32_t ipmi_wait_queue = 0; + +struct ipmi_sensor_data +{ + uint8_t addr; + uint8_t sensor_type; + uint8_t sensor_idstring[SENSOR_ATTR_NAME_LENGTH]; + + uint32_t capability; + + struct header_info + { + uint8_t header_type; + uint8_t header_byte; + } headerinfo; + + struct record_info + { + uint8_t record_analog; + uint8_t record_linearization; + + int32_t record_m; + int32_t record_b; + int32_t record_k1; + int32_t record_k2; + } recordinfo; + + struct threshold_upper_info + { + uint8_t unr; + uint8_t ucr; + uint8_t unc; + } upperinfo; + + struct threshold_lower_info + { + uint8_t lnr; + uint8_t lcr; + uint8_t lnc; + } lowerinfo; + + struct attr_info + { + bool attr_exist; + char attr_name[SENSOR_ATTR_MAX][SENSOR_ATTR_NAME_LENGTH]; + char attr_type_str[SENSOR_ATTR_NAME_LENGTH]; + + struct attribute *attrs[SENSOR_ATTR_MAX + 1]; + struct attribute_group attr_group; + struct sensor_device_attribute sd_attrs[SENSOR_ATTR_MAX + 1]; + } attrinfo; + +} *g_sensor_data; + +struct ipmi_comm_data +{ + int32_t tx_id; + + int32_t rx_result; + int64_t rx_len; + void *rx_data; + struct completion *rx_read_complete; +}; + +struct ipmi_sdr_iterator +{ + uint16_t reservation; + int32_t total; + int32_t next; +}; + +struct ipm_devid_rsp +{ + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +} __attribute__((packed)); + +struct sdr_repo_info_rs +{ + uint8_t version; /* SDR version (51h) */ + uint16_t count; /* number of records */ + uint16_t free; /* free space in SDR */ + uint32_t add_stamp; /* last add timestamp */ + uint32_t erase_stamp; /* last del timestamp */ + uint8_t op_support; /* supported operations */ +} __attribute__((packed)); + +struct sdr_device_info_rs +{ + uint8_t count; /* number of records */ + uint8_t flags; /* flags */ + uint8_t popChangeInd[3]; /* free space in SDR */ +} __attribute__((packed)); + +struct sdr_get_rs +{ + uint16_t next; /* next record id */ + uint16_t id; /* record ID */ + uint8_t version; /* SDR version (51h) */ +#define SDR_RECORD_TYPE_FULL_SENSOR 0x01 +#define SDR_RECORD_TYPE_COMPACT_SENSOR 0x02 +#define SDR_RECORD_TYPE_EVENTONLY_SENSOR 0x03 +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC 0x09 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 +#define SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR 0x11 +#define SDR_RECORD_TYPE_MC_DEVICE_LOCATOR 0x12 +#define SDR_RECORD_TYPE_MC_CONFIRMATION 0x13 +#define SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO 0x14 +#define SDR_RECORD_TYPE_OEM 0xc0 + uint8_t type; /* record type */ + uint8_t length; /* remaining record bytes */ +} __attribute__((packed)); + +struct sdr_get_rq +{ + uint16_t reserve_id; /* reservation ID */ + uint16_t id; /* record ID */ + uint8_t offset; /* offset into SDR */ +#define GET_SDR_ENTIRE_RECORD 0xff + uint8_t length; /* length to read */ +} __attribute__((packed)); + +struct entity_id +{ + uint8_t id; /* physical entity id */ +#ifdef WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} __attribute__((packed)); + +struct sdr_record_mask +{ + union + { + struct + { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event mask */ + uint16_t read; /* discrete reading mask */ + } discrete; + struct + { +#ifdef WORDS_BIGENDIAN + uint16_t reserved : 1; + uint16_t status_lnr : 1; + uint16_t status_lcr : 1; + uint16_t status_lnc : 1; + uint16_t assert_unr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lnc_low : 1; +#else + uint16_t assert_lnc_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_unr_high : 1; + uint16_t status_lnc : 1; + uint16_t status_lcr : 1; + uint16_t status_lnr : 1; + uint16_t reserved : 1; +#endif +#ifdef WORDS_BIGENDIAN + uint16_t reserved_2 : 1; + uint16_t status_unr : 1; + uint16_t status_ucr : 1; + uint16_t status_unc : 1; + uint16_t deassert_unr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lnc_low : 1; +#else + uint16_t deassert_lnc_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_unr_high : 1; + uint16_t status_unc : 1; + uint16_t status_ucr : 1; + uint16_t status_unr : 1; + uint16_t reserved_2 : 1; +#endif + union + { + struct + { +#ifdef WORDS_BIGENDIAN /* settable threshold mask */ + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; + /* padding lower 8 bits */ + uint16_t readable : 8; +#else + uint16_t readable : 8; + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; +#endif + } set; + struct + { +#ifdef WORDS_BIGENDIAN /* readable threshold mask */ + /* padding upper 8 bits */ + uint16_t settable : 8; + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; +#else + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; + uint16_t settable : 8; +#endif + } read; + }; + } threshold; + } type; +} __attribute__((packed)); + +struct sdr_record_full_sensor +{ + struct + { + uint8_t owner_id; +#ifdef WORDS_BIGENDIAN + uint8_t channel : 4; /* channel number */ + uint8_t __reserved : 2; + uint8_t lun : 2; /* sensor owner lun */ +#else + uint8_t lun : 2; /* sensor owner lun */ + uint8_t __reserved : 2; + uint8_t channel : 4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } keys; + + struct entity_id entity; + + struct + { + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 1; + uint8_t scanning : 1; + uint8_t events : 1; + uint8_t thresholds : 1; + uint8_t hysteresis : 1; + uint8_t type : 1; + uint8_t event_gen : 1; + uint8_t sensor_scan : 1; +#else + uint8_t sensor_scan : 1; + uint8_t event_gen : 1; + uint8_t type : 1; + uint8_t hysteresis : 1; + uint8_t thresholds : 1; + uint8_t events : 1; + uint8_t scanning : 1; + uint8_t __reserved : 1; +#endif + } init; + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t ignore : 1; + uint8_t rearm : 1; + uint8_t hysteresis : 2; + uint8_t threshold : 2; + uint8_t event_msg : 2; +#else + uint8_t event_msg : 2; + uint8_t threshold : 2; + uint8_t hysteresis : 2; + uint8_t rearm : 1; + uint8_t ignore : 1; +#endif + } capabilities; + uint8_t type; + } sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t analog : 2; + uint8_t rate : 3; + uint8_t modifier : 2; + uint8_t pct : 1; +#else + uint8_t pct : 1; + uint8_t modifier : 2; + uint8_t rate : 3; + uint8_t analog : 2; +#endif + struct + { + uint8_t base; + uint8_t modifier; + } type; + } unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct + { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 5; + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t nominal_read : 1; /* nominal reading field specified */ +#else + uint8_t nominal_read : 1; /* nominal reading field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t __reserved : 5; +#endif + } analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct + { + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } upper; + struct + { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } lower; + struct + { + uint8_t positive; + uint8_t negative; + } hysteresis; + } threshold; + uint8_t __reserved[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} __attribute__((packed)); + +int32_t pow_convert(int32_t *a, int32_t b) +{ + /* function input parameter (a * 10 ^ b) */ + int32_t i = 0, r = 1, temp_b = 0; + + temp_b = (b > 0) ? b : -b; + + for (i = 0; i < temp_b; i++) + { + r = r * 10; + } + + if (b > 0) + { + *a = (*a) * r; + r = 1; + } + /* function return parameter calc_result = *a, decimal_point = r */ + return r; +} + +void simple_atoi(const char *buf, int8_t *output_val) +{ + while (*buf >= '0' && *buf <= '9') + { + *output_val = *output_val * 10 + *buf - '0'; + buf++; + } +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) +{ + int32_t rv = -IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + struct ipmi_comm_data *comm_data = msg->user_msg_data; + + ipmi_wait_queue--; + + if (msg->msg.data[0] != 0) + { + if ((msg->msg.data[0] != 0x83) && (msg->msg.netfn != 0x07) + && (msg->msg.cmd != 0x52)) + { + /*skip master r/w cmd return code */ + printk("ipmi: Error 0x%x on cmd 0x%x/0x%x\n", msg->msg.data[0], msg->msg.netfn, + msg->msg.cmd); + rv = msg->msg.data[0]; + goto get_BMC_response_fail; + } + } + + if (msg->msgid != comm_data->tx_id) + { + printk("ipmi: rx msgid %d mismatch tx msgid %d\n", (int32_t)msg->msgid, + comm_data->tx_id); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len <= 0) + { + printk("ipmi: Data len too low (%d)\n", msg->msg.data_len); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len > 1) + { + if (comm_data->rx_len) + { + comm_data->rx_len = msg->msg.data_len - 1; + memcpy(comm_data->rx_data, msg->msg.data + 1, comm_data->rx_len); + } + else + { + printk("ipmi: rx len = 0, it should be not retrun ?\n"); + goto get_BMC_response_fail; + } + } + + rv = 0; + +get_BMC_response_fail: + ipmi_free_recv_msg(msg); + + if (ipmi_wait_queue == 0) + { + comm_data->rx_result = rv; + if (rv == 0) + { + complete(comm_data->rx_read_complete); + } + } +} +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_msg_handler, }; + +int32_t ipmi_request_wait_for_response(struct kernel_ipmi_msg msg, + struct ipmi_comm_data *comm_data) +{ + int32_t rv = 0; + int32_t escape_time = 0; + + struct ipmi_addr ipmi_address; + + if (ipmi_wait_queue >= IPMI_MAX_WAIT_QUEUE) + { + /* printk("msg queue full, cannot send ipmi cmd\n"); */ + return -EBUSY; + } + ipmi_wait_queue++; + + ipmi_address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi_address.channel = IPMI_BMC_CHANNEL; + ipmi_address.data[0] = 0; + + rv = ipmi_validate_addr(&ipmi_address, sizeof(ipmi_address)); + if (rv) + { + printk("ipmi_validate_addr fail, err code : %d\n", rv); + return rv; + } + + ipmi_request_settime(ipmi_mh_user, &ipmi_address, comm_data->tx_id, &msg, + comm_data, 0, 0, 0); + + escape_time = wait_for_completion_timeout(comm_data->rx_read_complete, + IPMI_TIMEOUT); + + rv = comm_data->rx_result; + if (escape_time == 0) + { + printk("BMC not response (%d)\n", escape_time); + } + + return rv; +} + +int32_t ipmi_send_system_cmd(uint8_t *msg_tx_data, int32_t msg_tx_len, + void *msg_rx_data, int32_t msg_rx_len) +{ + int32_t i = 0; + int32_t rv = 0; + + static uint64_t tx_msgid = 1; + + struct kernel_ipmi_msg msg; + struct ipmi_comm_data *comm_data = NULL; + struct completion read_complete; + + init_completion(&read_complete); + + /* prepare transfer message */ + msg.netfn = msg_tx_data[0]; + msg.cmd = msg_tx_data[1]; + msg.data_len = msg_tx_len - 2; + + msg.data = kzalloc(msg.data_len, GFP_KERNEL); + if (msg.data == NULL) + { + printk("%s(%d): malloc [msg.data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + comm_data = kzalloc(sizeof(struct ipmi_comm_data), GFP_KERNEL); + if (comm_data == NULL) + { + printk("%s(%d): malloc [comm_data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + for (i = 2; i < msg_tx_len; i++) + { + msg.data[i - 2] = msg_tx_data[i]; + } + + comm_data->tx_id = tx_msgid++; + + /* prepare recive message */ + comm_data->rx_data = msg_rx_data; + comm_data->rx_len = msg_rx_len; + comm_data->rx_result = -1; + comm_data->rx_read_complete = &read_complete; + + rv = ipmi_request_wait_for_response(msg, comm_data); + +alloc_mem_fail: + if (msg.data) + { + kfree(msg.data); + } + if (comm_data) + { + kfree(comm_data); + } + if (tx_msgid > UINT_MAX) + { + tx_msgid = 1; + } + + return rv; +} + +int32_t ipmi_sdr_get_reservation(uint16_t *reserve_id) +{ + int32_t rv = 0; + uint8_t msg_data[] = { 0x00, GET_SDR_RESERVE_REPO }; /*netfn = 0x00; cmd = GET_SDR_RESERVE_REPO; */ + + msg_data[0] = (g_use_built_in == 0) ? IPMI_NETFN_STORAGE : IPMI_NETFN_SE; + + /* obtain reservation ID */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), reserve_id, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + +#if enable_debug_msg + printk("SDR reservation ID %04x\n", *reserve_id); +#endif + + return rv; +} + +int32_t ipmi_sdr_start(struct ipmi_sdr_iterator *itr) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { IPMI_NETFN_APP, BMC_GET_DEVICE_ID }; /*netfn = IPMI_NETFN_APP; cmd = BMC_GET_DEVICE_ID; */ + + struct ipm_devid_rsp devid; + + /* check SDRR capability */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &devid, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return rv; + } + + if (devid.device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) + { + if ((devid.adtl_device_support & 0x02) == 0) + { + if ((devid.adtl_device_support & 0x01)) + { + printk("Using Device SDRs\n"); + g_use_built_in = 1; + } + else + { + printk("Error obtaining SDR info\n"); + } + } + } + + if (g_use_built_in == 0) + { + struct sdr_repo_info_rs sdr_info; + /* get sdr repository info */ + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + +#if enable_debug_msg + printk("SDR version: 0x%x\n", sdr_info.version); + printk("SDR free space: %d\n", sdr_info.free); +#endif + } + else + { + struct sdr_device_info_rs sdr_info; + /* get device sdr info */ + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + } + +#if enable_debug_msg + printk("SDR records : %d\n", sdr_info.count); +#endif + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + itr->next = 0; + rv = ipmi_sdr_get_reservation(&(itr->reservation)); + } + + return rv; +} + +int32_t ipmi_sdr_get_header(struct ipmi_sdr_iterator *itr, + struct sdr_get_rs *sdr_rs) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = itr->next; + sdr_rq.offset = 0; + sdr_rq.length = 5; /* only get the header */ + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), sdr_rs, 1); + if ((rv) || (sdr_rs->length == 0)) + { + printk("SDR record id 0x%04x: invalid length %d", itr->next, sdr_rs->length); + return -1; + } + + if (sdr_rs->id != itr->next) + { +#if enable_debug_msg + printk("SDR record id mismatch: 0x%04x\n", sdr_rs->id); +#endif + sdr_rs->id = itr->next; + } +#if enable_debug_msg + printk("\nSDR record ID : 0x%04x", itr->next); + printk("SDR record type : 0x%02x\n", sdr_rs->type); + printk("SDR record next : 0x%04x\n", sdr_rs->next); + printk("SDR record bytes: %d\n", sdr_rs->length); +#endif + + return rv; +} + +int32_t ipmi_sdr_get_record(struct sdr_get_rs *header, + struct ipmi_sdr_iterator *itr, uint8_t *ret_data) +{ + int32_t rv = 0, len = 0; + + uint8_t buff[128] = ""; + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; /*netfn = 0x00; cmd = 0x00; */ + + struct sdr_get_rq sdr_rq; + + len = header->length; + if (len > 0) + { + memset(&sdr_rq, 0, sizeof(sdr_rq)); + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = header->id; + sdr_rq.offset = 5; + sdr_rq.length = len; + + if (g_use_built_in == 0) + { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else + { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), ret_data, 1); + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + memset(buff, 0, sizeof(buff)); + memcpy(buff, ret_data + 2, sdr_rq.length); + memcpy(ret_data, buff, sdr_rq.length + 2); + } + } + + return rv; +} + +void ipmi_sdr_set_sensor_threshold(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + + /* lower threshold info */ + if (sensor->mask.type.threshold.read.lnc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNC; + } + if (sensor->mask.type.threshold.read.lcr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LCR; + } + if (sensor->mask.type.threshold.read.lnr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNR; + } + g_sensor_data[idx].lowerinfo.lnc = sensor->threshold.lower.non_critical; + g_sensor_data[idx].lowerinfo.lcr = sensor->threshold.lower.critical; + g_sensor_data[idx].lowerinfo.lnr = sensor->threshold.lower.non_recover; + + /* upper threshold info */ + if (sensor->mask.type.threshold.read.unc) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNC; + } + if (sensor->mask.type.threshold.read.ucr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UCR; + } + if (sensor->mask.type.threshold.read.unr) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNR; + } + g_sensor_data[idx].upperinfo.unc = sensor->threshold.upper.non_critical; + g_sensor_data[idx].upperinfo.ucr = sensor->threshold.upper.critical; + g_sensor_data[idx].upperinfo.unr = sensor->threshold.upper.non_recover; +} + +void ipmi_sdr_set_sensor_factor(uint8_t idx, + struct sdr_record_full_sensor *sensor) +{ + char *loc = NULL; + + g_sensor_data[idx].sensor_type = sensor->sensor.type; + sprintf(g_sensor_data[idx].sensor_idstring, "%s", sensor->id_string); + + g_sensor_data[idx].recordinfo.record_m = __TO_M(sensor->mtol); + g_sensor_data[idx].recordinfo.record_b = __TO_B(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k1 = __TO_B_EXP(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k2 = __TO_R_EXP(sensor->bacc); + + g_sensor_data[idx].recordinfo.record_analog = sensor->unit.analog; + g_sensor_data[idx].recordinfo.record_linearization = sensor->linearization; + + memset(g_sensor_data[idx].attrinfo.attr_type_str, 0x00, + SENSOR_ATTR_NAME_LENGTH); + + switch (g_sensor_data[idx].sensor_type) + { + case SDR_SENSOR_TYPE_TEMP: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "temp"); + break; + case SDR_SENSOR_TYPE_VOLT: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + break; + case SDR_SENSOR_TYPE_FAN: + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PWM; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_CONMODE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_DIRECTION; + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "fan"); + break; + case SDR_SENSOR_TYPE_PS: + loc = strstr(g_sensor_data[idx].sensor_idstring, "POWER"); + if (loc) + { + if ((strncmp(g_sensor_data[idx].sensor_idstring + 11, "OUT", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MODEL; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_SN; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MFRID; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PSU_PRESENT; + } + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "power"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "VOLTAGE"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "CURRENT"); + if (loc) + { + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + } + + break; + case SDR_SENSOR_TYPE_CURR: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + break; + case SDR_SENSOR_TYPE_OTHER: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "other"); + break; + default: + printk("not support sensor type !! [%d]\n", g_sensor_data[idx].sensor_type); + break; + } + + if ((strncmp(g_sensor_data[idx].sensor_idstring, "Fan", 3)) == 0) + { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_FAN_PRESENT; + } + +#if enable_debug_msg + { + printk("\n********************\n"); + + printk("m[%d], b[%d], k1[%d], k2[%d]\n", g_sensor_data[idx].recordinfo.record_m, + g_sensor_data[idx].recordinfo.record_b + , g_sensor_data[idx].recordinfo.record_k1, + g_sensor_data[idx].recordinfo.record_k2); + + printk("sensor [%s] type[%d], analog[%d], linearization[%d]\n", + g_sensor_data[idx].sensor_idstring, g_sensor_data[idx].sensor_type + , g_sensor_data[idx].recordinfo.record_analog, + g_sensor_data[idx].recordinfo.record_linearization); + + printk("\n********************\n"); + } +#endif + +} + +int32_t sdr_convert_sensor_reading(uint8_t idx, uint8_t val, + int32_t *point_result) +{ + int32_t m = g_sensor_data[idx].recordinfo.record_m; + int32_t b = g_sensor_data[idx].recordinfo.record_b; + int32_t k1 = g_sensor_data[idx].recordinfo.record_k1; + int32_t k2 = g_sensor_data[idx].recordinfo.record_k2; + int32_t decimal_point = 0; + int32_t result = 0; + + decimal_point = pow_convert(&b, k1); + + switch (g_sensor_data[idx].recordinfo.record_analog) + { + case 0: + result = m * val * decimal_point + b; + break; + case 1: + if (val & 0x80) + { + val++; + } + case 2: + result = (m * (int16_t)val) * decimal_point + b; + break; + default: + return; + } + + pow_convert(&result, k2); + if (k1 < 0) + { + *point_result += -k1; + } + if (k2 < 0) + { + *point_result += -k2; + } + + if (g_sensor_data[idx].sensor_type != SDR_SENSOR_TYPE_FAN) + { + result = result * 1000; /*shift for lm-sensors */ + } + + return result; +} + +int32_t ipmi_sdr_parsing_value(int32_t idx, uint8_t input_value, + int8_t *ret_str) +{ + int32_t calc_result = 0, point_result = 0; + int32_t temp_len = 0; + + uint8_t temp_str[16] = ""; + + calc_result = sdr_convert_sensor_reading(idx, input_value, &point_result); + + temp_len = sprintf(temp_str, "%d", calc_result); + temp_len = temp_len - point_result; + + /* int part */ + if (temp_len <= 0) + { + sprintf(ret_str, "0"); + } + else + { + snprintf(ret_str, temp_len + 1, "%s", + temp_str); /* +1 for snprintf reserve space'\0' */ + } + + /* point part */ + strcat(ret_str, "."); + + /* float part */ + if ((point_result == 0) || (temp_len < 0)) + { + strcat(ret_str, "0"); + } + else + { + strcat(ret_str, temp_str + temp_len); + } + + /* EOL part */ + strcat(ret_str, "\n\0"); + + return (temp_len + 1 + point_result + + 2); /*integer + point + float + EOL + \0 */ +} + + +uint8_t ipmi_check_psu_present(uint8_t psu_slot) +{ + uint8_t slot_mask = 0x0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x03 }; /*netfn = 0x36; cmd = 0xB9; */ + /*uint8_t msg_data[] = { 0x06, 0x52, 0x1B, 0x4C, 0x01, 0x00 }; //netfn = IPMI_NETFN_APP; cmd = GET_PSU_READING; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return 0; + } + else + { + slot_mask = (psu_slot == 1) ? 0x01 : 0x02; + return (returnData[0] & slot_mask) ? 0 : 1; + } +} + +int32_t ipmi_get_psu_info(uint8_t idx, uint8_t cmd, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xBB, 0x4C, 0x1C, 0x00, cmd, 0x00 }; /*netfn = 0x36; cmd = 0xBB; */ + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) + { + psu_slot = 1; + } + else + { + psu_slot = 2; + } + + if (ipmi_check_psu_present(psu_slot)) + { + msg_data[6] = psu_slot; + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + } + else + { + return sprintf(retbuf, "%s\n", returnData); + } + } + else + { + /*printk("Error ! cannot detect PSU%d\n", psu_slot); */ + } + + return sprintf(retbuf, "N/A\n"); +} + +void ipmi_fan_control(uint8_t cmd_data1, uint8_t cmd_data2, uint8_t *retbuf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_TSOL, GET_FAN_INFO, cmd_data1, cmd_data2 }; /*netfn = IPMI_NETFN_TSOL; cmd = GET_FAN_INFO; */ + + mutex_lock(&ipmi_lock); + if (cmd_data1) + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), NULL, 0); + } + else + { + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + } + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + sprintf(retbuf, "N/A\n"); + } + else + { + sprintf(retbuf, "%s", returnData); + } +} + +static ssize_t show_label(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%s\n", + g_sensor_data[attr->index + DEBUGUSE_SHIFT].sensor_idstring); +} + +static ssize_t show_crit_alarm(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%d\n", attr->index); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int32_t rv = 0; + + uint8_t returnData[4] = ""; + uint8_t msg_data[] = { IPMI_NETFN_SE, GET_SENSOR_READING, 0x00 }; /*netfn = IPMI_NETFN_SE; cmd = GET_SENSOR_READING; */ + + mutex_lock(&ipmi_lock); + msg_data[2] = g_sensor_data[attr->index + DEBUGUSE_SHIFT].addr; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "0.0\n"); + } + else + { + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, returnData[0], buf); + } +} + +static ssize_t show_lnr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnr, buf); +} + +static ssize_t show_lcr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lcr, buf); +} + +static ssize_t show_lnc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnc, buf); +} + +static ssize_t show_unr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unr, buf); +} + +static ssize_t show_ucr(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.ucr, buf); +} + +static ssize_t show_unc(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, + g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unc, buf); +} + +static ssize_t show_model(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9a, buf); +} + +static ssize_t show_sn(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9e, buf); +} + +static ssize_t show_mfrid(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x99, buf); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, + char *buf) +{ + uint8_t returnData[10] = { 0 }; + ipmi_fan_control(0x00, 0x00, returnData); + return sprintf(buf, "%d\n", returnData[0]); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, + const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + if (g_fan_control_mode == 1) + { + ipmi_fan_control(0x01, store_input, returnData); + } + + return count; +} + +static ssize_t show_controlmode(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%d\n", g_fan_control_mode); +} + +static ssize_t store_controlmode(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + g_fan_control_mode = store_input; + if (g_fan_control_mode == 3) + { + ipmi_fan_control(0x7f, 0xff, returnData); + } + + return count; +} + +static ssize_t show_direction(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_STORAGE, GET_FRU_INFO, 0x00, 0x19, 0x00, 0x01 }; /*netfn = IPMI_NETFN_STORAGE; cmd = GET_FRU_INFO; */ + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) + { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "N/A\n"); + } + else + { + return sprintf(buf, "%c\n", returnData[1]); + } +} + +static ssize_t show_fanpresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + int32_t fan_idx = 0, fan_present = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x02 }; /*netfn = 0x36; cmd = 0xB9; */ + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct kernel_ipmi_msg msg; + + fan_idx = (g_sensor_data[attr->index].sensor_idstring[8] - '0') - 1; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + fan_present = ((returnData[0] >> fan_idx) & 0x1) ? 0 : 1; + + return sprintf(buf, "%d\n", fan_present); +} + +static ssize_t show_psupresent(struct device *dev, + struct device_attribute *devattr, char *buf) +{ + int32_t psu_idx = 0; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + psu_idx = g_sensor_data[attr->index].sensor_idstring[3] - '0'; + + return sprintf(buf, "%d\n", ipmi_check_psu_present(psu_idx)); +} + +static ssize_t(*const attr_show_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, char *buf) = +{ + show_label, show_crit_alarm, show_input + , show_lnc, show_lcr, show_lnr + , show_unc, show_ucr, show_unr + , show_model, show_sn, show_pwm + , show_controlmode, show_direction, show_fanpresent + , show_psupresent, show_mfrid +}; + +static ssize_t(*const attr_store_func_ptr[SENSOR_ATTR_MAX])(struct device *dev, + struct device_attribute *devattr, const char *buf, size_t count) = +{ + NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, store_pwm + , store_controlmode, NULL, NULL + , NULL, NULL +}; + +static const char *const sensor_attrnames[SENSOR_ATTR_MAX] = +{ + "%s%d_label", "%s%d_crit_alarm", "%s%d_input" + , "%s%d_lncrit", "%s%d_lcrit", "%s%d_min" + , "%s%d_ncrit", "%s%d_crit", "%s%d_max" + , "%s%d_model", "%s%d_sn", "%s%d_pwm" + , "%s%d_controlmode", "%s%d_direction", "%s%d_present" + , "%s%d_present", "%s%d_mfrid" +}; + +static int32_t create_sensor_attrs(int32_t attr_no) +{ + int32_t i = 0, j = 0; + + struct attr_info *attrdata = &g_sensor_data[attr_no].attrinfo; + +#if enable_debug_msg + printk("##### %s:%d attr_no %d\n", __FUNCTION__, __LINE__, attr_no); +#endif + + for (i = 0; i < SENSOR_ATTR_MAX; i++) + { + if ((g_sensor_data[attr_no].capability >> i) & 0x01) + { + snprintf(attrdata->attr_name[j], SENSOR_ATTR_NAME_LENGTH, sensor_attrnames[i], + attrdata->attr_type_str, attr_no - DEBUGUSE_SHIFT); + + sysfs_attr_init(&attrdata->sd_attrs[j].dev_attr.attr); + attrdata->sd_attrs[j].dev_attr.attr.name = attrdata->attr_name[j]; + attrdata->sd_attrs[j].dev_attr.show = attr_show_func_ptr[i]; + attrdata->sd_attrs[j].dev_attr.store = attr_store_func_ptr[i]; + + attrdata->sd_attrs[j].dev_attr.attr.mode = S_IRUGO; + if (attrdata->sd_attrs[j].dev_attr.store) + { + attrdata->sd_attrs[j].dev_attr.attr.mode |= S_IWUSR; + } + + attrdata->sd_attrs[j].index = attr_no - DEBUGUSE_SHIFT; + attrdata->attrs[j] = &attrdata->sd_attrs[j].dev_attr.attr; + j++; + + data->total_create_sysfs++; + } + } + + attrdata->attrs[j] = NULL; + attrdata->attr_group.attrs = attrdata->attrs; + + g_sensor_data[attr_no].attrinfo.attr_exist = 1; + + return sysfs_create_group(&data->ipmi_hwmon_dev->kobj, &attrdata->attr_group); +} + +static int32_t remove_sensor_attrs(void) +{ + int32_t i = 0; + + for (i = 0; i < data->total_sensor_id; i++) + { + if (g_sensor_data[i].attrinfo.attr_exist) + { + sysfs_remove_group(&data->ipmi_hwmon_dev->kobj, + &g_sensor_data[i].attrinfo.attr_group); + } + } + return 0; +} + +int32_t ipmi_init_sdr_sensors_data(void) +{ + int32_t sdr_idx = 0; + int32_t err = 0; + + struct ipmi_sdr_iterator *itr = NULL; + struct sdr_get_rs *header = NULL; + + uint8_t *rec = NULL; + + mutex_lock(&ipmi_lock); + + itr = kzalloc(sizeof(struct ipmi_sdr_iterator), GFP_KERNEL); + if (itr == NULL) + { + printk("%s(%d): kzalloc failure.\n", __func__, __LINE__); + goto itr_malloc_fail; + } + + header = kzalloc(sizeof(struct sdr_get_rs), GFP_KERNEL); + if (header == NULL) + { + printk("%s(%d): malloc failure.\n", __func__, __LINE__); + goto header_malloc_fail; + } + + err = ipmi_sdr_start(itr); + if (err) + { + printk("%s(%d): ipmi_sdr_start fail.\n", __func__, __LINE__); + goto ipmi_sdr_start_fail; + } + + data->total_sensor_id = itr->total; + rec = kzalloc(GET_SDR_ENTIRE_RECORD, GFP_KERNEL); + if (rec == NULL) + { + printk("%s(%d): kzalloc failure\n", __func__, __LINE__); + goto rec_malloc_fail; + } + + g_sensor_data = kzalloc(itr->total * sizeof(struct ipmi_sensor_data), + GFP_KERNEL); + if (g_sensor_data == NULL) + { + printk("%s(%d): malloc failure", __func__, __LINE__); + goto g_sensor_data_malloc_fail; + } + + memset(g_sensor_data, 0x0, itr->total * sizeof(struct ipmi_sensor_data)); + + for (sdr_idx = 0; sdr_idx < itr->total; sdr_idx++) + { + err = ipmi_sdr_get_header(itr, header); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_header_fail; + } + + + memset(rec, 0, GET_SDR_ENTIRE_RECORD); + err = ipmi_sdr_get_record(header, itr, rec); + if (err) + { + if (err == 0xC5) + { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_record_fail; + } + + itr->next = header->next; + + switch (header->type) + { + case SDR_RECORD_TYPE_FULL_SENSOR: + /* prepare (threshold, factor)data whilie init, for reduce reading step and improve operate speed */ + g_sensor_data[sdr_idx].addr = rec[2]; + g_sensor_data[sdr_idx].capability = + SENSOR_GET_CAP_LABEL /*| SENSOR_GET_CAP_ALARM */ | SENSOR_GET_CAP_INPUT; + g_sensor_data[sdr_idx].headerinfo.header_type = header->type; + g_sensor_data[sdr_idx].headerinfo.header_byte = header->length; + + ipmi_sdr_set_sensor_threshold(sdr_idx, (struct sdr_record_full_sensor *) rec); + ipmi_sdr_set_sensor_factor(sdr_idx, (struct sdr_record_full_sensor *) rec); + + if (sdr_idx >= DEBUGUSE_SHIFT) + { + err = create_sensor_attrs(sdr_idx); + if (err) + { + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; + printk("[err : %d]sysfs_create_group fail in [%d] %s\n", err, sdr_idx, + g_sensor_data[sdr_idx].sensor_idstring); + goto create_sysfs_fail; + } + } + + data->total_suport_sensor++; + + break; + case SDR_RECORD_TYPE_COMPACT_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_EVENTONLY_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR: /* not supporrt now */ + default: + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; +#if enable_debug_msg + printk("ID[%d] : not support type [%d]\n", sdr_idx, header->type); +#endif + break; + } + } + + printk("quanta_hwmon_ipmi : detected [%d] sensor, create [%d] sysfs\n", + data->total_suport_sensor, data->total_create_sysfs); + +create_sysfs_fail: +ipmi_sdr_get_header_fail: +ipmi_sdr_get_record_fail: +g_sensor_data_malloc_fail: + if (header) + { + kfree(header); + header = NULL; + } + if (rec) + { + kfree(rec); + rec = NULL; + } + +rec_malloc_fail: +ipmi_sdr_start_fail: +header_malloc_fail: + if (itr) + { + kfree(itr); + itr = NULL; + } + +itr_malloc_fail: + mutex_unlock(&ipmi_lock); + + return err; +} + +static int32_t __init quanta_hwmon_ipmi_init(void) +{ + int32_t err = 0; + + init_completion(&g_read_complete); + + data = kzalloc(sizeof(struct quanta_hwmon_ipmi_data), GFP_KERNEL); + if (NULL == data) + { + printk("alloc data fail\n"); + goto alloc_err; + } + + data->ipmi_platform_dev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + err = IS_ERR(data->ipmi_platform_dev); + if (err) + { + printk("platform device register fail (err : %d)\n", err); + goto device_reg_err; + } + + data->ipmi_hwmon_dev = hwmon_device_register_with_groups(NULL, DRVNAME, NULL, + NULL); + err = IS_ERR(data->ipmi_hwmon_dev); + if (err) + { + printk("hwmon register fail\n"); + goto hwmon_register_err; + } + + err = ipmi_create_user(0, &ipmi_hndlrs, NULL, &ipmi_mh_user); + if (err) + { + printk("warning: create user fail, watchdog broken (err : %d)\n", err); + goto ipmi_create_err; + } + + mutex_init(&ipmi_lock); + err = ipmi_init_sdr_sensors_data(); + if (err) + { + printk("init sensor data fail (err : %d)\n", err); + goto init_sensor_err; + } + + return 0; + +init_sensor_err: + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } +ipmi_create_err: + hwmon_device_unregister(data->ipmi_hwmon_dev); +hwmon_register_err: + platform_device_unregister(data->ipmi_platform_dev); +device_reg_err: + if (data) + { + kfree(data); + data = NULL; + } +alloc_err: + return err; +} + +static void __exit quanta_hwmon_ipmi_exit(void) +{ + remove_sensor_attrs(); + hwmon_device_unregister(data->ipmi_hwmon_dev); + + mutex_lock(&ipmi_lock); + ipmi_destroy_user(ipmi_mh_user); + mutex_unlock(&ipmi_lock); + + platform_device_unregister(data->ipmi_platform_dev); + + if (g_sensor_data) + { + kfree(g_sensor_data); + g_sensor_data = NULL; + } + + if (data) + { + kfree(data); + data = NULL; + } +} + +module_init(quanta_hwmon_ipmi_init); +module_exit(quanta_hwmon_ipmi_exit); + +MODULE_AUTHOR("Charcar~~Charcar~Charlie li li"); +MODULE_VERSION("2.0"); +MODULE_DESCRIPTION("Quanta BMC hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/service/ix8a-bwde-platform-init.service b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/service/ix8a-bwde-platform-init.service new file mode 100644 index 0000000000..4527d70bd3 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/service/ix8a-bwde-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Quanta IX8A-BWDE-56X Platform initialization service +Before=pmon.service +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/quanta_ix8a_bwde_util.py install +ExecStop=/usr/local/bin/quanta_ix8a_bwde_util.py clean +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/setup.py new file mode 100644 index 0000000000..a157e46cb6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +from setuptools import setup +os.listdir + +setup( + name='ix8a_bwde_56x', + version='1.0', + description='Module to initialize Quanta IX8A-BWDE-56X platforms', + + packages=['ix8a_bwde_56x'], + package_dir={'ix8a_bwde_56x': 'ix8a-bwde-56x/classes'}, +) + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/__init__.py new file mode 100644 index 0000000000..4bfefa0fb6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/chassis.py new file mode 100644 index 0000000000..c765f37344 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/chassis.py @@ -0,0 +1,232 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import sys + import time + import syslog + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 56 + self.__num_of_sfps = 48 + self.__num_of_fan_drawers = 6 + self.__fan_per_drawer = 2 + self.__num_of_thermals = 28 + self.__xcvr_presence = {} + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + fan_index = 1 + for drawer_index in range(1, self.__num_of_fan_drawers + 1): + drawer_fan_list = [] + for index in range(0, self.__fan_per_drawer): + fan = Fan(fan_index, False) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(1, self.__num_of_ports + 1): + if index in range(1, self.__num_of_sfps + 1): + sfp = Sfp(index, 'SFP') + else: + sfp = Sfp(index, 'QSFP') + + self._sfp_list.append(sfp) + + for index in range(1, self.__num_of_ports + 1): + self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() + +############################################## +# Device methods +############################################## + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + For Quanta IX8A the index in sfputil.py starts from 1, so override + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + if (index == 0): + raise IndexError + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("override: SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_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 + +############################################## +# Chassis methods +############################################## + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + return self._eeprom.system_eeprom_info() + + ############################################## + # Other methods + ############################################## + def get_watchdog(self): + """ + Retreives hardware watchdog device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + watchdog device + """ + try: + if self._watchdog is None: + from sonic_platform.watchdog import Watchdog + # Create the watchdog Instance + self._watchdog = Watchdog() + + except Exception as e: + syslog.syslog(syslog.LOG_ERR, "Fail to load watchdog due to {}".format(e)) + return self._watchdog + + def get_change_event(self, timeout=0): + """ + Currently only support transceiver change events + """ + + start_ms = time.time() * 1000 + xcvr_change_event_dict = {} + event = False + + while True: + time.sleep(0.5) + for index in range(1, self.__num_of_ports + 1): + cur_xcvr_presence = self._sfp_list[index-1].get_presence() + if cur_xcvr_presence != self.__xcvr_presence[index]: + if cur_xcvr_presence is True: + xcvr_change_event_dict[str(index)] = '1' + self.__xcvr_presence[index] = True + elif cur_xcvr_presence is False: + xcvr_change_event_dict[str(index)] = '0' + self.__xcvr_presence[index] = False + event = True + + if event is True: + return True, {'sfp':xcvr_change_event_dict} + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, {'sfp':xcvr_change_event_dict} + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/eeprom.py new file mode 100644 index 0000000000..d154a8a0c4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/eeprom.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.__eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + 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] + + if tlv[0] == self._TLV_CODE_VENDOR_EXT: + value = str((tlv[2] << 24) | (tlv[3] << 16) | + (tlv[4] << 8) | tlv[5]) + value += tlv[6:6 + tlv[1]].decode('ascii') + else: + value = self.decoder(None, tlv)[30:] + + 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): + (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): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in results[2]]).upper() + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/fan.py new file mode 100644 index 0000000000..8aae9147c4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/fan.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta IX8A-BWDE +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import logging + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +HWMON_DIR = "/sys/class/hwmon/hwmon2/" +FAN_INDEX_START = 18 +NUM_FANTRAYS = 6 +FANS_PERTRAY = 2 + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + self.fan_index = index + self.psu_fan_index_mapping = { + 1:120, + 2:132, + } + self.psu_index_mapping = { + 1:114, + 2:126, + } + if self.is_psu_fan: + self.fan_presence_attr = "power{}_present".format(self.psu_index_mapping[index]) + self.fan_pwm_attr = "fan{}_pwm".format(self.psu_fan_index_mapping[index]) + self.fan_rpm_attr = "fan{}_input".format(self.psu_fan_index_mapping[index]) + self.fan_direction_attr = "fan{}_direction".format(self.psu_fan_index_mapping[index]) + else: + self.fan_presence_attr = "fan{}_present".format(FAN_INDEX_START+(index-1)) + self.fan_pwm_attr = "fan{}_pwm".format(FAN_INDEX_START+(index-1)) + self.fan_rpm_attr = "fan{}_input".format(FAN_INDEX_START+(index-1)) + self.fan_direction_attr = "fan{}_direction".format(FAN_INDEX_START+(index-1)) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + 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.fan_index) + else: + fantray_index = (self.fan_index-1)//FANS_PERTRAY+1 + fan_index_intray = self.fan_index - ((fantray_index-1)*FANS_PERTRAY) + return "Fantray{}_{}".format(fantray_index, fan_index_intray) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.fan_presence_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == '1'): + return True + else: + return False + + return None + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR' and attr_rv != '0.0'): + return True + else: + return False + else: + return False + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + attr_path = HWMON_DIR + self.fan_direction_attr + attr_rv = self.__get_attr_value(attr_path) + + if attr_rv == '2': + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + else: + return 0 + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 25 + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + + Args: + color: A string representing the color with which to set the + fan module status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return True + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..75e954576a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/fan_drawer.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/platform.py new file mode 100644 index 0000000000..8d20abef90 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +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): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/psu.py new file mode 100644 index 0000000000..bd3f4ce808 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/psu.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import logging + 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") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +class Psu(PsuBase): + def __init__(self, index): + PsuBase.__init__(self) + fan = Fan(index, True) + self._fan_list.append(fan) + + self.psu_index_mapping = { + 1:114, + 2:126, + } + self.psu_powerin_index_mapping = { + 1:119, + 2:131, + } + self.psu_currentout_index_mapping = { + 1:130, + 2:115, + } + self.psu_currentin_index_mapping = { + 1:130, + 2:115, + } + self.psu_voltageout_index_mapping = { + 1:129, + 2:124, + } + self.psu_voltagein_index_mapping = { + 1:125, + 2:128, + } + self.index = index + self.psu_presence_attr = "power{}_present".format(self.psu_index_mapping[self.index]) + self.psu_status_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_power_in_attr = "power{}_input".format(self.psu_powerin_index_mapping[self.index]) + self.psu_power_out_attr = "power{}_input".format(self.psu_index_mapping[self.index]) + self.psu_voltage_out_attr = "in{}_input".format(self.psu_voltageout_index_mapping[self.index]) + self.psu_current_out_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_voltage_in_attr = "in{}_input".format(self.psu_voltagein_index_mapping[self.index]) + self.psu_current_in_attr = "curr{}_input".format(self.psu_currentin_index_mapping[self.index]) + self.psu_serial_attr = "power{}_sn".format(self.psu_index_mapping[self.index]) + self.psu_model_attr = "power{}_model".format(self.psu_index_mapping[self.index]) + self.psu_mfr_id_attr = "power{}_mfrid".format(self.psu_index_mapping[self.index]) + self.psu_capacity_attr = "power{}_pout_max".format(self.psu_index_mapping[self.index]) + self.psu_type_attr = "power{}_vin_type".format(self.psu_index_mapping[self.index]) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + fd.close() + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = HWMON_DIR+self.psu_presence_attr + attr_normal = '1' + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = HWMON_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_mfr_id(self): + """ + Retrieves the manufacturer's name (or id) of the device + + Returns: + string: Manufacturer's id of device + """ + mfr_id = "N/A" + attr_path = HWMON_DIR+self.psu_mfr_id_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + mfr_id = attr_rv + + return mfr_id + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = HWMON_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = HWMON_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = HWMON_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_out = float(attr_rv) / 1000 + + return current_out + + def get_input_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_in = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_in = float(attr_rv) / 1000 + + return voltage_in + + def get_input_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_in = 0.0 + attr_path = HWMON_DIR+self.psu_current_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_in = float(attr_rv) / 1000 + + return current_in + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = HWMON_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + power_out = float(attr_rv) / 1000 + + return power_out + + 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. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + type = "AC" + attr_path = HWMON_DIR+self.psu_type_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + type = attr_rv + + return type + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + capacity = 0 + attr_path = HWMON_DIR+self.psu_capacity_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + try: + capacity = int(attr_rv) + except ValueError: + capacity = 0 + + return capacity + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/sfp.py new file mode 100644 index 0000000000..3b75b69275 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/sfp.py @@ -0,0 +1,1633 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +#import subprocess +#import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase +# from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_MODULE_THRESHOLD_OFFSET = 512 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 560 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +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_TYPE = "SFP" +QSFP_TYPE = "QSFP" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 56 + QSFP_START = 49 + QSFP_END = 56 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-quanta_ix8a_bwde-r0" + HWSKU = "Quanta-IX8A-BWDE-56X" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + #self.dom_supported = False + self.sfp_type = sfp_type + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44, + 33 : 45, + 34 : 46, + 35 : 47, + 36 : 48, + 37 : 49, + 38 : 50, + 39 : 51, + 40 : 52, + 41 : 53, + 42 : 54, + 43 : 55, + 44 : 56, + 45 : 57, + 46 : 58, + 47 : 59, + 48 : 60, + 49 : 61,#QSFP49 + 50 : 62,#QSFP50 + 51 : 63,#QSFP51 + 52 : 64,#QSFP52 + 53 : 65,#QSFP53 + 54 : 66,#QSFP54 + 55 : 67,#QSFP55 + 56 : 68,#QSFP56 + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self.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', 'vendor_date', + 'vendor_oui', 'application_advertisement'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', + 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the SFP module + Returns: + bool: True if SFP module is present, False if not + """ + # Check for invalid port_num + if self.port_num < self.PORT_START or self.port_num > self.PORT_END: + return False + + try: + if self.sfp_type == SFP_TYPE: + reg_file = open("/sys/class/cpld-sfp28/port-"+str(self.port_num)+"/pre_n") + else: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+34)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + reg_file.close() + if self.sfp_type == SFP_TYPE: + if reg_value == '1': + return True + else: + if reg_value == '0': + return True + + return False + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + eeprom_raw = None + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability = int(qsfp_dom_capability_raw[0], 16) + + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + if qsfp_version_compliance_raw is not None: + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qsfp_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qsfp_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qsfp_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + self.dom_tx_disable_supported = True + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ======================================================================== + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + if not self.get_presence(): + return transceiver_info_dict + + if self.sfp_type == QSFP_TYPE: + offset = QSFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == SFP_TYPE: + offset = SFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + else: + return transceiver_info_dict + + # Add retry for xcvr eeprom to get ready + max_retry = 10 + for i in range(0,max_retry): + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is not None: + break + else: + if not self.get_presence(): + return transceiver_info_dict + elif i == max_retry-1: + pass + else: + time.sleep(0.5) + + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + transceiver_info_dict['type'] = sfp_interface_bulk_data \ + ['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data \ + ['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data \ + ['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data \ + ['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data \ + ['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data \ + ['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data \ + ['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data \ + ['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data \ + ['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data \ + ['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data \ + ['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = 'N/A' + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = QSFP_DOM_OFFSET + offset_xcvr = QSFP_INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability_data = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qsfp_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + if not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + else: + return None + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + if not self.get_presence() or not sfpd_obj: + return {} + DOM_OFFSET = 0 + transceiver_dom_threshold_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + offset = DOM_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + module_threshold_values = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_channel_thres_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNEL_THRESHOLD_OFFSET), QSFP_CHANNEL_THRESHOLD_WIDTH) + if dom_channel_thres_raw is not None: + channel_threshold_values = sfpd_obj.parse_channel_threshold_values(dom_channel_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + else: + channel_threshold_data = None + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + DOM_OFFSET = 256 + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + else: + return None + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+32)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return None + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return True + else: + return False + else: + return None + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + else: + return None + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + else: + return None + + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + else: + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return 0 + elif self.sfp_type == QSFP_TYPE: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + else: + return None + + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this QSFP module + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+35)+"/value") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return False + else: + return True + else: + return None + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_POWEROVERRIDE_OFFSET), QSFP_POWEROVERRIDE_WIDTH) + if dom_control_raw is not None: + if int(dom_control_raw[0],16) & (0x01 << QSFP_POWEROVERRIDE_BIT): + return True + else: + return False + else: + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( \ + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default state. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/direction", 'r+') as f: + f.write('out') + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+32)+"/value", "r+") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+32)+"/value", "r+") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + offset = 256 + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( + status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(offset + SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + else: + return None + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + else: + return False + else: + return None + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+35)+"/value", "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + else: + return None + + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings(self.__get_path_to_port_config_file()) + print("self.index{}".format(self.index)) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/thermal.py new file mode 100644 index 0000000000..1e07cb0e3e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/thermal.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import logging +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +thermal_index_mapping = { + 1:53, + 2:54, + 3:55, + 4:56, + 5:57, + 6:58, + 7:59, + 8:60, + 9:61, + 10:62, + 11:63, + 12:64, + 13:86, + 14:87, + 15:88, + 16:89, + 17:90, + 18:91, + 19:92, + 20:93, + 21:94, + 22:109, + 23:116, + 24:117, + 25:121, + 26:122, + 27:123, + 28:127 +} + + + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index + self.temp_attr = "temp{}_input".format(thermal_index_mapping[self.index]) + self.high_th_attr = "temp{}_ncrit".format(thermal_index_mapping[self.index]) + self.high_crit_th_attr = "temp{}_crit".format(thermal_index_mapping[self.index]) + self.name_attr = "temp{}_label".format(thermal_index_mapping[self.index]) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return attr_rv + else: + return None + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if (self.get_temperature() != None): + return True + else: + return False + + 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 + """ + attr_path = HWMON_DIR + self.temp_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + 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 + """ + attr_path = HWMON_DIR + self.high_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + def get_high_critical_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 + """ + attr_path = HWMON_DIR + self.high_crit_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/watchdog.py new file mode 100644 index 0000000000..282f356f4e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform/watchdog.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python + +############################################################################# +# +# Watchdog contains an implementation of SONiC Platform Base Watchdog API +# +############################################################################# +import fcntl +import os +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +""" ioctl constants """ +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +""" Watchdog ioctl commands """ +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +""" Watchdog status constants """ +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +WDT_COMMON_ERROR = -1 +WD_MAIN_IDENTITY = "iTCO_wdt" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + +DEFAULT_TIMEOUT=180 + +class Watchdog(WatchdogBase): + + def __init__(self): + + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = DEFAULT_TIMEOUT + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WD_MAIN_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + self.watchdog = os.open(watchdog_device_path, os.O_RDWR) + return self.watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + return int(req[0]) + + def _gettimeout(self, timeout_path): + """ + Get watchdog timeout + @return watchdog timeout + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + ################################################################# + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of 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 , 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. + """ + + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._settimeout(seconds) + self._enable() + self.armed = True + ret = self.timeout + except IOError as e: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + Returns: + A boolean, True if watchdog is armed, False if not + """ + + return self.armed + + 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 thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + + os.close(self.watchdog) + + + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform_setup.py new file mode 100644 index 0000000000..a4899c6183 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/sonic_platform_setup.py @@ -0,0 +1,24 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Quanta Platforms', + license='Apache 2.0', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/utils/quanta_ix8a_bwde_util.py b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/utils/quanta_ix8a_bwde_util.py new file mode 100755 index 0000000000..ed8c5fef6b --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8a-bwde-56x/utils/quanta_ix8a_bwde_util.py @@ -0,0 +1,336 @@ +#!/usr/bin/env python +# +# Copyright (C) 2018 Quanta Computer Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes +""" + +import os +import commands +import sys, getopt +import logging +import time + +DEBUG = False +args = [] +FORCE = 0 +i2c_prefix = '/sys/bus/i2c/devices/' + +if DEBUG == True: + print sys.argv[0] + print 'ARGV :', sys.argv[1:] + +def main(): + global DEBUG + global args + global FORCE + + if len(sys.argv) < 2: + show_help() + + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', + 'debug', + 'force', + ]) + if DEBUG == True: + print options + print args + print len(sys.argv) + + for opt, arg in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in args: + if arg == 'install': + install() + elif arg == 'clean': + uninstall() + else: + show_help() + + return 0 + +def show_help(): + print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} + sys.exit(0) + +def show_log(txt): + if DEBUG == True: + print "[IX8A-BWDE-56X]" + txt + return + +def exec_cmd(cmd, show): + logging.info('Run :' + cmd) + status, output = commands.getstatusoutput(cmd) + show_log (cmd +"with result:" + str(status)) + show_log (" output:" + output) + if status: + logging.info('Failed :' + cmd) + if show: + print('Failed :' + cmd) + return status, output + +instantiate =[ +#export pca9698 for qsfp present +'echo 34 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio34/direction', +'echo 38 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio38/direction', +'echo 42 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio42/direction', +'echo 46 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio46/direction', +'echo 50 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio50/direction', +'echo 54 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio54/direction', +'echo 58 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio58/direction', +'echo 62 > /sys/class/gpio/export', +'echo in > /sys/class/gpio/gpio62/direction', +#export pca9698 for qsfp lpmode +'echo 35 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio35/direction', +'echo 0 >/sys/class/gpio/gpio35/value', +'echo 39 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio39/direction', +'echo 0 >/sys/class/gpio/gpio39/value', +'echo 43 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio43/direction', +'echo 0 >/sys/class/gpio/gpio43/value', +'echo 47 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio47/direction', +'echo 0 >/sys/class/gpio/gpio47/value', +'echo 51 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio51/direction', +'echo 0 >/sys/class/gpio/gpio51/value', +'echo 55 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio55/direction', +'echo 0 >/sys/class/gpio/gpio55/value', +'echo 59 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio59/direction', +'echo 0 >/sys/class/gpio/gpio59/value', +'echo 63 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio63/direction', +'echo 0 >/sys/class/gpio/gpio63/value', +#SFP28 Module TxEnable +'echo 0 > /sys/class/cpld-sfp28/port-1/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-2/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-3/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-4/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-5/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-6/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-7/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-8/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-9/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-10/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-11/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-12/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-13/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-14/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-15/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-16/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-17/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-18/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-19/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-20/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-21/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-22/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-23/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-24/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-25/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-26/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-27/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-28/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-29/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-30/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-31/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-32/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-33/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-34/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-35/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-36/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-37/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-38/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-39/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-40/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-41/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-42/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-43/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-44/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-45/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-46/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-47/tx_dis', +'echo 0 > /sys/class/cpld-sfp28/port-48/tx_dis', +#Update System LED +'echo 79 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio79/direction', +'echo 0 > /sys/class/gpio/gpio79/value', +'echo 80 > /sys/class/gpio/export', +'echo out > /sys/class/gpio/gpio80/direction', +'echo 1 > /sys/class/gpio/gpio80/value' +] + +drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', +'i2c-mux-pca954x force_deselect_on_exit=1', +'gpio-pca953x', +'optoe', +'qci_cpld_sfp28', +'qci_cpld_led', +'qci_platform_ix8a_bwde', +'quanta_hwmon_ipmi', +'ipmi_devintf' +] + +un_drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', +'i2c-mux-pca954x', +'gpio-pca953x', +'optoe', +'qci_cpld_sfp28', +'qci_cpld_led', +'qci_platform_ix8a_bwde', +'quanta_hwmon_ipmi', +'ipmi_devintf' +] + +def system_install(): + global FORCE + + #setup driver dependency + exec_cmd("depmod -a ", 1) + #install drivers + for i in range(0,len(drivers)): + status, output = exec_cmd("modprobe " + drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + + #reload ethernet drivers in correct order + exec_cmd("rmmod ixgbe ", 1) + exec_cmd("rmmod igb ", 1) + exec_cmd("modprobe igb ", 1) + exec_cmd("modprobe ixgbe ", 1) + + #turn on module power + exec_cmd("echo 21 > /sys/class/gpio/export ", 1) + exec_cmd("echo high > /sys/class/gpio/gpio21/direction ", 1) + + # qsfp reset gpio + time.sleep(1) + for qsfp_reset in [32, 36, 40, 44, 48, 52, 56, 60]: + exec_cmd("echo "+str(qsfp_reset)+" > /sys/class/gpio/export", 1) + exec_cmd("echo high > /sys/class/gpio/gpio"+str(qsfp_reset)+"/direction", 1) + + # Reset fron-ports LED CPLD + exec_cmd("echo 73 > /sys/class/gpio/export ", 1) + status, output = exec_cmd("cat /sys/class/gpio/gpio73/value", 1) + if output != '1': + exec_cmd("echo out > /sys/class/gpio/gpio73/direction ", 1) + exec_cmd("echo 0 >/sys/class/gpio/gpio73/value", 1) + exec_cmd("echo 1 >/sys/class/gpio/gpio73/value", 1) + + #instantiate devices + for i in range(0, len(instantiate)): + status, output = exec_cmd(instantiate[i], 1) + if status: + print output + if FORCE == 0: + return status + + #QSFP for 1~56 port + for port_number in range(1, 57): + bus_number = port_number + 12 + os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) + + #Enable front-ports LED decoding + exec_cmd('echo 1 > /sys/class/cpld-led/CPLDLED-1/led_decode', 1) + exec_cmd('echo 1 > /sys/class/cpld-led/CPLDLED-2/led_decode', 1) + + return + +def system_ready(): + if not device_found(): + return False + return True + +def install(): + if not device_found(): + print "No device, installing...." + status = system_install() + if status: + if FORCE == 0: + return status + status, output = exec_cmd("pip3 install /usr/share/sonic/device/x86_64-quanta_ix8a_bwde-r0/sonic_platform-1.0-py3-none-any.whl",1) + if status: + print output + if FORCE == 0: + return status + else: + print " ix8a-bwde driver already installed...." + return + +def uninstall(): + global FORCE + #uninstall drivers + for i in range(len(un_drivers) - 1, -1, -1): + status, output = exec_cmd("rmmod " + un_drivers[i], 1) + if status: + print output + if FORCE == 0: + return status + + status, output = exec_cmd("pip3 uninstall sonic-platform -y ",1) + if status: + print output + if FORCE == 0: + return status + + return + +def device_found(): + ret1, log1 = exec_cmd("cat /proc/modules | grep ix8a > /tmp/chkdriver.log", 0) + ret2, log2 = exec_cmd("cat /tmp/chkdriver.log | grep ix8a", 0) + + if ret1 == 0 and len(log2) > 0: + return True + else: + return False + +if __name__ == "__main__": + main() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/Makefile b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/Makefile index bfb8ec0c45..df010f27e8 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/Makefile @@ -1,3 +1,3 @@ -obj-m:=qci_cpld_sfp28.o qci_cpld_led.o qci_platform_ix8c.o +obj-m:=qci_cpld_sfp28.o qci_cpld_led.o qci_platform_ix8c.o quanta_hwmon_ipmi.o diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_led.c b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_led.c index 229195249b..2b0fe902c4 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_led.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_led.c @@ -242,6 +242,7 @@ err_out: } /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if 0 static int idr_has_entry(int id, void *p, void *data) { return 1; @@ -251,6 +252,7 @@ static bool cpld_idr_is_empty(struct idr *idp) { return !idr_for_each(idp, idr_has_entry, NULL); } +#endif static int cpld_led_remove(struct i2c_client *client) { @@ -261,7 +263,7 @@ static int cpld_led_remove(struct i2c_client *client) ida_simple_remove(&cpld_led_ida, data->cpld_data->cpld_id); kfree(data->cpld_data); - if (cpld_idr_is_empty(&cpld_led_ida.idr)) + if (ida_is_empty(&cpld_led_ida)) class_destroy(cpld_class); return 0; diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_sfp28.c b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_sfp28.c index dac76667c6..6e6608db62 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_sfp28.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_cpld_sfp28.c @@ -52,7 +52,6 @@ static struct class *cpld_class = NULL; struct sfp_data { struct i2c_client *cpld_client; char name[8]; - char type[8]; u8 port_id; u8 cpld_port; }; @@ -253,8 +252,6 @@ static ssize_t set_tx_dis(struct device *dev, } //SFP -//static DEVICE_ATTR(led_enable, S_IWUSR | S_IRUGO, get_led_enable, set_led_enable); -//static DEVICE_ATTR(monitor_enable, S_IWUSR | S_IRUGO, get_monitor_enable, set_monitor_enable); //SFP static DEVICE_ATTR(tx_fault, S_IRUGO, get_tx_fault, NULL); static DEVICE_ATTR(tx_dis, S_IWUSR | S_IRUGO, get_tx_dis, set_tx_dis); @@ -262,7 +259,6 @@ static DEVICE_ATTR(pre_n, S_IRUGO, get_pre_n, NULL); static DEVICE_ATTR(rx_los, S_IRUGO, get_rx_los, NULL); static const struct attribute *sfp_attrs[] = { -// &dev_attr_led_enable.attr, &dev_attr_tx_fault.attr, &dev_attr_tx_dis.attr, &dev_attr_pre_n.attr, @@ -279,26 +275,14 @@ static int cpld_probe(struct i2c_client *client, { struct cpld_data *data; struct sfp_data *port_data; -// struct i2c_monitor_data *monitor_data; struct device *port_dev; -// struct device *i2c_dev; int port_nr, i=0, err; - char name[I2C_NAME_SIZE], type[I2C_NAME_SIZE]; printk("cpld cpld_probe\n"); - while(id->name[i]) - { - name[i]=tolower(id->name[i]); - i++; - } - name[i]='\0'; - strncpy(type,name+5,strlen(name)-5); - type[strlen(name)-5]='\0'; - if (!cpld_class) { - cpld_class = class_create(THIS_MODULE, name); + cpld_class = class_create(THIS_MODULE, "cpld-sfp28"); if (IS_ERR(cpld_class)) { pr_err("couldn't create sysfs class\n"); return PTR_ERR(cpld_class); @@ -328,9 +312,7 @@ static int cpld_probe(struct i2c_client *client, data->port_dev[i] = port_dev; data->port_data[i] = port_data; - strcpy(port_data->type, type); - - dev_info(&client->dev, "Register %s port-%d\n", port_data->type , port_nr); + dev_info(&client->dev, "Register port-%d\n", port_nr); /* FIXME: implement Logical/Physical port remapping */ //port_data->cpld_port = i; @@ -358,7 +340,7 @@ err_out: } /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ -#if 1 +#if 0 static int idr_has_entry(int id, void *p, void *data) { return 1; @@ -374,18 +356,20 @@ static int cpld_remove(struct i2c_client *client) { struct cpld_data *data = i2c_get_clientdata(client); int i; -// int id; for (i = 15; i >= 0; i--) { - dev_info(data->port_dev[i], "Remove %s port-%d\n", data->port_data[i]->type , data->port_data[i]->port_id); + dev_info(data->port_dev[i], "Remove port-%d\n", data->port_data[i]->port_id); device_unregister(data->port_dev[i]); ida_simple_remove(&cpld_ida, data->port_data[i]->port_id); kfree(data->port_data[i]); } - if (cpld_idr_is_empty(&cpld_ida.idr)) + if (ida_is_empty(&cpld_ida)) + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_platform_ix8c.c b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_platform_ix8c.c index f389304a2f..d0ae085cd4 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_platform_ix8c.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/qci_platform_ix8c.c @@ -39,158 +39,12 @@ #include #include #include -#include #if (LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)) #include #else #include #endif -#define MUX_INFO(bus, deselect) \ - {.adap_id = bus, .deselect_on_exit = deselect} - -static struct pca954x_platform_mode pca9548sfp1_modes[] = { - MUX_INFO(0x20, 1), - MUX_INFO(0x21, 1), - MUX_INFO(0x22, 1), - MUX_INFO(0x23, 1), - MUX_INFO(0x24, 1), - MUX_INFO(0x25, 1), - MUX_INFO(0x26, 1), - MUX_INFO(0x27, 1), -}; - -static struct pca954x_platform_data pca9548sfp1_data = { - .modes = pca9548sfp1_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp2_modes[] = { - MUX_INFO(0x28, 1), - MUX_INFO(0x29, 1), - MUX_INFO(0x2a, 1), - MUX_INFO(0x2b, 1), - MUX_INFO(0x2c, 1), - MUX_INFO(0x2d, 1), - MUX_INFO(0x2e, 1), - MUX_INFO(0x2f, 1), -}; - -static struct pca954x_platform_data pca9548sfp2_data = { - .modes = pca9548sfp2_modes, - .num_modes = 8, -}; -static struct pca954x_platform_mode pca9548sfp3_modes[] = { - MUX_INFO(0x30, 1), - MUX_INFO(0x31, 1), - MUX_INFO(0x32, 1), - MUX_INFO(0x33, 1), - MUX_INFO(0x34, 1), - MUX_INFO(0x35, 1), - MUX_INFO(0x36, 1), - MUX_INFO(0x37, 1), -}; - -static struct pca954x_platform_data pca9548sfp3_data = { - .modes = pca9548sfp3_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp4_modes[] = { - MUX_INFO(0x38, 1), - MUX_INFO(0x39, 1), - MUX_INFO(0x3a, 1), - MUX_INFO(0x3b, 1), - MUX_INFO(0x3c, 1), - MUX_INFO(0x3d, 1), - MUX_INFO(0x3e, 1), - MUX_INFO(0x3f, 1), -}; - -static struct pca954x_platform_data pca9548sfp4_data = { - .modes = pca9548sfp4_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp5_modes[] = { - MUX_INFO(0x40, 1), - MUX_INFO(0x41, 1), - MUX_INFO(0x42, 1), - MUX_INFO(0x43, 1), - MUX_INFO(0x44, 1), - MUX_INFO(0x45, 1), - MUX_INFO(0x46, 1), - MUX_INFO(0x47, 1), -}; - -static struct pca954x_platform_data pca9548sfp5_data = { - .modes = pca9548sfp5_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp6_modes[] = { - MUX_INFO(0x48, 1), - MUX_INFO(0x49, 1), - MUX_INFO(0x4a, 1), - MUX_INFO(0x4b, 1), - MUX_INFO(0x4c, 1), - MUX_INFO(0x4d, 1), - MUX_INFO(0x4e, 1), - MUX_INFO(0x4f, 1), -}; - -static struct pca954x_platform_data pca9548sfp6_data = { - .modes = pca9548sfp6_modes, - .num_modes = 8, -}; - -//ZQSFP -static struct pca954x_platform_mode pca9548sfp7_modes[] = { - MUX_INFO(0x50, 1), - MUX_INFO(0x51, 1), - MUX_INFO(0x52, 1), - MUX_INFO(0x53, 1), - MUX_INFO(0x54, 1), - MUX_INFO(0x55, 1), - MUX_INFO(0x56, 1), - MUX_INFO(0x57, 1), -}; - -static struct pca954x_platform_data pca9548sfp7_data = { - .modes = pca9548sfp7_modes, - .num_modes = 8, -}; - -// end port - -static struct pca954x_platform_mode pca9546_modes[] = { - MUX_INFO(0x10, 1), - MUX_INFO(0x11, 1), - MUX_INFO(0x12, 1), - MUX_INFO(0x13, 1), -}; - -static struct pca954x_platform_data pca9546_data = { - .modes = pca9546_modes, - .num_modes = 4, -}; - -static struct pca954x_platform_mode pca9548_modes[] = { - MUX_INFO(0x14, 1), - MUX_INFO(0x15, 1), - MUX_INFO(0x16, 1), - MUX_INFO(0x17, 1), - MUX_INFO(0x18, 1), - MUX_INFO(0x19, 1), - MUX_INFO(0x1a, 1), - MUX_INFO(0x1b, 1), -}; - -static struct pca954x_platform_data pca9548_data = { - .modes = pca9548_modes, - .num_modes = 8, -}; - //MB Board Data static struct pca953x_platform_data pca9555_1_data = { .gpio_base = 0x10, @@ -203,45 +57,37 @@ static struct pca953x_platform_data pca9698_2_data = { static struct pca953x_platform_data pca9555_CPU_data = { .gpio_base = 0x48, }; + static struct i2c_board_info ix8c_i2c_devices[] = { { I2C_BOARD_INFO("pca9546", 0x72), // 0 - .platform_data = &pca9546_data, }, { I2C_BOARD_INFO("pca9548", 0x77), // 1 - .platform_data = &pca9548_data, }, { I2C_BOARD_INFO("24c02", 0x54), // 2 eeprom }, { I2C_BOARD_INFO("pca9548", 0x73), // 3 0x77 ch0 - .platform_data = &pca9548sfp1_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 4 0x77 ch1 - .platform_data = &pca9548sfp2_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 5 0x77 ch2 - .platform_data = &pca9548sfp3_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 6 0x77 ch3 - .platform_data = &pca9548sfp4_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 7 0x77 ch4 - .platform_data = &pca9548sfp5_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 8 0x77 ch5 - .platform_data = &pca9548sfp6_data, }, { I2C_BOARD_INFO("pca9548", 0x73), // 9 0x77 ch6 - .platform_data = &pca9548sfp7_data, }, { I2C_BOARD_INFO("CPLD-SFP28", 0x38), // 10 0x72 ch0 CPLD1_:SFP28 1~16 @@ -287,9 +133,13 @@ static struct platform_driver ix8c_platform_driver = { static struct platform_device *ix8c_device; +static struct i2c_client **g_client; +static struct i2c_client **g_client_port; +int numof_i2c_devices = 18; +int numof_ports = 56; + static int __init ix8c_platform_init(void) { - struct i2c_client *client; struct i2c_adapter *adapter; int ret, i; @@ -308,72 +158,166 @@ static int __init ix8c_platform_init(void) if (ret) goto fail_platform_device; + g_client = kmalloc(sizeof(*g_client) * numof_i2c_devices, GFP_KERNEL); + for (i = 0; i < numof_i2c_devices; i++) g_client[i] = NULL; + + g_client_port = kmalloc(sizeof(*g_client_port) * numof_ports, GFP_KERNEL); + for (i = 0; i < numof_ports; i++) g_client_port[i] = NULL; + adapter = i2c_get_adapter(0); - client = i2c_new_device(adapter, &ix8c_i2c_devices[0]); // pca9546 - client = i2c_new_device(adapter, &ix8c_i2c_devices[1]); // pca9548 - client = i2c_new_device(adapter, &ix8c_i2c_devices[16]); // CPU Linking Board at CPU's I2C Bus - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x10); - client = i2c_new_device(adapter, &ix8c_i2c_devices[10]); // CPLD_1 - client = i2c_new_device(adapter, &ix8c_i2c_devices[17]); // CPLD_4 - client = i2c_new_device(adapter, &ix8c_i2c_devices[18]); // CPLD_6 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x11); - client = i2c_new_device(adapter, &ix8c_i2c_devices[11]); // CPLD_2 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x12); - client = i2c_new_device(adapter, &ix8c_i2c_devices[12]); // CPLD_3 - client = i2c_new_device(adapter, &ix8c_i2c_devices[2]); // MB_BOARDINFO_EEPROM - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x13); - client = i2c_new_device(adapter, &ix8c_i2c_devices[13]); // MB Board Data - client = i2c_new_device(adapter, &ix8c_i2c_devices[14]); // QSFP:49~52 - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x14); - client = i2c_new_device(adapter, &ix8c_i2c_devices[3]); // pca9548_1 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x15); - client = i2c_new_device(adapter, &ix8c_i2c_devices[4]); // pca9548_2 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x16); - client = i2c_new_device(adapter, &ix8c_i2c_devices[5]); // pca9548_3 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x17); - client = i2c_new_device(adapter, &ix8c_i2c_devices[6]); // pca9548_4 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x18); - client = i2c_new_device(adapter, &ix8c_i2c_devices[7]); // pca9548_5 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x19); - client = i2c_new_device(adapter, &ix8c_i2c_devices[8]); // pca9548_6 SFP - i2c_put_adapter(adapter); - - adapter = i2c_get_adapter(0x1a); - client = i2c_new_device(adapter, &ix8c_i2c_devices[9]); // pca9548_7 QSFP - i2c_put_adapter(adapter); - - for(i = 80; i < 88; i ++){ // QSFP 49~56 EEPROM - adapter = i2c_get_adapter(i); - client = i2c_new_device(adapter, &ix8c_i2c_devices[15]); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[0] = i2c_new_device(adapter, &ix8c_i2c_devices[0]); // pca9546 + g_client[1] = i2c_new_device(adapter, &ix8c_i2c_devices[1]); // pca9548 + g_client[2] = i2c_new_device(adapter, &ix8c_i2c_devices[16]); // CPU Linking Board at CPU's I2C Bus i2c_put_adapter(adapter); } - for(i = 32; i < 80; i ++){ // SFP28 1~48 EEPROM - adapter = i2c_get_adapter(i); - client = i2c_new_device(adapter, &ix8c_i2c_devices[19]); + adapter = i2c_get_adapter(0x01); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[3] = i2c_new_device(adapter, &ix8c_i2c_devices[10]); // CPLD_1 + g_client[4] = i2c_new_device(adapter, &ix8c_i2c_devices[17]); // CPLD_4 + g_client[5] = i2c_new_device(adapter, &ix8c_i2c_devices[18]); // CPLD_6 i2c_put_adapter(adapter); } + adapter = i2c_get_adapter(0x02); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[6] = i2c_new_device(adapter, &ix8c_i2c_devices[11]); // CPLD_2 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x03); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[7] = i2c_new_device(adapter, &ix8c_i2c_devices[12]); // CPLD_3 + g_client[8] = i2c_new_device(adapter, &ix8c_i2c_devices[2]); // MB_BOARDINFO_EEPROM + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x04); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[9] = i2c_new_device(adapter, &ix8c_i2c_devices[13]); // MB Board Data + g_client[10] = i2c_new_device(adapter, &ix8c_i2c_devices[14]); // QSFP:49~52 + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x05); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[11] = i2c_new_device(adapter, &ix8c_i2c_devices[3]); // pca9548_1 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x06); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[12] = i2c_new_device(adapter, &ix8c_i2c_devices[4]); // pca9548_2 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x07); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[13] = i2c_new_device(adapter, &ix8c_i2c_devices[5]); // pca9548_3 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x08); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[14] = i2c_new_device(adapter, &ix8c_i2c_devices[6]); // pca9548_4 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x09); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[15] = i2c_new_device(adapter, &ix8c_i2c_devices[7]); // pca9548_5 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x0a); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[16] = i2c_new_device(adapter, &ix8c_i2c_devices[8]); // pca9548_6 SFP + i2c_put_adapter(adapter); + } + + adapter = i2c_get_adapter(0x0b); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[17] = i2c_new_device(adapter, &ix8c_i2c_devices[9]); // pca9548_7 QSFP + i2c_put_adapter(adapter); + } + + for(i = 13; i < 69; i ++){ + adapter = i2c_get_adapter(i); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + if (i < 61) // SFP28 1~48 EEPROM + g_client_port[i - 13] = i2c_new_device(adapter, &ix8c_i2c_devices[19]); + else // QSFP 49~56 EEPROM + g_client_port[i - 13] = i2c_new_device(adapter, &ix8c_i2c_devices[15]); + i2c_put_adapter(adapter); + } + } + return 0; fail_platform_device: @@ -386,6 +330,26 @@ fail_platform_driver: static void __exit ix8c_platform_exit(void) { + int i = 0; + + for (i = numof_ports - 1; i >= 0; i--) + { + if (g_client_port[i]) + { + i2c_unregister_device(g_client_port[i]); + g_client_port[i] = NULL; + } + } + + for (i = numof_i2c_devices - 1; i >= 0; i--) + { + if (g_client[i]) + { + i2c_unregister_device(g_client[i]); + g_client[i] = NULL; + } + } + platform_device_unregister(ix8c_device); platform_driver_unregister(&ix8c_platform_driver); } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/quanta_hwmon_ipmi.c b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/quanta_hwmon_ipmi.c new file mode 100644 index 0000000000..157ae94778 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/modules/quanta_hwmon_ipmi.c @@ -0,0 +1,1587 @@ +/* +* +* A hwmon driver for the Quanta switch BMC hwmon +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define enable_debug_msg 0 +#define DEBUGUSE_SHIFT 0 + +#define DRVNAME "quanta_hwmon_ipmi" + +#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & (1<<((bits)-1))) | (val)) : (val)) +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) +#define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) +#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & 0xff000000) >> 24) | ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) +#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4), 4)) +#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) + +#define SENSOR_ATTR_MAX 17 +#define SENSOR_ATTR_NAME_LENGTH 20 + +#define SENSOR_GET_CAP_LABEL 0x001 +#define SENSOR_GET_CAP_ALARM 0x002 +#define SENSOR_GET_CAP_INPUT 0x004 + +#define SENSOR_GET_CAP_LNC 0x008 +#define SENSOR_GET_CAP_LCR 0x010 +#define SENSOR_GET_CAP_LNR 0x020 + +#define SENSOR_GET_CAP_UNC 0x040 +#define SENSOR_GET_CAP_UCR 0x080 +#define SENSOR_GET_CAP_UNR 0x100 + +#define SENSOR_GET_CAP_MODEL 0x200 +#define SENSOR_GET_CAP_SN 0x400 +#define SENSOR_GET_CAP_PWM 0x800 + +#define SENSOR_GET_CAP_CONMODE 0x1000 +#define SENSOR_GET_CAP_DIRECTION 0x2000 +#define SENSOR_GET_CAP_FAN_PRESENT 0x4000 +#define SENSOR_GET_CAP_PSU_PRESENT 0x8000 + +#define SENSOR_GET_CAP_MFRID 0x10000 + +#define SDR_SENSOR_TYPE_TEMP 0x01 +#define SDR_SENSOR_TYPE_VOLT 0x02 +#define SDR_SENSOR_TYPE_CURR 0x03 +#define SDR_SENSOR_TYPE_FAN 0x04 +#define SDR_SENSOR_TYPE_PS 0x08 +#define SDR_SENSOR_TYPE_OTHER 0x0b + +#define BMC_GET_DEVICE_ID 0x01 + +#define IPMI_NETFN_SE 0x04 +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_STORAGE 0x0a +#define IPMI_NETFN_TSOL 0x30 + +#define GET_SDR_REPO_INFO 0x20 +#define GET_DEVICE_SDR 0x21 +#define GET_SDR_RESERVE_REPO 0x22 +#define GET_SDR 0x23 +#define GET_SENSOR_THRESHOLDS 0x27 +#define GET_SENSOR_EVENT_ENABLE 0x29 +#define GET_SENSOR_EVENT_STATUS 0x2b +#define GET_SENSOR_READING 0x2d +#define GET_PSU_READING 0x52 +#define GET_FAN_INFO 0xd6 +#define GET_FRU_INFO 0x11 + +#define IPM_DEV_DEVICE_ID_SDR_MASK (0x80) /* 1 = provides SDRs */ +#define IPMI_TIMEOUT (4 * HZ) +#define IPMI_MAX_WAIT_QUEUE 1 + +struct quanta_hwmon_ipmi_data { + struct platform_device *ipmi_platform_dev; + struct device *ipmi_hwmon_dev; + //struct mutex ipmi_lock; + + int32_t total_sensor_id; + int32_t total_suport_sensor; + int32_t total_create_sysfs; +} *data; + +static struct mutex ipmi_lock; +static struct completion g_read_complete; + +static ipmi_user_t ipmi_mh_user = NULL; + +static int8_t g_fan_control_mode = 3; +static int32_t g_use_built_in = 0; +static int32_t ipmi_wait_queue = 0; + +struct ipmi_sensor_data { + uint8_t addr; + uint8_t sensor_type; + uint8_t sensor_idstring[SENSOR_ATTR_NAME_LENGTH]; + + uint32_t capability; + + struct header_info { + uint8_t header_type; + uint8_t header_byte; + } headerinfo; + + struct record_info { + uint8_t record_analog; + uint8_t record_linearization; + + int32_t record_m; + int32_t record_b; + int32_t record_k1; + int32_t record_k2; + } recordinfo; + + struct threshold_upper_info { + uint8_t unr; + uint8_t ucr; + uint8_t unc; + } upperinfo; + + struct threshold_lower_info { + uint8_t lnr; + uint8_t lcr; + uint8_t lnc; + } lowerinfo; + + struct attr_info + { + bool attr_exist; + char attr_name[SENSOR_ATTR_MAX][SENSOR_ATTR_NAME_LENGTH]; + char attr_type_str[SENSOR_ATTR_NAME_LENGTH]; + + struct attribute *attrs[SENSOR_ATTR_MAX + 1]; + struct attribute_group attr_group; + struct sensor_device_attribute sd_attrs[SENSOR_ATTR_MAX + 1]; + } attrinfo; + +} *g_sensor_data; + +struct ipmi_comm_data { + int32_t tx_id; + + int32_t rx_result; + int64_t rx_len; + void *rx_data; + struct completion *rx_read_complete; +}; + +struct ipmi_sdr_iterator { + uint16_t reservation; + int32_t total; + int32_t next; +}; + +struct ipm_devid_rsp { + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +} __attribute__((packed)); + +struct sdr_repo_info_rs { + uint8_t version; /* SDR version (51h) */ + uint16_t count; /* number of records */ + uint16_t free; /* free space in SDR */ + uint32_t add_stamp; /* last add timestamp */ + uint32_t erase_stamp; /* last del timestamp */ + uint8_t op_support; /* supported operations */ +} __attribute__((packed)); + +struct sdr_device_info_rs { + uint8_t count; /* number of records */ + uint8_t flags; /* flags */ + uint8_t popChangeInd[3]; /* free space in SDR */ +} __attribute__((packed)); + +struct sdr_get_rs { + uint16_t next; /* next record id */ + uint16_t id; /* record ID */ + uint8_t version; /* SDR version (51h) */ +#define SDR_RECORD_TYPE_FULL_SENSOR 0x01 +#define SDR_RECORD_TYPE_COMPACT_SENSOR 0x02 +#define SDR_RECORD_TYPE_EVENTONLY_SENSOR 0x03 +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC 0x09 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 +#define SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR 0x11 +#define SDR_RECORD_TYPE_MC_DEVICE_LOCATOR 0x12 +#define SDR_RECORD_TYPE_MC_CONFIRMATION 0x13 +#define SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO 0x14 +#define SDR_RECORD_TYPE_OEM 0xc0 + uint8_t type; /* record type */ + uint8_t length; /* remaining record bytes */ +} __attribute__((packed)); + +struct sdr_get_rq { + uint16_t reserve_id; /* reservation ID */ + uint16_t id; /* record ID */ + uint8_t offset; /* offset into SDR */ +#define GET_SDR_ENTIRE_RECORD 0xff + uint8_t length; /* length to read */ +} __attribute__((packed)); + +struct entity_id { + uint8_t id; /* physical entity id */ +#ifdef WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} __attribute__((packed)); + +struct sdr_record_mask { + union { + struct { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event mask */ + uint16_t read; /* discrete reading mask */ + } discrete; + struct { +#ifdef WORDS_BIGENDIAN + uint16_t reserved : 1; + uint16_t status_lnr : 1; + uint16_t status_lcr : 1; + uint16_t status_lnc : 1; + uint16_t assert_unr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lnc_low : 1; +#else + uint16_t assert_lnc_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_unr_high : 1; + uint16_t status_lnc : 1; + uint16_t status_lcr : 1; + uint16_t status_lnr : 1; + uint16_t reserved : 1; +#endif +#ifdef WORDS_BIGENDIAN + uint16_t reserved_2 : 1; + uint16_t status_unr : 1; + uint16_t status_ucr : 1; + uint16_t status_unc : 1; + uint16_t deassert_unr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lnc_low : 1; +#else + uint16_t deassert_lnc_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_unr_high : 1; + uint16_t status_unc : 1; + uint16_t status_ucr : 1; + uint16_t status_unr : 1; + uint16_t reserved_2 : 1; +#endif + union { + struct { +#ifdef WORDS_BIGENDIAN /* settable threshold mask */ + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; + /* padding lower 8 bits */ + uint16_t readable : 8; +#else + uint16_t readable : 8; + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; +#endif + } set; + struct { +#ifdef WORDS_BIGENDIAN /* readable threshold mask */ + /* padding upper 8 bits */ + uint16_t settable : 8; + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; +#else + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; + uint16_t settable : 8; +#endif + } read; + }; + } threshold; + } type; +} __attribute__((packed)); + +struct sdr_record_full_sensor { + struct { + uint8_t owner_id; +#ifdef WORDS_BIGENDIAN + uint8_t channel : 4; /* channel number */ + uint8_t __reserved : 2; + uint8_t lun : 2; /* sensor owner lun */ +#else + uint8_t lun : 2; /* sensor owner lun */ + uint8_t __reserved : 2; + uint8_t channel : 4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } keys; + + struct entity_id entity; + + struct { + struct { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 1; + uint8_t scanning : 1; + uint8_t events : 1; + uint8_t thresholds : 1; + uint8_t hysteresis : 1; + uint8_t type : 1; + uint8_t event_gen : 1; + uint8_t sensor_scan : 1; +#else + uint8_t sensor_scan : 1; + uint8_t event_gen : 1; + uint8_t type : 1; + uint8_t hysteresis : 1; + uint8_t thresholds : 1; + uint8_t events : 1; + uint8_t scanning : 1; + uint8_t __reserved : 1; +#endif + } init; + struct { +#ifdef WORDS_BIGENDIAN + uint8_t ignore : 1; + uint8_t rearm : 1; + uint8_t hysteresis : 2; + uint8_t threshold : 2; + uint8_t event_msg : 2; +#else + uint8_t event_msg : 2; + uint8_t threshold : 2; + uint8_t hysteresis : 2; + uint8_t rearm : 1; + uint8_t ignore : 1; +#endif + } capabilities; + uint8_t type; + } sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct { +#ifdef WORDS_BIGENDIAN + uint8_t analog : 2; + uint8_t rate : 3; + uint8_t modifier : 2; + uint8_t pct : 1; +#else + uint8_t pct : 1; + uint8_t modifier : 2; + uint8_t rate : 3; + uint8_t analog : 2; +#endif + struct { + uint8_t base; + uint8_t modifier; + } type; + } unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 5; + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t nominal_read : 1; /* nominal reading field specified */ +#else + uint8_t nominal_read : 1; /* nominal reading field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t __reserved : 5; +#endif + } analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct { + struct { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } upper; + struct { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } lower; + struct { + uint8_t positive; + uint8_t negative; + } hysteresis; + } threshold; + uint8_t __reserved[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} __attribute__((packed)); + +int32_t pow_convert(int32_t *a, int32_t b) +{ + /* function input parameter (a * 10 ^ b) */ + int32_t i = 0, r = 1, temp_b = 0; + + temp_b = (b > 0) ? b : -b; + + for (i = 0; i < temp_b; i++) r = r * 10; + + if (b > 0) { + *a = (*a) * r; + r = 1; + } + /* function return parameter calc_result = *a, decimal_point = r */ + return r; +} + +void simple_atoi(const char *buf, int8_t *output_val) +{ + while (*buf >= '0' && *buf <= '9') { + *output_val = *output_val * 10 + *buf - '0'; + buf++; + } +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) +{ + int32_t rv = -IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + struct ipmi_comm_data *comm_data = msg->user_msg_data; + + ipmi_wait_queue--; + + if (msg->msg.data[0] != 0) { + if ((msg->msg.data[0] != 0x83) && (msg->msg.netfn != 0x07) && (msg->msg.cmd != 0x52)) { + //skip master r/w cmd return code + printk("ipmi: Error 0x%x on cmd 0x%x/0x%x\n", msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); + rv = msg->msg.data[0]; + goto get_BMC_response_fail; + } + } + + if (msg->msgid != comm_data->tx_id) { + printk("ipmi: rx msgid %d mismatch tx msgid %d\n", (int32_t)msg->msgid, comm_data->tx_id); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len <= 0) { + printk("ipmi: Data len too low (%d)\n", msg->msg.data_len); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len > 1) { + if (comm_data->rx_len) { + comm_data->rx_len = msg->msg.data_len - 1; + memcpy(comm_data->rx_data, msg->msg.data + 1, comm_data->rx_len); + } + else { + printk("ipmi: rx len = 0, it should be not retrun ?\n"); + goto get_BMC_response_fail; + } + } + + rv = 0; + +get_BMC_response_fail: + ipmi_free_recv_msg(msg); + + if (ipmi_wait_queue == 0) { + comm_data->rx_result = rv; + if (rv == 0) complete(comm_data->rx_read_complete); + } +} +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_msg_handler, }; + +int32_t ipmi_request_wait_for_response(struct kernel_ipmi_msg msg, struct ipmi_comm_data *comm_data) +{ + int32_t rv = 0; + int32_t escape_time = 0; + + struct ipmi_addr ipmi_address; + + if (ipmi_wait_queue >= IPMI_MAX_WAIT_QUEUE) { + /* printk("msg queue full, cannot send ipmi cmd\n"); */ + return -EBUSY; + } + ipmi_wait_queue++; + + ipmi_address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi_address.channel = IPMI_BMC_CHANNEL; + ipmi_address.data[0] = 0; + + rv = ipmi_validate_addr(&ipmi_address, sizeof(ipmi_address)); + if (rv) { + printk("ipmi_validate_addr fail, err code : %d\n", rv); + return rv; + } + + ipmi_request_settime(ipmi_mh_user, &ipmi_address, comm_data->tx_id, &msg, comm_data, 0, 0, 0); + + escape_time = wait_for_completion_timeout(comm_data->rx_read_complete, IPMI_TIMEOUT); + + rv = comm_data->rx_result; + if (escape_time == 0) { + printk("BMC not response (%d)\n", escape_time); + } + + return rv; +} + +int32_t ipmi_send_system_cmd(uint8_t *msg_tx_data, int32_t msg_tx_len, void *msg_rx_data, int32_t msg_rx_len) +{ + int32_t i = 0; + int32_t rv = 0; + + static uint64_t tx_msgid = 1; + + struct kernel_ipmi_msg msg; + struct ipmi_comm_data *comm_data = NULL; + struct completion read_complete; + + init_completion(&read_complete); + + /* prepare transfer message */ + msg.netfn = msg_tx_data[0]; + msg.cmd = msg_tx_data[1]; + msg.data_len = msg_tx_len - 2; + + msg.data = kzalloc(msg.data_len, GFP_KERNEL); + if (msg.data == NULL) { + printk("%s(%d): malloc [msg.data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + comm_data = kzalloc(sizeof(struct ipmi_comm_data), GFP_KERNEL); + if (comm_data == NULL) { + printk("%s(%d): malloc [comm_data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + for (i = 2; i < msg_tx_len; i++) { + msg.data[i - 2] = msg_tx_data[i]; + } + + comm_data->tx_id = tx_msgid++; + + /* prepare recive message */ + comm_data->rx_data = msg_rx_data; + comm_data->rx_len = msg_rx_len; + comm_data->rx_result = -1; + comm_data->rx_read_complete = &read_complete; + + rv = ipmi_request_wait_for_response(msg, comm_data); + +alloc_mem_fail: + if (msg.data) kfree(msg.data); + if (comm_data) kfree(comm_data); + if (tx_msgid > UINT_MAX) tx_msgid = 1; + + return rv; +} + +int32_t ipmi_sdr_get_reservation(uint16_t * reserve_id) +{ + int32_t rv = 0; + uint8_t msg_data[] = { 0x00, GET_SDR_RESERVE_REPO }; //netfn = 0x00; cmd = GET_SDR_RESERVE_REPO; + + msg_data[0] = (g_use_built_in == 0) ? IPMI_NETFN_STORAGE : IPMI_NETFN_SE; + + /* obtain reservation ID */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), reserve_id, 1); + if (rv) printk("BMC down at (%d)!!\n", __LINE__); + +#if enable_debug_msg + printk("SDR reservation ID %04x\n", *reserve_id); +#endif + + return rv; +} + +int32_t ipmi_sdr_start(struct ipmi_sdr_iterator *itr) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { IPMI_NETFN_APP, BMC_GET_DEVICE_ID }; //netfn = IPMI_NETFN_APP; cmd = BMC_GET_DEVICE_ID; + + struct ipm_devid_rsp devid; + + /* check SDRR capability */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &devid, 1); + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return rv; + } + + if (devid.device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) { + if ((devid.adtl_device_support & 0x02) == 0) { + if ((devid.adtl_device_support & 0x01)) { + printk("Using Device SDRs\n"); + g_use_built_in = 1; + } + else { + printk("Error obtaining SDR info\n"); + } + } + } + + if (g_use_built_in == 0) { + struct sdr_repo_info_rs sdr_info; + /* get sdr repository info */ + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + +#if enable_debug_msg + printk("SDR version: 0x%x\n", sdr_info.version); + printk("SDR free space: %d\n", sdr_info.free); +#endif + } + else { + struct sdr_device_info_rs sdr_info; + /* get device sdr info */ + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + } + +#if enable_debug_msg + printk("SDR records : %d\n", sdr_info.count); +#endif + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + itr->next = 0; + rv = ipmi_sdr_get_reservation(&(itr->reservation)); + } + + return rv; +} + +int32_t ipmi_sdr_get_header(struct ipmi_sdr_iterator *itr, struct sdr_get_rs *sdr_rs) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //netfn = 0x00; cmd = 0x00; + + struct sdr_get_rq sdr_rq; + + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = itr->next; + sdr_rq.offset = 0; + sdr_rq.length = 5; /* only get the header */ + + if (g_use_built_in == 0) { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), sdr_rs, 1); + if ((rv) || (sdr_rs->length == 0)) { + printk("SDR record id 0x%04x: invalid length %d", itr->next, sdr_rs->length); + return -1; + } + + if (sdr_rs->id != itr->next) { +#if enable_debug_msg + printk("SDR record id mismatch: 0x%04x\n", sdr_rs->id); +#endif + sdr_rs->id = itr->next; + } +#if enable_debug_msg + printk("\nSDR record ID : 0x%04x", itr->next); + printk("SDR record type : 0x%02x\n", sdr_rs->type); + printk("SDR record next : 0x%04x\n", sdr_rs->next); + printk("SDR record bytes: %d\n", sdr_rs->length); +#endif + + return rv; +} + +int32_t ipmi_sdr_get_record(struct sdr_get_rs * header, struct ipmi_sdr_iterator * itr, uint8_t *ret_data) +{ + int32_t rv = 0, len = 0; + + uint8_t buff[128] = ""; + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //netfn = 0x00; cmd = 0x00; + + struct sdr_get_rq sdr_rq; + + len = header->length; + if (len > 0) { + memset(&sdr_rq, 0, sizeof(sdr_rq)); + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = header->id; + sdr_rq.offset = 5; + sdr_rq.length = len; + + if (g_use_built_in == 0) { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), ret_data, 1); + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + memset(buff, 0, sizeof(buff)); + memcpy(buff, ret_data + 2, sdr_rq.length); + memcpy(ret_data, buff, sdr_rq.length + 2); + } + } + + return rv; +} + +void ipmi_sdr_set_sensor_threshold(uint8_t idx, struct sdr_record_full_sensor *sensor) +{ + + /*refer to Table 35-, Get Sensor Event Enable*/ + /* + // change detect threshold method, keep it for record detail format + // in this version function input is + "void ipmi_sdr_set_sensor_threshold(uint8_t idx, uint8_t *rec)" + #define offset_threshold_enable 9 + #define offset_threshold_data 31 + if (rec[offset_threshold_enable + 1] & 0x08) g_sensor_data[idx].upperinfo.unr_high = 1; + if (rec[offset_threshold_enable + 1] & 0x04) g_sensor_data[idx].upperinfo.unr_low = 1; + if (rec[offset_threshold_enable + 1] & 0x02) g_sensor_data[idx].upperinfo.ucr_high = 1; + if (rec[offset_threshold_enable + 1] & 0x01) g_sensor_data[idx].upperinfo.ucr_low = 1; + if (rec[offset_threshold_enable] & 0x80) g_sensor_data[idx].upperinfo.unc_high = 1; + if (rec[offset_threshold_enable] & 0x40) g_sensor_data[idx].upperinfo.unc_low = 1; + + if (rec[offset_threshold_enable] & 0x20) g_sensor_data[idx].lowerinfo.lnr_high = 1; + if (rec[offset_threshold_enable] & 0x10) g_sensor_data[idx].lowerinfo.lnr_low = 1; + if (rec[offset_threshold_enable] & 0x08) g_sensor_data[idx].lowerinfo.lcr_high = 1; + if (rec[offset_threshold_enable] & 0x04) g_sensor_data[idx].lowerinfo.lcr_low = 1; + if (rec[offset_threshold_enable] & 0x02) g_sensor_data[idx].lowerinfo.lnc_high = 1; + if (rec[offset_threshold_enable] & 0x01) g_sensor_data[idx].lowerinfo.lnc_low = 1; + //*/ + + /* lower threshold info */ + if (sensor->mask.type.threshold.read.lnc) g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNC; + if (sensor->mask.type.threshold.read.lcr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_LCR; + if (sensor->mask.type.threshold.read.lnr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNR; + g_sensor_data[idx].lowerinfo.lnc = sensor->threshold.lower.non_critical; + g_sensor_data[idx].lowerinfo.lcr = sensor->threshold.lower.critical; + g_sensor_data[idx].lowerinfo.lnr = sensor->threshold.lower.non_recover; + + /* upper threshold info */ + if (sensor->mask.type.threshold.read.unc) g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNC; + if (sensor->mask.type.threshold.read.ucr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_UCR; + if (sensor->mask.type.threshold.read.unr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNR; + g_sensor_data[idx].upperinfo.unc = sensor->threshold.upper.non_critical; + g_sensor_data[idx].upperinfo.ucr = sensor->threshold.upper.critical; + g_sensor_data[idx].upperinfo.unr = sensor->threshold.upper.non_recover; +} + +void ipmi_sdr_set_sensor_factor(uint8_t idx, struct sdr_record_full_sensor *sensor) +{ + char *loc = NULL; + + g_sensor_data[idx].sensor_type = sensor->sensor.type; + sprintf(g_sensor_data[idx].sensor_idstring, "%s", sensor->id_string); + + g_sensor_data[idx].recordinfo.record_m = __TO_M(sensor->mtol); + g_sensor_data[idx].recordinfo.record_b = __TO_B(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k1 = __TO_B_EXP(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k2 = __TO_R_EXP(sensor->bacc); + + g_sensor_data[idx].recordinfo.record_analog = sensor->unit.analog; + g_sensor_data[idx].recordinfo.record_linearization = sensor->linearization; + + memset(g_sensor_data[idx].attrinfo.attr_type_str, 0x00, SENSOR_ATTR_NAME_LENGTH); + + switch (g_sensor_data[idx].sensor_type) + { + case SDR_SENSOR_TYPE_TEMP: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "temp"); + break; + case SDR_SENSOR_TYPE_VOLT: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + break; + case SDR_SENSOR_TYPE_FAN: + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PWM; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_CONMODE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_DIRECTION; + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "fan"); + break; + case SDR_SENSOR_TYPE_PS: + loc = strstr(g_sensor_data[idx].sensor_idstring, "POWER"); + if (loc) { + if ((strncmp(g_sensor_data[idx].sensor_idstring + 11, "OUT", 3)) == 0) { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MODEL; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_SN; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MFRID; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PSU_PRESENT; + } + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "power"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "VOLTAGE"); + if (loc) sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + + loc = strstr(g_sensor_data[idx].sensor_idstring, "CURRENT"); + if (loc) sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + + break; + case SDR_SENSOR_TYPE_CURR: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + break; + case SDR_SENSOR_TYPE_OTHER: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "other"); + break; + default: + printk("not support sensor type !! [%d]\n", g_sensor_data[idx].sensor_type); + break; + } + + if ((strncmp(g_sensor_data[idx].sensor_idstring, "Fan", 3)) == 0) { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_FAN_PRESENT; + } + +#if enable_debug_msg + { + printk("\n********************\n"); + + printk("m[%d], b[%d], k1[%d], k2[%d]\n", g_sensor_data[idx].recordinfo.record_m, g_sensor_data[idx].recordinfo.record_b + , g_sensor_data[idx].recordinfo.record_k1, g_sensor_data[idx].recordinfo.record_k2); + + printk("sensor [%s] type[%d], analog[%d], linearization[%d]\n", g_sensor_data[idx].sensor_idstring, g_sensor_data[idx].sensor_type + , g_sensor_data[idx].recordinfo.record_analog, g_sensor_data[idx].recordinfo.record_linearization); + + printk("\n********************\n"); + } +#endif + +} + +int32_t sdr_convert_sensor_reading(uint8_t idx, uint8_t val, int32_t *point_result) +{ + int32_t m = g_sensor_data[idx].recordinfo.record_m; + int32_t b = g_sensor_data[idx].recordinfo.record_b; + int32_t k1 = g_sensor_data[idx].recordinfo.record_k1; + int32_t k2 = g_sensor_data[idx].recordinfo.record_k2; + int32_t decimal_point = 0; + int32_t result = 0; + + decimal_point = pow_convert(&b, k1); + + switch (g_sensor_data[idx].recordinfo.record_analog) + { + case 0: + result = m * val * decimal_point + b; + break; + case 1: + if (val & 0x80) val++; + case 2: + result = (m * (int16_t)val) * decimal_point + b; + break; + default: + return; + } + + pow_convert(&result, k2); + if (k1 < 0) *point_result += -k1; + if (k2 < 0) *point_result += -k2; + + if (g_sensor_data[idx].sensor_type != SDR_SENSOR_TYPE_FAN) { + result = result * 1000; //shift for lm-sensors + } + + return result; +} + +int32_t ipmi_sdr_parsing_value(int32_t idx, uint8_t input_value, int8_t *ret_str) +{ + int32_t calc_result = 0, point_result = 0; + int32_t temp_len = 0; + + uint8_t temp_str[16] = ""; + + calc_result = sdr_convert_sensor_reading(idx, input_value, &point_result); + + temp_len = sprintf(temp_str, "%d", calc_result); + temp_len = temp_len - point_result; + + /* int part */ + if (temp_len <= 0) sprintf(ret_str, "0"); + else snprintf(ret_str, temp_len + 1, "%s", temp_str); // +1 for snprintf reserve space'\0' + + /* point part */ + strcat(ret_str, "."); + + /* float part */ + if ((point_result == 0) || (temp_len < 0)) strcat(ret_str, "0"); + else strcat(ret_str, temp_str + temp_len); + + /* EOL part */ + strcat(ret_str, "\n\0"); + + return (temp_len + 1 + point_result + 2); //integer + point + float + EOL + \0 +} + + +uint8_t ipmi_check_psu_present(uint8_t psu_slot) +{ + uint8_t slot_mask = 0x0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x03 }; //netfn = 0x36; cmd = 0xB9; + //uint8_t msg_data[] = { 0x06, 0x52, 0x1B, 0x4C, 0x01, 0x00 }; //netfn = IPMI_NETFN_APP; cmd = GET_PSU_READING; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return 0; + } + else { + slot_mask = (psu_slot == 1) ? 0x02 : 0x01; // for IX8C, PSU order is different from other QCT projects + return (returnData[0] & slot_mask) ? 0 : 1; + } +} + +int32_t ipmi_get_psu_info(uint8_t idx, uint8_t cmd, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xBB, 0x4C, 0x1C, 0x00, cmd, 0x00 }; //netfn = 0x36; cmd = 0xBB; + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + if (ipmi_check_psu_present(psu_slot)) { + msg_data[6] = psu_slot; + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + return sprintf(retbuf, "%s\n", returnData); + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +void ipmi_fan_control(uint8_t cmd_data1, uint8_t cmd_data2, uint8_t *retbuf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_TSOL, GET_FAN_INFO, cmd_data1, cmd_data2 }; //netfn = IPMI_NETFN_TSOL; cmd = GET_FAN_INFO; + + mutex_lock(&ipmi_lock); + if (cmd_data1) rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), NULL, 0); + else rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + sprintf(retbuf, "N/A\n"); + } + else { + sprintf(retbuf, "%s", returnData); + } +} + +static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%s\n", g_sensor_data[attr->index + DEBUGUSE_SHIFT].sensor_idstring); +} + +static ssize_t show_crit_alarm(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%d\n", attr->index); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int32_t rv = 0; + + uint8_t returnData[4] = ""; + uint8_t msg_data[] = { IPMI_NETFN_SE, GET_SENSOR_READING, 0x00 }; //netfn = IPMI_NETFN_SE; cmd = GET_SENSOR_READING; + + mutex_lock(&ipmi_lock); + msg_data[2] = g_sensor_data[attr->index + DEBUGUSE_SHIFT].addr; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "0.0\n"); + } + else { + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, returnData[0], buf); + } +} + +static ssize_t show_lnr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnr, buf); +} + +static ssize_t show_lcr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lcr, buf); +} + +static ssize_t show_lnc(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnc, buf); +} + +static ssize_t show_unr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unr, buf); +} + +static ssize_t show_ucr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.ucr, buf); +} + +static ssize_t show_unc(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unc, buf); +} + +static ssize_t show_model(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9a, buf); +} + +static ssize_t show_sn(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9e, buf); +} + +static ssize_t show_mfrid(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x99, buf); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) +{ + uint8_t returnData[10] = { 0 }; + ipmi_fan_control(0x00, 0x00, returnData); + return sprintf(buf, "%d\n", returnData[0]); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + if (g_fan_control_mode == 1) ipmi_fan_control(0x01, store_input, returnData); + + return count; +} + +static ssize_t show_controlmode(struct device *dev, struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%d\n", g_fan_control_mode); +} + +static ssize_t store_controlmode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + g_fan_control_mode = store_input; + if (g_fan_control_mode == 3) ipmi_fan_control(0x7f, 0xff, returnData); + + return count; +} + +static ssize_t show_direction(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_STORAGE, GET_FRU_INFO, 0x00, 0x19, 0x00, 0x01 }; //netfn = IPMI_NETFN_STORAGE; cmd = GET_FRU_INFO; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "N/A\n"); + } + else { + return sprintf(buf, "%c\n", returnData[1]); + } +} + +static ssize_t show_fanpresent(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + int32_t fan_idx = 0, fan_present = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x02 }; //netfn = 0x36; cmd = 0xB9; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + struct kernel_ipmi_msg msg; + + fan_idx = (g_sensor_data[attr->index].sensor_idstring[8] - '0') - 1; + fan_idx = 5 - fan_idx; // for IX8C, FAN order is different from other QCT projects + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + fan_present = ((returnData[0] >> fan_idx) & 0x1) ? 0 : 1; + + return sprintf(buf, "%d\n", fan_present); +} + +static ssize_t show_psupresent(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int32_t psu_idx = 0; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + psu_idx = g_sensor_data[attr->index].sensor_idstring[3] - '0'; + + return sprintf(buf, "%d\n", ipmi_check_psu_present(psu_idx)); +} + +static ssize_t(*const attr_show_func_ptr[SENSOR_ATTR_MAX]) (struct device *dev, struct device_attribute *devattr, char *buf) = +{ + show_label, show_crit_alarm, show_input + , show_lnc, show_lcr, show_lnr + , show_unc, show_ucr, show_unr + , show_model, show_sn, show_pwm + , show_controlmode, show_direction, show_fanpresent + , show_psupresent, show_mfrid +}; + +static ssize_t(*const attr_store_func_ptr[SENSOR_ATTR_MAX]) (struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) = +{ + NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, store_pwm + , store_controlmode, NULL, NULL + , NULL, NULL +}; + +static const char *const sensor_attrnames[SENSOR_ATTR_MAX] = +{ + "%s%d_label", "%s%d_crit_alarm", "%s%d_input" + , "%s%d_lncrit", "%s%d_lcrit", "%s%d_min" + , "%s%d_ncrit", "%s%d_crit", "%s%d_max" + , "%s%d_model", "%s%d_sn", "%s%d_pwm" + , "%s%d_controlmode", "%s%d_direction", "%s%d_present" + , "%s%d_present", "%s%d_mfrid" +}; + +static int32_t create_sensor_attrs(int32_t attr_no) +{ + int32_t i = 0, j = 0; + + struct attr_info *attrdata = &g_sensor_data[attr_no].attrinfo; + +#if enable_debug_msg + printk("##### %s:%d attr_no %d\n", __FUNCTION__, __LINE__, attr_no); +#endif + + for (i = 0; i < SENSOR_ATTR_MAX; i++) { + if ((g_sensor_data[attr_no].capability >> i) & 0x01) { + snprintf(attrdata->attr_name[j], SENSOR_ATTR_NAME_LENGTH, sensor_attrnames[i], attrdata->attr_type_str, attr_no - DEBUGUSE_SHIFT); + + sysfs_attr_init(&attrdata->sd_attrs[j].dev_attr.attr); + attrdata->sd_attrs[j].dev_attr.attr.name = attrdata->attr_name[j]; + attrdata->sd_attrs[j].dev_attr.show = attr_show_func_ptr[i]; + attrdata->sd_attrs[j].dev_attr.store = attr_store_func_ptr[i]; + + attrdata->sd_attrs[j].dev_attr.attr.mode = S_IRUGO; + if (attrdata->sd_attrs[j].dev_attr.store) attrdata->sd_attrs[j].dev_attr.attr.mode |= S_IWUSR; + + attrdata->sd_attrs[j].index = attr_no - DEBUGUSE_SHIFT; + attrdata->attrs[j] = &attrdata->sd_attrs[j].dev_attr.attr; + j++; + + data->total_create_sysfs++; + } + } + + attrdata->attrs[j] = NULL; + attrdata->attr_group.attrs = attrdata->attrs; + + g_sensor_data[attr_no].attrinfo.attr_exist = 1; + + return sysfs_create_group(&data->ipmi_hwmon_dev->kobj, &attrdata->attr_group); +} + +static int32_t remove_sensor_attrs(void) +{ + int32_t i = 0; + + for (i = 0; i < data->total_sensor_id; i++) { + if (g_sensor_data[i].attrinfo.attr_exist) { + sysfs_remove_group(&data->ipmi_hwmon_dev->kobj, &g_sensor_data[i].attrinfo.attr_group); + } + } + return 0; +} + +int32_t ipmi_init_sdr_sensors_data(void) +{ + int32_t sdr_idx = 0; + int32_t err = 0; + + struct ipmi_sdr_iterator *itr = NULL; + struct sdr_get_rs *header = NULL; + + uint8_t *rec = NULL; + + mutex_lock(&ipmi_lock); + + itr = kzalloc(sizeof(struct ipmi_sdr_iterator), GFP_KERNEL); + if (itr == NULL) { + printk("%s(%d): kzalloc failure.\n", __func__, __LINE__); + goto itr_malloc_fail; + } + + header = kzalloc(sizeof(struct sdr_get_rs), GFP_KERNEL); + if (header == NULL) { + printk("%s(%d): malloc failure.\n", __func__, __LINE__); + goto header_malloc_fail; + } + + err = ipmi_sdr_start(itr); + if (err) { + printk("%s(%d): ipmi_sdr_start fail.\n", __func__, __LINE__); + goto ipmi_sdr_start_fail; + } + + data->total_sensor_id = itr->total; + rec = kzalloc(GET_SDR_ENTIRE_RECORD, GFP_KERNEL); + if (rec == NULL) { + printk("%s(%d): kzalloc failure\n", __func__, __LINE__); + goto rec_malloc_fail; + } + + g_sensor_data = kzalloc(itr->total * sizeof(struct ipmi_sensor_data), GFP_KERNEL); + if (g_sensor_data == NULL) { + printk("%s(%d): malloc failure", __func__, __LINE__); + goto g_sensor_data_malloc_fail; + } + + memset(g_sensor_data, 0x0, itr->total * sizeof(struct ipmi_sensor_data)); + + for (sdr_idx = 0; sdr_idx < itr->total; sdr_idx++) { + err = ipmi_sdr_get_header(itr, header); + if (err) { + if (err == 0xC5) { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_header_fail; + } + + + memset(rec, 0, GET_SDR_ENTIRE_RECORD); + err = ipmi_sdr_get_record(header, itr, rec); + if (err) { + if (err == 0xC5) { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_record_fail; + } + + itr->next = header->next; + + switch (header->type) + { + case SDR_RECORD_TYPE_FULL_SENSOR: + /* prepare (threshold, factor)data whilie init, for reduce reading step and improve operate speed */ + g_sensor_data[sdr_idx].addr = rec[2]; + g_sensor_data[sdr_idx].capability = SENSOR_GET_CAP_LABEL /*| SENSOR_GET_CAP_ALARM */ | SENSOR_GET_CAP_INPUT; + g_sensor_data[sdr_idx].headerinfo.header_type = header->type; + g_sensor_data[sdr_idx].headerinfo.header_byte = header->length; + + ipmi_sdr_set_sensor_threshold(sdr_idx, (struct sdr_record_full_sensor*) rec); + ipmi_sdr_set_sensor_factor(sdr_idx, (struct sdr_record_full_sensor*) rec); + + if (sdr_idx >= DEBUGUSE_SHIFT) { + err = create_sensor_attrs(sdr_idx); + if (err) { + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; + printk("[err : %d]sysfs_create_group fail in [%d] %s\n", err, sdr_idx, g_sensor_data[sdr_idx].sensor_idstring); + goto create_sysfs_fail; + } + } + + data->total_suport_sensor++; + + break; + case SDR_RECORD_TYPE_COMPACT_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_EVENTONLY_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR: /* not supporrt now */ + default: + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; +#if enable_debug_msg + printk("ID[%d] : not support type [%d]\n", sdr_idx, header->type); +#endif + break; + } + } + + printk("quanta_hwmon_ipmi : detected [%d] sensor, create [%d] sysfs\n", data->total_suport_sensor, data->total_create_sysfs); + +create_sysfs_fail: +ipmi_sdr_get_header_fail: +ipmi_sdr_get_record_fail: +g_sensor_data_malloc_fail: + if (header) { + kfree(header); + header = NULL; + } + if (rec) { + kfree(rec); + rec = NULL; + } + +rec_malloc_fail: +ipmi_sdr_start_fail: +header_malloc_fail: + if (itr) { + kfree(itr); + itr = NULL; + } + +itr_malloc_fail: + mutex_unlock(&ipmi_lock); + + return err; +} + +static int32_t __init quanta_hwmon_ipmi_init(void) +{ + int32_t err = 0; + + init_completion(&g_read_complete); + + data = kzalloc(sizeof(struct quanta_hwmon_ipmi_data), GFP_KERNEL); + if (NULL == data) { + printk("alloc data fail\n"); + goto alloc_err; + } + + data->ipmi_platform_dev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + err = IS_ERR(data->ipmi_platform_dev); + if (err) { + printk("platform device register fail (err : %d)\n", err); + goto device_reg_err; + } + + data->ipmi_hwmon_dev = hwmon_device_register_with_groups(NULL, DRVNAME, NULL, NULL); + err = IS_ERR(data->ipmi_hwmon_dev); + if (err) { + printk("hwmon register fail\n"); + goto hwmon_register_err; + } + + err = ipmi_create_user(0, &ipmi_hndlrs, NULL, &ipmi_mh_user); + if (err) { + printk("warning: create user fail, watchdog broken (err : %d)\n", err); + goto ipmi_create_err; + } + + mutex_init(&ipmi_lock); + err = ipmi_init_sdr_sensors_data(); + if (err) { + printk("init sensor data fail (err : %d)\n", err); + goto init_sensor_err; + } + + return 0; + +init_sensor_err: + if (g_sensor_data) { + kfree(g_sensor_data); + g_sensor_data = NULL; + } +ipmi_create_err: + hwmon_device_unregister(data->ipmi_hwmon_dev); +hwmon_register_err: + platform_device_unregister(data->ipmi_platform_dev); +device_reg_err: + if (data) { + kfree(data); + data = NULL; + } +alloc_err: + return err; +} + +static void __exit quanta_hwmon_ipmi_exit(void) +{ + remove_sensor_attrs(); + hwmon_device_unregister(data->ipmi_hwmon_dev); + + mutex_lock(&ipmi_lock); + ipmi_destroy_user(ipmi_mh_user); + mutex_unlock(&ipmi_lock); + + platform_device_unregister(data->ipmi_platform_dev); + + if (g_sensor_data) { + kfree(g_sensor_data); + g_sensor_data = NULL; + } + + if (data) { + kfree(data); + data = NULL; + } +} + +module_init(quanta_hwmon_ipmi_init); +module_exit(quanta_hwmon_ipmi_exit); + +MODULE_AUTHOR("Charcar~~Charcar~Charlie li li"); +MODULE_VERSION("2.0"); +MODULE_DESCRIPTION("Quanta BMC hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/service/ix8c-platform-init.service b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/service/ix8c-platform-init.service old mode 100755 new mode 100644 diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/setup.py index 26a3101bf7..7d39961b70 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/setup.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import sys from setuptools import setup os.listdir @@ -9,7 +8,7 @@ setup( name='ix8c_56x', version='1.0', description='Module to initialize Quanta IX8C-56X platforms', - + packages=['ix8c_56x'], package_dir={'ix8c_56x': 'ix8c-56x/classes'}, ) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/__init__.py new file mode 100644 index 0000000000..4bfefa0fb6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/chassis.py new file mode 100644 index 0000000000..544a3ee27c --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/chassis.py @@ -0,0 +1,222 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import sys + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 56 + self.__num_of_sfps = 48 + self.__num_of_fan_drawers = 6 + self.__fan_per_drawer = 2 + self.__num_of_thermals = 18 + self.__xcvr_presence = {} + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + fan_index = 1 + for drawer_index in range(1, self.__num_of_fan_drawers + 1): + drawer_fan_list = [] + for index in range(0, self.__fan_per_drawer): + fan = Fan(fan_index, False) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(1, self.__num_of_ports + 1): + if index in range(1, self.__num_of_sfps + 1): + sfp = Sfp(index, 'SFP') + else: + sfp = Sfp(index, 'QSFP') + + self._sfp_list.append(sfp) + + for index in range(1, self.__num_of_ports + 1): + self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() + +############################################## +# Device methods +############################################## + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + For Quanta IX8C the index in sfputil.py starts from 1, so override + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + if (index == 0): + raise IndexError + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("override: SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_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 + +############################################## +# Chassis methods +############################################## + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + 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. + """ + #raise NotImplementedError + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") + + def get_change_event(self, timeout=0): + """ + Currently only support transceiver change events + """ + start_ms = time.time() * 1000 + xcvr_change_event_dict = {} + event = False + + while True: + time.sleep(0.5) + for index in range(1, self.__num_of_ports + 1): + cur_xcvr_presence = self._sfp_list[index-1].get_presence() + if cur_xcvr_presence != self.__xcvr_presence[index]: + if cur_xcvr_presence is True: + xcvr_change_event_dict[str(index)] = '1' + self.__xcvr_presence[index] = True + elif cur_xcvr_presence is False: + xcvr_change_event_dict[str(index)] = '0' + self.__xcvr_presence[index] = False + event = True + + if event is True: + return True, {'sfp':xcvr_change_event_dict} + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, {'sfp':xcvr_change_event_dict} + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/eeprom.py new file mode 100644 index 0000000000..1c044638ed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/eeprom.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + # Display vendor extension for Quanta platforms + _TLV_DISPLAY_VENDOR_EXT = True + + def __init__(self): + self.__eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + 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] + + if tlv[0] == self._TLV_CODE_VENDOR_EXT: + value = str((tlv[2] << 24) | (tlv[3] << 16) | + (tlv[4] << 8) | tlv[5]) + value += tlv[6:6 + tlv[1]].decode('ascii') + else: + value = self.decoder(None, tlv)[30:] + + 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): + (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): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in results[2]]).upper() + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + + def decoder(self, s, t): + ''' + Return a string representing the contents of the TLV field. The format of + the string is: + 1. The name of the field left justified in 20 characters + 2. The type code in hex right justified in 5 characters + 3. The length in decimal right justified in 4 characters + 4. The value, left justified in however many characters it takes + The vailidity of EEPROM contents and the TLV field has been verified + prior to calling this function. The 's' parameter is unused + ''' + if t[0] == self._TLV_CODE_PRODUCT_NAME: + name = "Product Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PART_NUMBER: + name = "Part Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERIAL_NUMBER: + name = "Serial Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_BASE: + name = "Base MAC Address" + value = ":".join(["{:02x}".format(T) for T in t[2:8]]).upper() + elif t[0] == self._TLV_CODE_MANUF_DATE: + name = "Manufacture Date" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DEVICE_VERSION: + name = "Device Version" + value = str(t[2]) + elif t[0] == self._TLV_CODE_LABEL_REVISION: + name = "Label Revision" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PLATFORM_NAME: + name = "Platform Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_ONIE_VERSION: + name = "ONIE Version" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_SIZE: + name = "MAC Addresses" + value = str((t[2] << 8) | t[3]) + elif t[0] == self._TLV_CODE_MANUF_NAME: + name = "Manufacturer" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MANUF_COUNTRY: + name = "Manufacture Country" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_NAME: + name = "Vendor Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DIAG_VERSION: + name = "Diag Version" + # Quanta legacy format of diag version + if t[1] == 4: + value = "{}.{}.{}.{}".format('{:02x}'.format(t[2])[0], '{:02x}'.format(t[2])[1], + '{:02x}'.format(t[3])[0], '{:02x}'.format(t[3])[1]) + else: + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERVICE_TAG: + name = "Service Tag" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_EXT: + name = "Vendor Extension" + value = "" + if self._TLV_DISPLAY_VENDOR_EXT: + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + elif t[0] == self._TLV_CODE_CRC_32 and len(t) == 6: + name = "CRC-32" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + # Quanta specific codes below here. + # These decodes are lifted from their U-Boot codes + elif t[0] == self._TLV_CODE_QUANTA_MAGIC and len(t) == 3: + name = "Magic Number" + value = "0x%02X" % t[2] + elif t[0] == self._TLV_CODE_QUANTA_CRC and len(t) == 4: + name = "QUANTA-CRC" + value = "0x%04X" % ((t[2] << 8) + t[3]) + elif t[0] == self._TLV_CODE_QUANTA_CARD_TYPE and len(t) == 6: + name = "Card Type" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + elif t[0] == self._TLV_CODE_QUANTA_HW_VERSION and len(t) == 6: + name = "Hardware Version" + value = "%d.%d" % (t[2], t[3]) + elif t[0] == self._TLV_CODE_QUANTA_SW_VERSION and len(t) == 6: + name = "Software Version" + value = "%d.%d.%d.%d" % ((t[2] >> 4), (t[2] & 0xF), (t[3] >> 4), (t[3] & 0xF)) + elif t[0] == self._TLV_CODE_QUANTA_MANUF_DATE and len(t) == 6: + name = "Manufacture Date" + value = "%04d/%d/%d" % (((t[2] << 8) | t[3]), t[4], t[5]) + elif t[0] == self._TLV_CODE_QUANTA_MODEL_NAME: + name = "Model Name" + value = t[2:2 + t[1]].decode("ascii") + else: + name = "Unknown" + value = "" + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + return name, value + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/fan.py new file mode 100644 index 0000000000..ed3a836ba1 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/fan.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python + +############################################################################# +# Inventec d7264 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import logging + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +HWMON_DIR = "/sys/class/hwmon/hwmon2/" +FAN_INDEX_START = 20 +NUM_FANTRAYS = 6 +FANS_PERTRAY = 2 + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + self.fan_index = index + self.psu_fan_index_mapping = { + 1:39, + 2:49, + } + self.psu_index_mapping = { + 1:41, + 2:51, + } + if self.is_psu_fan: + self.fan_presence_attr = "power{}_present".format(self.psu_index_mapping[index]) + self.fan_pwm_attr = "fan{}_pwm".format(self.psu_fan_index_mapping[index]) + self.fan_rpm_attr = "fan{}_input".format(self.psu_fan_index_mapping[index]) + self.fan_direction_attr = "fan{}_direction".format(self.psu_fan_index_mapping[index]) + else: + self.fan_presence_attr = "fan{}_present".format(FAN_INDEX_START+(index-1)) + self.fan_pwm_attr = "fan{}_pwm".format(FAN_INDEX_START+(index-1)) + self.fan_rpm_attr = "fan{}_input".format(FAN_INDEX_START+(index-1)) + self.fan_direction_attr = "fan{}_direction".format(FAN_INDEX_START+(index-1)) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + 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.fan_index) + else: + fantray_index = (self.fan_index-1)/FANS_PERTRAY+1 + fan_index_intray = self.fan_index - ((fantray_index-1)*FANS_PERTRAY) + return "Fantray{}_{}".format(fantray_index, fan_index_intray) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.fan_presence_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == '1'): + return True + else: + return False + + return None + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR' and attr_rv != '0.0'): + return True + else: + return False + else: + return False + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + attr_path = HWMON_DIR + self.fan_direction_attr + attr_rv = self.__get_attr_value(attr_path) + + if attr_rv == '2': + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + else: + return 0 + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 25 + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + + Args: + color: A string representing the color with which to set the + fan module status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return True + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..75e954576a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/fan_drawer.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/platform.py new file mode 100644 index 0000000000..ddad8c4c57 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +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): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() \ No newline at end of file diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/psu.py new file mode 100644 index 0000000000..941d8faef4 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/psu.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import logging + 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") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +class Psu(PsuBase): + def __init__(self, index): + PsuBase.__init__(self) + fan = Fan(index, True) + self._fan_list.append(fan) + + self.psu_index_mapping = { + 1:41, + 2:51, + } + self.psu_powerin_index_mapping = { + 1:40, + 2:50, + } + self.psu_current_index_mapping = { + 1:38, + 2:48, + } + self.psu_voltageout_index_mapping = { + 1:46, + 2:56, + } + self.index = index + self.psu_presence_attr = "power{}_present".format(self.psu_index_mapping[self.index]) + self.psu_status_attr = "curr{}_input".format(self.psu_current_index_mapping[self.index]) + self.psu_power_in_attr = "power{}_input".format(self.psu_powerin_index_mapping[self.index]) + self.psu_power_out_attr = "power{}_input".format(self.psu_index_mapping[self.index]) + self.psu_voltage_out_attr = "in{}_input".format(self.psu_voltageout_index_mapping[self.index]) + self.psu_current_out_attr = "curr{}_input".format(self.psu_current_index_mapping[self.index]) + self.psu_serial_attr = "power{}_sn".format(self.psu_index_mapping[self.index]) + self.psu_model_attr = "power{}_model".format(self.psu_index_mapping[self.index]) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + fd.close() + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = HWMON_DIR+self.psu_presence_attr + attr_normal = '1' + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = HWMON_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = HWMON_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = HWMON_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = HWMON_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_out = float(attr_rv) / 1000 + + return current_out + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = HWMON_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + power_out = float(attr_rv) / 1000 + + return power_out + + 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. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/sfp.py new file mode 100644 index 0000000000..a85b225afe --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/sfp.py @@ -0,0 +1,1625 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +#import subprocess +#import sonic_device_util +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase +# from sonic_platform_base.sonic_eeprom import eeprom_dts + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +QSFP_INFO_OFFSET = 128 +QSFP_DOM_OFFSET = 0 +SFP_INFO_OFFSET = 0 +SFP_DOM_OFFSET = 256 + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 1 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_MODULE_THRESHOLD_OFFSET = 512 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 560 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +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_TYPE = "SFP" +QSFP_TYPE = "QSFP" + + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 56 + QSFP_START = 49 + QSFP_END = 56 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-quanta_ix8c_bwde-r0" + HWSKU = "Quanta-IX8C-56X" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + #self.dom_supported = False + self.sfp_type = sfp_type + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/i2c-{0}/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44, + 33 : 45, + 34 : 46, + 35 : 47, + 36 : 48, + 37 : 49, + 38 : 50, + 39 : 51, + 40 : 52, + 41 : 53, + 42 : 54, + 43 : 55, + 44 : 56, + 45 : 57, + 46 : 58, + 47 : 59, + 48 : 60, + 49 : 61,#QSFP49 + 50 : 62,#QSFP50 + 51 : 63,#QSFP51 + 52 : 64,#QSFP52 + 53 : 65,#QSFP53 + 54 : 66,#QSFP54 + 55 : 67,#QSFP55 + 56 : 68,#QSFP56 + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self.info_dict_keys = ['type', 'hardware_rev', 'serialnum', 'manufacturer', + 'model', 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', + 'vendor_oui', 'application_advertisement'] + + self.dom_dict_keys = ['rx_los', 'tx_fault', 'reset_status', 'power_lpmode', + 'tx_disable', 'tx_disable_channel', 'temperature', 'voltage', + 'rx1power', 'rx2power', 'rx3power', 'rx4power', 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', 'tx1power', 'tx2power', 'tx3power', 'tx4power'] + + self.threshold_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', 'txpowerhighalarm', + 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + SfpBase.__init__(self) + + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the SFP module + Returns: + bool: True if SFP module is present, False if not + """ + # Check for invalid port_num + if self.port_num < self.PORT_START or self.port_num > self.PORT_END: + return False + + try: + if self.sfp_type == SFP_TYPE: + reg_file = open("/sys/class/cpld-sfp28/port-"+str(self.port_num)+"/pre_n") + else: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+34)+"/value") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + reg_file.close() + if self.sfp_type == SFP_TYPE: + if reg_value == '1': + return True + else: + if reg_value == '0': + return True + + return False + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + eeprom_raw = None + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == "QSFP": + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability = int(qsfp_dom_capability_raw[0], 16) + + qsfp_version_compliance_raw = self.__read_eeprom_specific_bytes( + QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_OFFSET) + if qsfp_version_compliance_raw is not None: + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = (qsfp_dom_capability & 0x20 != 0) + self.dom_volt_supported = (qsfp_dom_capability & 0x10 != 0) + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = (qsfp_dom_capability & 0x04 != 0) + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = (qsfp_dom_capability & 0x08 != 0) + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + self.dom_tx_disable_supported = True + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + elif self.sfp_type == "SFP": + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serialnum |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + nominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ======================================================================== + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + if not self.get_presence(): + return transceiver_info_dict + + if self.sfp_type == QSFP_TYPE: + offset = QSFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + + elif self.sfp_type == SFP_TYPE: + offset = SFP_INFO_OFFSET + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return transceiver_info_dict + else: + return transceiver_info_dict + + # Add retry for xcvr eeprom to get ready + max_retry = 10 + for i in range(0,max_retry): + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is not None: + break + else: + if not self.get_presence(): + return transceiver_info_dict + elif i == max_retry-1: + pass + else: + time.sleep(0.5) + + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + transceiver_info_dict['type'] = sfp_interface_bulk_data \ + ['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data \ + ['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data \ + ['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data \ + ['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data \ + ['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data \ + ['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data \ + ['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data \ + ['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data \ + ['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data \ + ['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data \ + ['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = 'N/A' + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str( + sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data \ + ['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data \ + ['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + offset = QSFP_DOM_OFFSET + offset_xcvr = QSFP_INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes( + (offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_dom_capability_data = sfpi_obj.parse_dom_capability( + qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qsfp_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + if not sfpd_obj: + return {} + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, SFP_DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = SFP_DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(self.dom_dict_keys, 'N/A') + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature( + dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params( + dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + else: + return None + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self._convert_string_to_num( + transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + if self.sfp_type == QSFP_TYPE: + sfpd_obj = sff8436Dom() + if not self.get_presence() or not sfpd_obj: + return {} + DOM_OFFSET = 0 + transceiver_dom_threshold_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + offset = DOM_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + module_threshold_values = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_channel_thres_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNEL_THRESHOLD_OFFSET), QSFP_CHANNEL_THRESHOLD_WIDTH) + if dom_channel_thres_raw is not None: + channel_threshold_values = sfpd_obj.parse_channel_threshold_values(dom_channel_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + else: + channel_threshold_data = None + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + elif self.sfp_type == SFP_TYPE: + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + DOM_OFFSET = 256 + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + if eeprom_ifraw is not None: + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + else: + return None + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+32)+"/value") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return None + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return True + else: + return False + else: + return None + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + else: + return None + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + else: + return None + + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + elif self.sfp_type == SFP_TYPE: + offset = 256 + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + else: + return None + + return tx_disable_list + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return 0 + elif self.sfp_type == QSFP_TYPE: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + else: + return None + + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this QSFP module + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+35)+"/value") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return False + else: + return True + else: + return None + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_POWEROVERRIDE_OFFSET), QSFP_POWEROVERRIDE_WIDTH) + if dom_control_raw is not None: + if int(dom_control_raw[0],16) & (0x01 << QSFP_POWEROVERRIDE_BIT): + return True + else: + return False + else: + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num( + dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num( + dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + else: + return None + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Bias']['value'])) + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params( \ + dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + elif self.sfp_type == SFP_TYPE: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = \ + sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num( + dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + else: + return None + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default state. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/direction", 'r+') as f: + f.write('out') + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/value", "r+") as f: + f.write('0') + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + with open("/sys/class/gpio/gpio"+str((self.port_num-self.QSFP_START)*4+32)+"/value", "r+") as f: + f.write('1') + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + else: + return None + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + offset = 256 + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self.__read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( + status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(offset + SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + else: + return None + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + else: + return False + else: + return None + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + reg_file = open("/sys/class/gpio/gpio" + +str((self.port_num-self.QSFP_START)*4+35)+"/value", "r+") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + else: + return None + + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings(self.__get_path_to_port_config_file()) + print ("self.index{}".format(self.index)) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/thermal.py new file mode 100644 index 0000000000..f30bdc8d71 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform/thermal.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +############################################################################# +# Inventec d7264 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import logging +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +thermal_index_mapping = { + 1:1, + 2:2, + 3:42, + 4:43, + 5:44, + 6:52, + 7:53, + 8:54, + 9:75, + 10:76, + 11:77, + 12:78, + 13:79, + 14:80, + 15:81, + 16:82, + 17:83, + 18:84, +} + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index + self.temp_attr = "temp{}_input".format(thermal_index_mapping[self.index]) + self.high_th_attr = "temp{}_crit".format(thermal_index_mapping[self.index]) + self.name_attr = "temp{}_label".format(thermal_index_mapping[self.index]) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return attr_rv + else: + return None + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if (self.get_temperature() != None): + return True + else: + return False + + 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 + """ + attr_path = HWMON_DIR + self.temp_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + 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 + """ + attr_path = HWMON_DIR + self.high_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform_setup.py new file mode 100644 index 0000000000..b1ba374776 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/sonic_platform_setup.py @@ -0,0 +1,24 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Quanta Platforms', + license='Apache 2.0', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/utils/quanta_ix8c_util.py b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/utils/quanta_ix8c_util.py index c495533638..f8e8b0f0f9 100755 --- a/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/utils/quanta_ix8c_util.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix8c-56x/utils/quanta_ix8c_util.py @@ -21,94 +21,86 @@ Usage: %(scriptName)s [options] command object options: -h | --help : this help message -d | --debug : run with debug mode - -f | --force : ignore error during installation or clean + -f | --force : ignore error during installation or clean command: install : install drivers and generate related sysfs nodes - clean : uninstall drivers and remove related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes """ import os import commands import sys, getopt import logging -import re import time -from collections import namedtuple DEBUG = False args = [] FORCE = 0 i2c_prefix = '/sys/bus/i2c/devices/' - if DEBUG == True: print sys.argv[0] - print 'ARGV :', sys.argv[1:] - + print 'ARGV :', sys.argv[1:] def main(): global DEBUG global args global FORCE - - if len(sys.argv)<2: + + if len(sys.argv) < 2: show_help() - + options, args = getopt.getopt(sys.argv[1:], 'hdf', ['help', 'debug', 'force', ]) - if DEBUG == True: + if DEBUG == True: print options print args print len(sys.argv) - + for opt, arg in options: if opt in ('-h', '--help'): show_help() - elif opt in ('-d', '--debug'): + elif opt in ('-d', '--debug'): DEBUG = True logging.basicConfig(level=logging.INFO) - elif opt in ('-f', '--force'): + elif opt in ('-f', '--force'): FORCE = 1 else: - logging.info('no option') - for arg in args: + logging.info('no option') + for arg in args: if arg == 'install': install() elif arg == 'clean': uninstall() else: show_help() - - - return 0 - + + + return 0 + def show_help(): print __doc__ % {'scriptName' : sys.argv[0].split("/")[-1]} sys.exit(0) - + def show_log(txt): if DEBUG == True: print "[IX8C-56X]"+txt return - + def exec_cmd(cmd, show): - logging.info('Run :'+cmd) - status, output = commands.getstatusoutput(cmd) + logging.info('Run :'+cmd) + status, output = commands.getstatusoutput(cmd) show_log (cmd +"with result:" + str(status)) - show_log (" output:"+output) + show_log (" output:"+output) if status: logging.info('Failed :'+cmd) if show: print('Failed :'+cmd) return status, output - + instantiate =[ -#turn on module power -'echo 21 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio21/direction', -'echo 1 >/sys/class/gpio/gpio21/value', #export pca9698 for qsfp present 'echo 34 > /sys/class/gpio/export', 'echo in > /sys/class/gpio/gpio34/direction', @@ -126,31 +118,6 @@ instantiate =[ 'echo in > /sys/class/gpio/gpio58/direction', 'echo 62 > /sys/class/gpio/export', 'echo in > /sys/class/gpio/gpio62/direction', -#export pca9698 for qsfp reset -'echo 32 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio32/direction', -'echo 1 >/sys/class/gpio/gpio32/value', -'echo 36 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio36/direction', -'echo 1 >/sys/class/gpio/gpio36/value', -'echo 40 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio40/direction', -'echo 1 >/sys/class/gpio/gpio40/value', -'echo 44 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio44/direction', -'echo 1 >/sys/class/gpio/gpio44/value', -'echo 48 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio48/direction', -'echo 1 >/sys/class/gpio/gpio48/value', -'echo 52 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio52/direction', -'echo 1 >/sys/class/gpio/gpio52/value', -'echo 56 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio56/direction', -'echo 1 >/sys/class/gpio/gpio56/value', -'echo 60 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio60/direction', -'echo 1 >/sys/class/gpio/gpio60/value', #export pca9698 for qsfp lpmode 'echo 35 > /sys/class/gpio/export', 'echo out > /sys/class/gpio/gpio35/direction', @@ -176,11 +143,6 @@ instantiate =[ 'echo 63 > /sys/class/gpio/export', 'echo out > /sys/class/gpio/gpio63/direction', 'echo 0 >/sys/class/gpio/gpio63/value', -#Reset fron-ports LED CPLD -'echo 73 > /sys/class/gpio/export', -'echo out > /sys/class/gpio/gpio73/direction', -'echo 0 >/sys/class/gpio/gpio73/value', -'echo 1 >/sys/class/gpio/gpio73/value', #Enable front-ports LED decoding 'echo 1 > /sys/class/cpld-led/CPLDLED-1/led_decode', 'echo 1 > /sys/class/cpld-led/CPLDLED-2/led_decode', @@ -239,41 +201,66 @@ drivers =[ 'lpc_ich', 'i2c-i801', 'i2c-dev', +'i2c-mux-pca954x force_deselect_on_exit=1', +'gpio-pca953x', +'optoe', +'qci_cpld_sfp28', +'qci_cpld_led', +'qci_platform_ix8c', +'quanta_hwmon_ipmi', +'ipmi_devintf' +] + +un_drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', 'i2c-mux-pca954x', 'gpio-pca953x', 'optoe', 'qci_cpld_sfp28', 'qci_cpld_led', 'qci_platform_ix8c', +'quanta_hwmon_ipmi', 'ipmi_devintf' ] - - def system_install(): global FORCE - #remove default drivers to avoid modprobe order conflicts - status, output = exec_cmd("rmmod i2c_ismt ", 1) - status, output = exec_cmd("rmmod i2c-i801 ", 1) #setup driver dependency - status, output = exec_cmd("depmod -a ", 1) + exec_cmd("depmod -a ", 1) #install drivers for i in range(0,len(drivers)): - status, output = exec_cmd("modprobe "+drivers[i], 1) + status, output = exec_cmd("modprobe " + drivers[i], 1) if status: print output if FORCE == 0: return status - #remove net rules for generating new net rules - status, output = exec_cmd("systemctl stop systemd-udevd.service ", 1) - status, output = exec_cmd("rm /etc/udev/rules.d/70-persistent-net.rules ", 1) - status, output = exec_cmd("rmmod ixgbe ", 1) - status, output = exec_cmd("rmmod igb ", 1) - status, output = exec_cmd("modprobe igb ", 1) - status, output = exec_cmd("modprobe ixgbe ", 1) - status, output = exec_cmd("systemctl start systemd-udevd.service ", 1) + #reload ethernet drivers in correct order + exec_cmd("rmmod ixgbe ", 1) + exec_cmd("rmmod igb ", 1) + exec_cmd("modprobe igb ", 1) + exec_cmd("modprobe ixgbe ", 1) + + #turn on module power + exec_cmd("echo 21 > /sys/class/gpio/export ", 1) + exec_cmd("echo high > /sys/class/gpio/gpio21/direction ", 1) + + time.sleep(1) + # qsfp reset gpio + for qsfp_reset in [32, 36, 40, 44, 48, 52, 56, 60]: + exec_cmd("echo "+str(qsfp_reset)+" > /sys/class/gpio/export", 1) + exec_cmd("echo high > /sys/class/gpio/gpio"+str(qsfp_reset)+"/direction", 1) + + # Reset fron-ports LED CPLD + exec_cmd("echo 73 > /sys/class/gpio/export ", 1) + status, output = exec_cmd("cat /sys/class/gpio/gpio73/value", 1) + if output != '1': + exec_cmd("echo out > /sys/class/gpio/gpio73/direction ", 1) + exec_cmd("echo 0 >/sys/class/gpio/gpio73/value", 1) + exec_cmd("echo 1 >/sys/class/gpio/gpio73/value", 1) #instantiate devices for i in range(0,len(instantiate)): @@ -285,24 +272,29 @@ def system_install(): #QSFP for 1~56 port for port_number in range(1,57): - bus_number = port_number + 31 + bus_number = port_number + 12 os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) return - - + + def system_ready(): - if not device_found(): + if not device_found(): return False return True - -def install(): + +def install(): if not device_found(): - print "No device, installing...." - status = system_install() + print "No device, installing...." + status = system_install() if status: - if FORCE == 0: - return status + if FORCE == 0: + return status + status, output = exec_cmd("pip3 install /usr/share/sonic/device/x86_64-quanta_ix8c_bwde-r0/sonic_platform-1.0-py3-none-any.whl",1) + if status: + print output + if FORCE == 0: + return status else: print " ix8c driver already installed...." return @@ -310,20 +302,29 @@ def install(): def uninstall(): global FORCE #uninstall drivers - for i in range(len(drivers)-1,-1,-1): - status, output = exec_cmd("rmmod "+drivers[i], 1) + for i in range(len(un_drivers) - 1, -1, -1): + status, output = exec_cmd("rmmod " + un_drivers[i], 1) if status: print output - if FORCE == 0: + if FORCE == 0: return status + + status, output = exec_cmd("pip3 uninstall sonic-platform -y ",1) + if status: + print output + if FORCE == 0: + return status + return def device_found(): - ret1, log = exec_cmd("ls "+i2c_prefix+"i2c-0", 0) - return ret1 + ret1, log1 = exec_cmd("cat /proc/modules | grep ix8c > /tmp/chkdriver.log", 0) + ret2, log2 = exec_cmd("cat /tmp/chkdriver.log | grep ix8c", 0) + + if ret1 == 0 and len(log2) > 0: + return True + else: + return False if __name__ == "__main__": main() - - - diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/Makefile b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/Makefile index 929782931a..8ab9ee0db1 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/Makefile +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/Makefile @@ -1,3 +1,3 @@ -obj-m:=qci_cpld_qsfpdd.o qci_cpld_led.o qci_platform_ix9.o +obj-m:=qci_cpld_qsfpdd.o qci_cpld_led.o qci_platform_ix9.o quanta_hwmon_ipmi.o diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_led.c b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_led.c index d8f89240a8..fdbc6c6c16 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_led.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_led.c @@ -26,6 +26,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -244,6 +245,8 @@ err_out: } /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0) +#else static int idr_has_entry(int id, void *p, void *data) { return 1; @@ -253,6 +256,7 @@ static bool cpld_idr_is_empty(struct idr *idp) { return !idr_for_each(idp, idr_has_entry, NULL); } +#endif static int cpld_led_remove(struct i2c_client *client) { @@ -262,8 +266,11 @@ static int cpld_led_remove(struct i2c_client *client) device_unregister(data->port_dev); ida_simple_remove(&cpld_led_ida, data->cpld_data->cpld_id); kfree(data->cpld_data); - +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0) + if (ida_is_empty(&cpld_led_ida)) +#else if (cpld_idr_is_empty(&cpld_led_ida.idr)) +#endif class_destroy(cpld_class); return 0; diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_qsfpdd.c b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_qsfpdd.c index d616f887db..89e04cee09 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_qsfpdd.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_cpld_qsfpdd.c @@ -26,6 +26,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include #include #include #include @@ -375,6 +376,8 @@ exit_remove: } /* FIXME: for older kernel doesn't with idr_is_empty function, implement here */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0) +#else static int idr_has_entry(int id, void *p, void *data) { return 1; @@ -384,6 +387,7 @@ static bool cpld_idr_is_empty(struct idr *idp) { return !idr_for_each(idp, idr_has_entry, NULL); } +#endif static int cpld_remove(struct i2c_client *client) { @@ -397,9 +401,15 @@ static int cpld_remove(struct i2c_client *client) ida_simple_remove(&cpld_ida, data->port_data[i]->port_id); kfree(data->port_data[i]); } - +#if LINUX_VERSION_CODE > KERNEL_VERSION(4,10,0) + if (ida_is_empty(&cpld_ida)) +#else if (cpld_idr_is_empty(&cpld_ida.idr)) +#endif + { class_destroy(cpld_class); + cpld_class = NULL; + } return 0; } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_platform_ix9.c b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_platform_ix9.c index 1b98c4a2f3..803b2b42f4 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_platform_ix9.c +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/qci_platform_ix9.c @@ -39,102 +39,11 @@ #include #include #include -#include #if LINUX_VERSION_CODE > KERNEL_VERSION(3,12,0) #include #else #include #endif -#define MUX_INFO(bus, deselect) \ - {.adap_id = bus, .deselect_on_exit = deselect} - -static struct pca954x_platform_mode pca9546_1_modes[] = { - MUX_INFO(0x10, 1), - MUX_INFO(0x11, 1), - MUX_INFO(0x12, 1), - MUX_INFO(0x13, 1), -}; - -static struct pca954x_platform_data pca9546_1_data = { - .modes = pca9546_1_modes, - .num_modes = 4, -}; - -static struct pca954x_platform_mode pca9548_1_modes[] = { - MUX_INFO(0x14, 1), - MUX_INFO(0x15, 1), - MUX_INFO(0x16, 1), - MUX_INFO(0x17, 1), -}; - -static struct pca954x_platform_data pca9548_1_data = { - .modes = pca9548_1_modes, - .num_modes = 4, -}; - -static struct pca954x_platform_mode pca9548sfp1_modes[] = { - MUX_INFO(0x20, 1), - MUX_INFO(0x21, 1), - MUX_INFO(0x22, 1), - MUX_INFO(0x23, 1), - MUX_INFO(0x24, 1), - MUX_INFO(0x25, 1), - MUX_INFO(0x26, 1), - MUX_INFO(0x27, 1), -}; - -static struct pca954x_platform_data pca9548sfp1_data = { - .modes = pca9548sfp1_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp2_modes[] = { - MUX_INFO(0x28, 1), - MUX_INFO(0x29, 1), - MUX_INFO(0x2a, 1), - MUX_INFO(0x2b, 1), - MUX_INFO(0x2c, 1), - MUX_INFO(0x2d, 1), - MUX_INFO(0x2e, 1), - MUX_INFO(0x2f, 1), -}; - -static struct pca954x_platform_data pca9548sfp2_data = { - .modes = pca9548sfp2_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp3_modes[] = { - MUX_INFO(0x30, 1), - MUX_INFO(0x31, 1), - MUX_INFO(0x32, 1), - MUX_INFO(0x33, 1), - MUX_INFO(0x34, 1), - MUX_INFO(0x35, 1), - MUX_INFO(0x36, 1), - MUX_INFO(0x37, 1), -}; - -static struct pca954x_platform_data pca9548sfp3_data = { - .modes = pca9548sfp3_modes, - .num_modes = 8, -}; - -static struct pca954x_platform_mode pca9548sfp4_modes[] = { - MUX_INFO(0x38, 1), - MUX_INFO(0x39, 1), - MUX_INFO(0x3a, 1), - MUX_INFO(0x3b, 1), - MUX_INFO(0x3c, 1), - MUX_INFO(0x3d, 1), - MUX_INFO(0x3e, 1), - MUX_INFO(0x3f, 1), -}; - -static struct pca954x_platform_data pca9548sfp4_data = { - .modes = pca9548sfp4_modes, - .num_modes = 8, -}; static struct pca953x_platform_data tca9539_1_data = { .gpio_base = 0x10, @@ -146,12 +55,10 @@ static struct pca953x_platform_data pca9555_CPU_data = { static struct i2c_board_info ix9_i2c_devices[] = { { - I2C_BOARD_INFO("pca9546", 0x72), - .platform_data = &pca9546_1_data, // 0 pca9546_1 + I2C_BOARD_INFO("pca9546", 0x72), // 0 pca9546_1 }, { - I2C_BOARD_INFO("pca9548", 0x77), - .platform_data = &pca9548_1_data, // 1 pca9548_1 + I2C_BOARD_INFO("pca9548", 0x77), // 1 pca9548_1 }, { I2C_BOARD_INFO("tca9539", 0x74), @@ -161,20 +68,16 @@ static struct i2c_board_info ix9_i2c_devices[] = { I2C_BOARD_INFO("24c02", 0x54), // 3 MB_BOARDINFO_EEPROM }, { - I2C_BOARD_INFO("pca9548", 0x73), - .platform_data = &pca9548sfp1_data, // 4 0x77 ch0 pca9548 #1 + I2C_BOARD_INFO("pca9548", 0x73), // 4 0x77 ch0 pca9548 #1 }, { - I2C_BOARD_INFO("pca9548", 0x73), - .platform_data = &pca9548sfp2_data, // 5 0x77 ch1 pca9548 #2 + I2C_BOARD_INFO("pca9548", 0x73), // 5 0x77 ch1 pca9548 #2 }, { - I2C_BOARD_INFO("pca9548", 0x73), - .platform_data = &pca9548sfp3_data, // 6 0x77 ch2 pca9548 #3 + I2C_BOARD_INFO("pca9548", 0x73), // 6 0x77 ch2 pca9548 #3 }, { - I2C_BOARD_INFO("pca9548", 0x73), - .platform_data = &pca9548sfp4_data, // 7 0x77 ch3 pca9548 #4 + I2C_BOARD_INFO("pca9548", 0x73), // 7 0x77 ch3 pca9548 #4 }, { I2C_BOARD_INFO("CPLD-QSFPDD", 0x38), // 8 0x72 ch0 CPLD-IO #2, #3 @@ -200,9 +103,13 @@ static struct platform_driver ix9_platform_driver = { static struct platform_device *ix9_device; +static struct i2c_client **g_client; +static struct i2c_client **g_client_port; +int numof_i2c_devices = 13; +int numof_ports = 32; + static int __init ix9_platform_init(void) { - struct i2c_client *client; struct i2c_adapter *adapter; int ret, i; @@ -221,51 +128,127 @@ static int __init ix9_platform_init(void) if (ret) goto fail_platform_device; + g_client = kmalloc(sizeof(*g_client) * numof_i2c_devices, GFP_KERNEL); + for (i = 0; i < numof_i2c_devices; i++) g_client[i] = NULL; + + g_client_port = kmalloc(sizeof(*g_client_port) * numof_ports, GFP_KERNEL); + for (i = 0; i < numof_ports; i++) g_client_port[i] = NULL; + adapter = i2c_get_adapter(0); - client = i2c_new_device(adapter, &ix9_i2c_devices[0]); // pca9546_1 - Address: 0x72 - client = i2c_new_device(adapter, &ix9_i2c_devices[1]); // pca9548_1 - Address: 0x77 - client = i2c_new_device(adapter, &ix9_i2c_devices[11]); // CPU Linking Board at CPU's I2C Bus - Address: 0x22 - i2c_put_adapter(adapter); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[0] = i2c_new_device(adapter, &ix9_i2c_devices[0]); // pca9546_1 - Address: 0x72 + g_client[1] = i2c_new_device(adapter, &ix9_i2c_devices[1]); // pca9548_1 - Address: 0x77 + g_client[2] = i2c_new_device(adapter, &ix9_i2c_devices[11]); // CPU Linking Board at CPU's I2C Bus - Address: 0x22 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x10); - client = i2c_new_device(adapter, &ix9_i2c_devices[8]); // CPLD-IO #2 - Address: 0x38 - client = i2c_new_device(adapter, &ix9_i2c_devices[9]); // CPLD-LED #4 - Address: 0x39 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x01); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[3] = i2c_new_device(adapter, &ix9_i2c_devices[8]); // CPLD-IO #2 - Address: 0x38 + g_client[4] = i2c_new_device(adapter, &ix9_i2c_devices[9]); // CPLD-LED #4 - Address: 0x39 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x11); - client = i2c_new_device(adapter, &ix9_i2c_devices[8]); // CPLD-IO #3 - Address: 0x38 - client = i2c_new_device(adapter, &ix9_i2c_devices[9]); // CPLD-LED #5 - Address: 0x39 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x02); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[5] = i2c_new_device(adapter, &ix9_i2c_devices[8]); // CPLD-IO #3 - Address: 0x38 + g_client[6] = i2c_new_device(adapter, &ix9_i2c_devices[9]); // CPLD-LED #5 - Address: 0x39 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x12); - client = i2c_new_device(adapter, &ix9_i2c_devices[3]); // MB_BOARDINFO_EEPROM - Address: 0x54 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x03); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[7] = i2c_new_device(adapter, &ix9_i2c_devices[3]); // MB_BOARDINFO_EEPROM - Address: 0x54 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x13); - client = i2c_new_device(adapter, &ix9_i2c_devices[2]); // tca9539_1 Board ID and QSFP-DD PW EN/PG - Address: 0x74 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x04); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[8] = i2c_new_device(adapter, &ix9_i2c_devices[2]); // tca9539_1 Board ID and QSFP-DD PW EN/PG - Address: 0x74 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x14); - client = i2c_new_device(adapter, &ix9_i2c_devices[4]); // pca9548 #1 QSFPDD - Address: 0x73 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x05); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[9] = i2c_new_device(adapter, &ix9_i2c_devices[4]); // pca9548 #1 QSFPDD - Address: 0x73 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x15); - client = i2c_new_device(adapter, &ix9_i2c_devices[5]); // pca9548 #2 QSFPDD - Address: 0x73 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x06); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[10] = i2c_new_device(adapter, &ix9_i2c_devices[5]); // pca9548 #2 QSFPDD - Address: 0x73 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x16); - client = i2c_new_device(adapter, &ix9_i2c_devices[6]); // pca9548 #3 QSFPDD - Address: 0x73 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x07); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[11] = i2c_new_device(adapter, &ix9_i2c_devices[6]); // pca9548 #3 QSFPDD - Address: 0x73 + i2c_put_adapter(adapter); + } - adapter = i2c_get_adapter(0x17); - client = i2c_new_device(adapter, &ix9_i2c_devices[7]); // pca9548 #4 QSFPDD - Address: 0x73 - i2c_put_adapter(adapter); + adapter = i2c_get_adapter(0x08); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client[12] = i2c_new_device(adapter, &ix9_i2c_devices[7]); // pca9548 #4 QSFPDD - Address: 0x73 + i2c_put_adapter(adapter); + } - for(i = 0x20; i < 0x40; i++) + for(i = 13; i < 45; i++) { adapter = i2c_get_adapter(i); - client = i2c_new_device(adapter, &ix9_i2c_devices[10]); // eeprom for loopback module - Address: 0x50 - i2c_put_adapter(adapter); + if (adapter == NULL) + { + printk("[%s] get i2c adapter fail at line %d", __FUNCTION__, __LINE__); + } + else + { + g_client_port[i - 13] = i2c_new_device(adapter, &ix9_i2c_devices[10]); // eeprom for loopback module - Address: 0x50 + i2c_put_adapter(adapter); + } } return 0; @@ -280,6 +263,26 @@ fail_platform_driver: static void __exit ix9_platform_exit(void) { + int i = 0; + + for (i = numof_ports - 1; i >= 0; i--) + { + if (g_client_port[i]) + { + i2c_unregister_device(g_client_port[i]); + g_client_port[i] = NULL; + } + } + + for (i = numof_i2c_devices - 1; i >= 0; i--) + { + if (g_client[i]) + { + i2c_unregister_device(g_client[i]); + g_client[i] = NULL; + } + } + platform_device_unregister(ix9_device); platform_driver_unregister(&ix9_platform_driver); } diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/quanta_hwmon_ipmi.c b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/quanta_hwmon_ipmi.c new file mode 100644 index 0000000000..05a9e044c7 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/modules/quanta_hwmon_ipmi.c @@ -0,0 +1,1669 @@ +/* +* +* A hwmon driver for the Quanta switch BMC hwmon +* +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define enable_debug_msg 0 +#define DEBUGUSE_SHIFT 0 + +#define DRVNAME "quanta_hwmon_ipmi" + +#define tos32(val, bits) ((val & ((1<<((bits)-1)))) ? (-((val) & (1<<((bits)-1))) | (val)) : (val)) +#define BSWAP_16(x) ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8)) +#define BSWAP_32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24)) +#define __TO_M(mtol) (int16_t)(tos32((((BSWAP_16(mtol) & 0xff00) >> 8) | ((BSWAP_16(mtol) & 0xc0) << 2)), 10)) +#define __TO_B(bacc) (int32_t)(tos32((((BSWAP_32(bacc) & 0xff000000) >> 24) | ((BSWAP_32(bacc) & 0xc00000) >> 14)), 10)) +#define __TO_R_EXP(bacc) (int32_t)(tos32(((BSWAP_32(bacc) & 0xf0) >> 4), 4)) +#define __TO_B_EXP(bacc) (int32_t)(tos32((BSWAP_32(bacc) & 0xf), 4)) + +#define SENSOR_ATTR_MAX 19 +#define SENSOR_ATTR_NAME_LENGTH 20 + +#define SENSOR_GET_CAP_LABEL 0x001 +#define SENSOR_GET_CAP_ALARM 0x002 +#define SENSOR_GET_CAP_INPUT 0x004 + +#define SENSOR_GET_CAP_LNC 0x008 +#define SENSOR_GET_CAP_LCR 0x010 +#define SENSOR_GET_CAP_LNR 0x020 + +#define SENSOR_GET_CAP_UNC 0x040 +#define SENSOR_GET_CAP_UCR 0x080 +#define SENSOR_GET_CAP_UNR 0x100 + +#define SENSOR_GET_CAP_MODEL 0x200 +#define SENSOR_GET_CAP_SN 0x400 +#define SENSOR_GET_CAP_PWM 0x800 + +#define SENSOR_GET_CAP_CONMODE 0x1000 +#define SENSOR_GET_CAP_DIRECTION 0x2000 +#define SENSOR_GET_CAP_FAN_PRESENT 0x4000 +#define SENSOR_GET_CAP_PSU_PRESENT 0x8000 + +#define SENSOR_GET_CAP_MFRID 0x10000 +#define SENSOR_GET_CAP_VIN_TYPE 0x20000 +#define SENSOR_GET_CAP_POUT_MAX 0x40000 + +#define SDR_SENSOR_TYPE_TEMP 0x01 +#define SDR_SENSOR_TYPE_VOLT 0x02 +#define SDR_SENSOR_TYPE_CURR 0x03 +#define SDR_SENSOR_TYPE_FAN 0x04 +#define SDR_SENSOR_TYPE_PS 0x08 +#define SDR_SENSOR_TYPE_OTHER 0x0b + +#define BMC_GET_DEVICE_ID 0x01 + +#define IPMI_NETFN_SE 0x04 +#define IPMI_NETFN_APP 0x06 +#define IPMI_NETFN_STORAGE 0x0a +#define IPMI_NETFN_TSOL 0x30 + +#define GET_SDR_REPO_INFO 0x20 +#define GET_DEVICE_SDR 0x21 +#define GET_SDR_RESERVE_REPO 0x22 +#define GET_SDR 0x23 +#define GET_SENSOR_THRESHOLDS 0x27 +#define GET_SENSOR_EVENT_ENABLE 0x29 +#define GET_SENSOR_EVENT_STATUS 0x2b +#define GET_SENSOR_READING 0x2d +#define GET_PSU_READING 0x52 +#define GET_FAN_INFO 0xd6 +#define GET_FRU_INFO 0x11 + +#define IPM_DEV_DEVICE_ID_SDR_MASK (0x80) /* 1 = provides SDRs */ +#define IPMI_TIMEOUT (4 * HZ) +#define IPMI_MAX_WAIT_QUEUE 1 + +struct quanta_hwmon_ipmi_data { + struct platform_device *ipmi_platform_dev; + struct device *ipmi_hwmon_dev; + //struct mutex ipmi_lock; + + int32_t total_sensor_id; + int32_t total_suport_sensor; + int32_t total_create_sysfs; +} *data; + +static struct mutex ipmi_lock; +static struct completion g_read_complete; + +static ipmi_user_t ipmi_mh_user = NULL; + +static int8_t g_fan_control_mode = 3; +static int32_t g_use_built_in = 0; +static int32_t ipmi_wait_queue = 0; + +struct ipmi_sensor_data { + uint8_t addr; + uint8_t sensor_type; + uint8_t sensor_idstring[SENSOR_ATTR_NAME_LENGTH]; + + uint32_t capability; + + struct header_info { + uint8_t header_type; + uint8_t header_byte; + } headerinfo; + + struct record_info { + uint8_t record_analog; + uint8_t record_linearization; + + int32_t record_m; + int32_t record_b; + int32_t record_k1; + int32_t record_k2; + } recordinfo; + + struct threshold_upper_info { + uint8_t unr; + uint8_t ucr; + uint8_t unc; + } upperinfo; + + struct threshold_lower_info { + uint8_t lnr; + uint8_t lcr; + uint8_t lnc; + } lowerinfo; + + struct attr_info + { + bool attr_exist; + char attr_name[SENSOR_ATTR_MAX][SENSOR_ATTR_NAME_LENGTH]; + char attr_type_str[SENSOR_ATTR_NAME_LENGTH]; + + struct attribute *attrs[SENSOR_ATTR_MAX + 1]; + struct attribute_group attr_group; + struct sensor_device_attribute sd_attrs[SENSOR_ATTR_MAX + 1]; + } attrinfo; + +} *g_sensor_data; + +struct ipmi_comm_data { + int32_t tx_id; + + int32_t rx_result; + int64_t rx_len; + void *rx_data; + struct completion *rx_read_complete; +}; + +struct ipmi_sdr_iterator { + uint16_t reservation; + int32_t total; + int32_t next; +}; + +struct ipm_devid_rsp { + uint8_t device_id; + uint8_t device_revision; + uint8_t fw_rev1; + uint8_t fw_rev2; + uint8_t ipmi_version; + uint8_t adtl_device_support; + uint8_t manufacturer_id[3]; + uint8_t product_id[2]; + uint8_t aux_fw_rev[4]; +} __attribute__((packed)); + +struct sdr_repo_info_rs { + uint8_t version; /* SDR version (51h) */ + uint16_t count; /* number of records */ + uint16_t free; /* free space in SDR */ + uint32_t add_stamp; /* last add timestamp */ + uint32_t erase_stamp; /* last del timestamp */ + uint8_t op_support; /* supported operations */ +} __attribute__((packed)); + +struct sdr_device_info_rs { + uint8_t count; /* number of records */ + uint8_t flags; /* flags */ + uint8_t popChangeInd[3]; /* free space in SDR */ +} __attribute__((packed)); + +struct sdr_get_rs { + uint16_t next; /* next record id */ + uint16_t id; /* record ID */ + uint8_t version; /* SDR version (51h) */ +#define SDR_RECORD_TYPE_FULL_SENSOR 0x01 +#define SDR_RECORD_TYPE_COMPACT_SENSOR 0x02 +#define SDR_RECORD_TYPE_EVENTONLY_SENSOR 0x03 +#define SDR_RECORD_TYPE_ENTITY_ASSOC 0x08 +#define SDR_RECORD_TYPE_DEVICE_ENTITY_ASSOC 0x09 +#define SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR 0x10 +#define SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR 0x11 +#define SDR_RECORD_TYPE_MC_DEVICE_LOCATOR 0x12 +#define SDR_RECORD_TYPE_MC_CONFIRMATION 0x13 +#define SDR_RECORD_TYPE_BMC_MSG_CHANNEL_INFO 0x14 +#define SDR_RECORD_TYPE_OEM 0xc0 + uint8_t type; /* record type */ + uint8_t length; /* remaining record bytes */ +} __attribute__((packed)); + +struct sdr_get_rq { + uint16_t reserve_id; /* reservation ID */ + uint16_t id; /* record ID */ + uint8_t offset; /* offset into SDR */ +#define GET_SDR_ENTIRE_RECORD 0xff + uint8_t length; /* length to read */ +} __attribute__((packed)); + +struct entity_id { + uint8_t id; /* physical entity id */ +#ifdef WORDS_BIGENDIAN + uint8_t logical : 1; /* physical/logical */ + uint8_t instance : 7; /* instance number */ +#else + uint8_t instance : 7; /* instance number */ + uint8_t logical : 1; /* physical/logical */ +#endif +} __attribute__((packed)); + +struct sdr_record_mask { + union { + struct { + uint16_t assert_event; /* assertion event mask */ + uint16_t deassert_event; /* de-assertion event mask */ + uint16_t read; /* discrete reading mask */ + } discrete; + struct { +#ifdef WORDS_BIGENDIAN + uint16_t reserved : 1; + uint16_t status_lnr : 1; + uint16_t status_lcr : 1; + uint16_t status_lnc : 1; + uint16_t assert_unr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lnc_low : 1; +#else + uint16_t assert_lnc_low : 1; + uint16_t assert_lnc_high : 1; + uint16_t assert_lcr_low : 1; + uint16_t assert_lcr_high : 1; + uint16_t assert_lnr_low : 1; + uint16_t assert_lnr_high : 1; + uint16_t assert_unc_low : 1; + uint16_t assert_unc_high : 1; + uint16_t assert_ucr_low : 1; + uint16_t assert_ucr_high : 1; + uint16_t assert_unr_low : 1; + uint16_t assert_unr_high : 1; + uint16_t status_lnc : 1; + uint16_t status_lcr : 1; + uint16_t status_lnr : 1; + uint16_t reserved : 1; +#endif +#ifdef WORDS_BIGENDIAN + uint16_t reserved_2 : 1; + uint16_t status_unr : 1; + uint16_t status_ucr : 1; + uint16_t status_unc : 1; + uint16_t deassert_unr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lnc_low : 1; +#else + uint16_t deassert_lnc_low : 1; + uint16_t deassert_lnc_high : 1; + uint16_t deassert_lcr_low : 1; + uint16_t deassert_lcr_high : 1; + uint16_t deassert_lnr_low : 1; + uint16_t deassert_lnr_high : 1; + uint16_t deassert_unc_low : 1; + uint16_t deassert_unc_high : 1; + uint16_t deassert_ucr_low : 1; + uint16_t deassert_ucr_high : 1; + uint16_t deassert_unr_low : 1; + uint16_t deassert_unr_high : 1; + uint16_t status_unc : 1; + uint16_t status_ucr : 1; + uint16_t status_unr : 1; + uint16_t reserved_2 : 1; +#endif + union { + struct { +#ifdef WORDS_BIGENDIAN /* settable threshold mask */ + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; + /* padding lower 8 bits */ + uint16_t readable : 8; +#else + uint16_t readable : 8; + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; +#endif + } set; + struct { +#ifdef WORDS_BIGENDIAN /* readable threshold mask */ + /* padding upper 8 bits */ + uint16_t settable : 8; + uint16_t reserved : 2; + uint16_t unr : 1; + uint16_t ucr : 1; + uint16_t unc : 1; + uint16_t lnr : 1; + uint16_t lcr : 1; + uint16_t lnc : 1; +#else + uint16_t lnc : 1; + uint16_t lcr : 1; + uint16_t lnr : 1; + uint16_t unc : 1; + uint16_t ucr : 1; + uint16_t unr : 1; + uint16_t reserved : 2; + uint16_t settable : 8; +#endif + } read; + }; + } threshold; + } type; +} __attribute__((packed)); + +struct sdr_record_full_sensor { + struct { + uint8_t owner_id; +#ifdef WORDS_BIGENDIAN + uint8_t channel : 4; /* channel number */ + uint8_t __reserved : 2; + uint8_t lun : 2; /* sensor owner lun */ +#else + uint8_t lun : 2; /* sensor owner lun */ + uint8_t __reserved : 2; + uint8_t channel : 4; /* channel number */ +#endif + uint8_t sensor_num; /* unique sensor number */ + } keys; + + struct entity_id entity; + + struct { + struct { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 1; + uint8_t scanning : 1; + uint8_t events : 1; + uint8_t thresholds : 1; + uint8_t hysteresis : 1; + uint8_t type : 1; + uint8_t event_gen : 1; + uint8_t sensor_scan : 1; +#else + uint8_t sensor_scan : 1; + uint8_t event_gen : 1; + uint8_t type : 1; + uint8_t hysteresis : 1; + uint8_t thresholds : 1; + uint8_t events : 1; + uint8_t scanning : 1; + uint8_t __reserved : 1; +#endif + } init; + struct { +#ifdef WORDS_BIGENDIAN + uint8_t ignore : 1; + uint8_t rearm : 1; + uint8_t hysteresis : 2; + uint8_t threshold : 2; + uint8_t event_msg : 2; +#else + uint8_t event_msg : 2; + uint8_t threshold : 2; + uint8_t hysteresis : 2; + uint8_t rearm : 1; + uint8_t ignore : 1; +#endif + } capabilities; + uint8_t type; + } sensor; + + uint8_t event_type; /* event/reading type code */ + + struct sdr_record_mask mask; + + struct { +#ifdef WORDS_BIGENDIAN + uint8_t analog : 2; + uint8_t rate : 3; + uint8_t modifier : 2; + uint8_t pct : 1; +#else + uint8_t pct : 1; + uint8_t modifier : 2; + uint8_t rate : 3; + uint8_t analog : 2; +#endif + struct { + uint8_t base; + uint8_t modifier; + } type; + } unit; + +#define SDR_SENSOR_L_LINEAR 0x00 +#define SDR_SENSOR_L_LN 0x01 +#define SDR_SENSOR_L_LOG10 0x02 +#define SDR_SENSOR_L_LOG2 0x03 +#define SDR_SENSOR_L_E 0x04 +#define SDR_SENSOR_L_EXP10 0x05 +#define SDR_SENSOR_L_EXP2 0x06 +#define SDR_SENSOR_L_1_X 0x07 +#define SDR_SENSOR_L_SQR 0x08 +#define SDR_SENSOR_L_CUBE 0x09 +#define SDR_SENSOR_L_SQRT 0x0a +#define SDR_SENSOR_L_CUBERT 0x0b +#define SDR_SENSOR_L_NONLINEAR 0x70 + + uint8_t linearization; /* 70h=non linear, 71h-7Fh=non linear, OEM */ + uint16_t mtol; /* M, tolerance */ + uint32_t bacc; /* accuracy, B, Bexp, Rexp */ + + struct { +#ifdef WORDS_BIGENDIAN + uint8_t __reserved : 5; + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t nominal_read : 1; /* nominal reading field specified */ +#else + uint8_t nominal_read : 1; /* nominal reading field specified */ + uint8_t normal_max : 1; /* normal max field specified */ + uint8_t normal_min : 1; /* normal min field specified */ + uint8_t __reserved : 5; +#endif + } analog_flag; + + uint8_t nominal_read; /* nominal reading, raw value */ + uint8_t normal_max; /* normal maximum, raw value */ + uint8_t normal_min; /* normal minimum, raw value */ + uint8_t sensor_max; /* sensor maximum, raw value */ + uint8_t sensor_min; /* sensor minimum, raw value */ + + struct { + struct { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } upper; + struct { + uint8_t non_recover; + uint8_t critical; + uint8_t non_critical; + } lower; + struct { + uint8_t positive; + uint8_t negative; + } hysteresis; + } threshold; + uint8_t __reserved[2]; + uint8_t oem; /* reserved for OEM use */ + uint8_t id_code; /* sensor ID string type/length code */ + uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */ +} __attribute__((packed)); + +int32_t pow_convert(int32_t *a, int32_t b) +{ + /* function input parameter (a * 10 ^ b) */ + int32_t i = 0, r = 1, temp_b = 0; + + temp_b = (b > 0) ? b : -b; + + for (i = 0; i < temp_b; i++) r = r * 10; + + if (b > 0) { + *a = (*a) * r; + r = 1; + } + /* function return parameter calc_result = *a, decimal_point = r */ + return r; +} + +void simple_atoi(const char *buf, int8_t *output_val) +{ + while (*buf >= '0' && *buf <= '9') { + *output_val = *output_val * 10 + *buf - '0'; + buf++; + } +} + +static void ipmi_msg_handler(struct ipmi_recv_msg *msg, void *handler_data) +{ + int32_t rv = -IPMI_UNKNOWN_ERR_COMPLETION_CODE; + + struct ipmi_comm_data *comm_data = msg->user_msg_data; + + ipmi_wait_queue--; + + if (msg->msg.data[0] != 0) { + if ((msg->msg.data[0] != 0x83) && (msg->msg.netfn != 0x07) && (msg->msg.cmd != 0x52)) { + //skip master r/w cmd return code + printk("ipmi: Error 0x%x on cmd 0x%x/0x%x\n", msg->msg.data[0], msg->msg.netfn, msg->msg.cmd); + rv = msg->msg.data[0]; + goto get_BMC_response_fail; + } + } + + if (msg->msgid != comm_data->tx_id) { + printk("ipmi: rx msgid %d mismatch tx msgid %d\n", (int32_t)msg->msgid, comm_data->tx_id); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len <= 0) { + printk("ipmi: Data len too low (%d)\n", msg->msg.data_len); + goto get_BMC_response_fail; + } + + if (msg->msg.data_len > 1) { + if (comm_data->rx_len) { + comm_data->rx_len = msg->msg.data_len - 1; + memcpy(comm_data->rx_data, msg->msg.data + 1, comm_data->rx_len); + } + else { + printk("ipmi: rx len = 0, it should be not retrun ?\n"); + goto get_BMC_response_fail; + } +} + + rv = 0; + +get_BMC_response_fail: + ipmi_free_recv_msg(msg); + + if (ipmi_wait_queue == 0) { + comm_data->rx_result = rv; + if (rv == 0) complete(comm_data->rx_read_complete); + } +} +static struct ipmi_user_hndl ipmi_hndlrs = { .ipmi_recv_hndl = ipmi_msg_handler, }; + +int32_t ipmi_request_wait_for_response(struct kernel_ipmi_msg msg, struct ipmi_comm_data *comm_data) +{ + int32_t rv = 0; + int32_t escape_time = 0; + + struct ipmi_addr ipmi_address; + + if (ipmi_wait_queue >= IPMI_MAX_WAIT_QUEUE) { + /* printk("msg queue full, cannot send ipmi cmd\n"); */ + return -EBUSY; + } + ipmi_wait_queue++; + + ipmi_address.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE; + ipmi_address.channel = IPMI_BMC_CHANNEL; + ipmi_address.data[0] = 0; + + rv = ipmi_validate_addr(&ipmi_address, sizeof(ipmi_address)); + if (rv) { + printk("ipmi_validate_addr fail, err code : %d\n", rv); + return rv; + } + + ipmi_request_settime(ipmi_mh_user, &ipmi_address, comm_data->tx_id, &msg, comm_data, 0, 0, 0); + + escape_time = wait_for_completion_timeout(comm_data->rx_read_complete, IPMI_TIMEOUT); + + rv = comm_data->rx_result; + if (escape_time == 0) { + printk("BMC not response (%d)\n", escape_time); + } + + return rv; +} + +int32_t ipmi_send_system_cmd(uint8_t *msg_tx_data, int32_t msg_tx_len, void *msg_rx_data, int32_t msg_rx_len) +{ + int32_t i = 0; + int32_t rv = 0; + + static uint64_t tx_msgid = 1; + + struct kernel_ipmi_msg msg; + struct ipmi_comm_data *comm_data = NULL; + struct completion read_complete; + + init_completion(&read_complete); + + /* prepare transfer message */ + msg.netfn = msg_tx_data[0]; + msg.cmd = msg_tx_data[1]; + msg.data_len = msg_tx_len - 2; + + msg.data = kzalloc(msg.data_len, GFP_KERNEL); + if (msg.data == NULL) { + printk("%s(%d): malloc [msg.data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + comm_data = kzalloc(sizeof(struct ipmi_comm_data), GFP_KERNEL); + if (comm_data == NULL) { + printk("%s(%d): malloc [comm_data] failure", __func__, __LINE__); + rv = -ENOMEM; + goto alloc_mem_fail; + } + + for (i = 2; i < msg_tx_len; i++) { + msg.data[i - 2] = msg_tx_data[i]; + } + + comm_data->tx_id = tx_msgid++; + + /* prepare recive message */ + comm_data->rx_data = msg_rx_data; + comm_data->rx_len = msg_rx_len; + comm_data->rx_result = -1; + comm_data->rx_read_complete = &read_complete; + + rv = ipmi_request_wait_for_response(msg, comm_data); + +alloc_mem_fail: + if (msg.data) kfree(msg.data); + if (comm_data) kfree(comm_data); + if (tx_msgid > UINT_MAX) tx_msgid = 1; + + return rv; +} + +int32_t ipmi_sdr_get_reservation(uint16_t * reserve_id) +{ + int32_t rv = 0; + uint8_t msg_data[] = { 0x00, GET_SDR_RESERVE_REPO }; //netfn = 0x00; cmd = GET_SDR_RESERVE_REPO; + + msg_data[0] = (g_use_built_in == 0) ? IPMI_NETFN_STORAGE : IPMI_NETFN_SE; + + /* obtain reservation ID */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), reserve_id, 1); + if (rv) printk("BMC down at (%d)!!\n", __LINE__); + +#if enable_debug_msg + printk("SDR reservation ID %04x\n", *reserve_id); +#endif + + return rv; +} + +int32_t ipmi_sdr_start(struct ipmi_sdr_iterator *itr) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { IPMI_NETFN_APP, BMC_GET_DEVICE_ID }; //netfn = IPMI_NETFN_APP; cmd = BMC_GET_DEVICE_ID; + + struct ipm_devid_rsp devid; + + /* check SDRR capability */ + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &devid, 1); + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return rv; + } + + if (devid.device_revision & IPM_DEV_DEVICE_ID_SDR_MASK) { + if ((devid.adtl_device_support & 0x02) == 0) { + if ((devid.adtl_device_support & 0x01)) { + printk("Using Device SDRs\n"); + g_use_built_in = 1; + } + else { + printk("Error obtaining SDR info\n"); + } + } + } + + if (g_use_built_in == 0) { + struct sdr_repo_info_rs sdr_info; + /* get sdr repository info */ + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + +#if enable_debug_msg + printk("SDR version: 0x%x\n", sdr_info.version); + printk("SDR free space: %d\n", sdr_info.free); +#endif + } + else { + struct sdr_device_info_rs sdr_info; + /* get device sdr info */ + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_SDR_REPO_INFO; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &sdr_info, 1); + itr->total = sdr_info.count; + } + +#if enable_debug_msg + printk("SDR records : %d\n", sdr_info.count); +#endif + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + itr->next = 0; + rv = ipmi_sdr_get_reservation(&(itr->reservation)); + } + + return rv; +} + +int32_t ipmi_sdr_get_header(struct ipmi_sdr_iterator *itr, struct sdr_get_rs *sdr_rs) +{ + int32_t rv = 0; + + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //netfn = 0x00; cmd = 0x00; + + struct sdr_get_rq sdr_rq; + + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = itr->next; + sdr_rq.offset = 0; + sdr_rq.length = 5; /* only get the header */ + + if (g_use_built_in == 0) { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), sdr_rs, 1); + if ((rv) || (sdr_rs->length == 0)) { + printk("SDR record id 0x%04x: invalid length %d", itr->next, sdr_rs->length); + return -1; + } + + if (sdr_rs->id != itr->next) { +#if enable_debug_msg + printk("SDR record id mismatch: 0x%04x\n", sdr_rs->id); +#endif + sdr_rs->id = itr->next; + } +#if enable_debug_msg + printk("\nSDR record ID : 0x%04x", itr->next); + printk("SDR record type : 0x%02x\n", sdr_rs->type); + printk("SDR record next : 0x%04x\n", sdr_rs->next); + printk("SDR record bytes: %d\n", sdr_rs->length); +#endif + + return rv; +} + +int32_t ipmi_sdr_get_record(struct sdr_get_rs * header, struct ipmi_sdr_iterator * itr, uint8_t *ret_data) +{ + int32_t rv = 0, len = 0; + + uint8_t buff[128] = ""; + uint8_t msg_data[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; //netfn = 0x00; cmd = 0x00; + + struct sdr_get_rq sdr_rq; + + len = header->length; + if (len > 0) { + memset(&sdr_rq, 0, sizeof(sdr_rq)); + sdr_rq.reserve_id = itr->reservation; + sdr_rq.id = header->id; + sdr_rq.offset = 5; + sdr_rq.length = len; + + if (g_use_built_in == 0) { + msg_data[0] = IPMI_NETFN_STORAGE; + msg_data[1] = GET_SDR; + } + else { + msg_data[0] = IPMI_NETFN_SE; + msg_data[1] = GET_DEVICE_SDR; + } + + memcpy(msg_data + 2, (uint8_t *)&sdr_rq, sizeof(struct sdr_get_rq)); + + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), ret_data, 1); + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + memset(buff, 0, sizeof(buff)); + memcpy(buff, ret_data + 2, sdr_rq.length); + memcpy(ret_data, buff, sdr_rq.length + 2); + } + } + + return rv; +} + +void ipmi_sdr_set_sensor_threshold(uint8_t idx, struct sdr_record_full_sensor *sensor) +{ + + /*refer to Table 35-, Get Sensor Event Enable*/ + /* + // change detect threshold method, keep it for record detail format + // in this version function input is + "void ipmi_sdr_set_sensor_threshold(uint8_t idx, uint8_t *rec)" + #define offset_threshold_enable 9 + #define offset_threshold_data 31 + if (rec[offset_threshold_enable + 1] & 0x08) g_sensor_data[idx].upperinfo.unr_high = 1; + if (rec[offset_threshold_enable + 1] & 0x04) g_sensor_data[idx].upperinfo.unr_low = 1; + if (rec[offset_threshold_enable + 1] & 0x02) g_sensor_data[idx].upperinfo.ucr_high = 1; + if (rec[offset_threshold_enable + 1] & 0x01) g_sensor_data[idx].upperinfo.ucr_low = 1; + if (rec[offset_threshold_enable] & 0x80) g_sensor_data[idx].upperinfo.unc_high = 1; + if (rec[offset_threshold_enable] & 0x40) g_sensor_data[idx].upperinfo.unc_low = 1; + + if (rec[offset_threshold_enable] & 0x20) g_sensor_data[idx].lowerinfo.lnr_high = 1; + if (rec[offset_threshold_enable] & 0x10) g_sensor_data[idx].lowerinfo.lnr_low = 1; + if (rec[offset_threshold_enable] & 0x08) g_sensor_data[idx].lowerinfo.lcr_high = 1; + if (rec[offset_threshold_enable] & 0x04) g_sensor_data[idx].lowerinfo.lcr_low = 1; + if (rec[offset_threshold_enable] & 0x02) g_sensor_data[idx].lowerinfo.lnc_high = 1; + if (rec[offset_threshold_enable] & 0x01) g_sensor_data[idx].lowerinfo.lnc_low = 1; + //*/ + + /* lower threshold info */ + if (sensor->mask.type.threshold.read.lnc) g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNC; + if (sensor->mask.type.threshold.read.lcr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_LCR; + if (sensor->mask.type.threshold.read.lnr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_LNR; + g_sensor_data[idx].lowerinfo.lnc = sensor->threshold.lower.non_critical; + g_sensor_data[idx].lowerinfo.lcr = sensor->threshold.lower.critical; + g_sensor_data[idx].lowerinfo.lnr = sensor->threshold.lower.non_recover; + + /* upper threshold info */ + if (sensor->mask.type.threshold.read.unc) g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNC; + if (sensor->mask.type.threshold.read.ucr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_UCR; + if (sensor->mask.type.threshold.read.unr) g_sensor_data[idx].capability |= SENSOR_GET_CAP_UNR; + g_sensor_data[idx].upperinfo.unc = sensor->threshold.upper.non_critical; + g_sensor_data[idx].upperinfo.ucr = sensor->threshold.upper.critical; + g_sensor_data[idx].upperinfo.unr = sensor->threshold.upper.non_recover; +} + +void ipmi_sdr_set_sensor_factor(uint8_t idx, struct sdr_record_full_sensor *sensor) +{ + char *loc = NULL; + + g_sensor_data[idx].sensor_type = sensor->sensor.type; + sprintf(g_sensor_data[idx].sensor_idstring, "%s", sensor->id_string); + + g_sensor_data[idx].recordinfo.record_m = __TO_M(sensor->mtol); + g_sensor_data[idx].recordinfo.record_b = __TO_B(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k1 = __TO_B_EXP(sensor->bacc); + g_sensor_data[idx].recordinfo.record_k2 = __TO_R_EXP(sensor->bacc); + + g_sensor_data[idx].recordinfo.record_analog = sensor->unit.analog; + g_sensor_data[idx].recordinfo.record_linearization = sensor->linearization; + + memset(g_sensor_data[idx].attrinfo.attr_type_str, 0x00, SENSOR_ATTR_NAME_LENGTH); + + switch (g_sensor_data[idx].sensor_type) + { + case SDR_SENSOR_TYPE_TEMP: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "temp"); + break; + case SDR_SENSOR_TYPE_VOLT: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + break; + case SDR_SENSOR_TYPE_FAN: + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PWM; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_CONMODE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_DIRECTION; + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "fan"); + break; + case SDR_SENSOR_TYPE_PS: + loc = strstr(g_sensor_data[idx].sensor_idstring, "POWER"); + if (loc) { + if ((strncmp(g_sensor_data[idx].sensor_idstring + 11, "OUT", 3)) == 0) { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MODEL; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_SN; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_MFRID; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_PSU_PRESENT; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_VIN_TYPE; + g_sensor_data[idx].capability |= SENSOR_GET_CAP_POUT_MAX; + } + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "power"); + } + + loc = strstr(g_sensor_data[idx].sensor_idstring, "VOLTAGE"); + if (loc) sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "in"); + + loc = strstr(g_sensor_data[idx].sensor_idstring, "CURRENT"); + if (loc) sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + + break; + case SDR_SENSOR_TYPE_CURR: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "curr"); + break; + case SDR_SENSOR_TYPE_OTHER: + sprintf(g_sensor_data[idx].attrinfo.attr_type_str, "other"); + break; + default: + printk("not support sensor type !! [%d]\n", g_sensor_data[idx].sensor_type); + break; + } + + if ((strncmp(g_sensor_data[idx].sensor_idstring, "Fan", 3)) == 0) { + g_sensor_data[idx].capability |= SENSOR_GET_CAP_FAN_PRESENT; + } + +#if enable_debug_msg + { + printk("\n********************\n"); + + printk("m[%d], b[%d], k1[%d], k2[%d]\n", g_sensor_data[idx].recordinfo.record_m, g_sensor_data[idx].recordinfo.record_b + , g_sensor_data[idx].recordinfo.record_k1, g_sensor_data[idx].recordinfo.record_k2); + + printk("sensor [%s] type[%d], analog[%d], linearization[%d]\n", g_sensor_data[idx].sensor_idstring, g_sensor_data[idx].sensor_type + , g_sensor_data[idx].recordinfo.record_analog, g_sensor_data[idx].recordinfo.record_linearization); + + printk("\n********************\n"); + } +#endif + +} + +int32_t sdr_convert_sensor_reading(uint8_t idx, uint8_t val, int32_t *point_result) +{ + int32_t m = g_sensor_data[idx].recordinfo.record_m; + int32_t b = g_sensor_data[idx].recordinfo.record_b; + int32_t k1 = g_sensor_data[idx].recordinfo.record_k1; + int32_t k2 = g_sensor_data[idx].recordinfo.record_k2; + int32_t decimal_point = 0; + int32_t result = 0; + + decimal_point = pow_convert(&b, k1); + + switch (g_sensor_data[idx].recordinfo.record_analog) + { + case 0: + result = m * val * decimal_point + b; + break; + case 1: + if (val & 0x80) val++; + case 2: + result = (m * (int16_t)val) * decimal_point + b; + break; + default: + return result; + } + + pow_convert(&result, k2); + if (k1 < 0) *point_result += -k1; + if (k2 < 0) *point_result += -k2; + + if (g_sensor_data[idx].sensor_type != SDR_SENSOR_TYPE_FAN) { + result = result * 1000; //shift for lm-sensors + } + + return result; +} + +int32_t ipmi_sdr_parsing_value(int32_t idx, uint8_t input_value, int8_t *ret_str) +{ + int32_t calc_result = 0, point_result = 0; + int32_t temp_len = 0; + + uint8_t temp_str[16] = ""; + + calc_result = sdr_convert_sensor_reading(idx, input_value, &point_result); + + temp_len = sprintf(temp_str, "%d", calc_result); + temp_len = temp_len - point_result; + + /* int part */ + if (temp_len <= 0) sprintf(ret_str, "0"); + else snprintf(ret_str, temp_len + 1, "%s", temp_str); // +1 for snprintf reserve space'\0' + + /* point part */ + strcat(ret_str, "."); + + /* float part */ + if ((point_result == 0) || (temp_len < 0)) strcat(ret_str, "0"); + else strcat(ret_str, temp_str + temp_len); + + /* EOL part */ + strcat(ret_str, "\n\0"); + + return (temp_len + 1 + point_result + 2); //integer + point + float + EOL + \0 +} + + +uint8_t ipmi_check_psu_present(uint8_t psu_slot) +{ + uint8_t slot_mask = 0x0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x03 }; //netfn = 0x36; cmd = 0xB9; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return 0; + } + else { + slot_mask = (psu_slot == 1) ? 0x01 : 0x02; + return (returnData[0] & slot_mask) ? 0 : 1; + } +} + +int32_t ipmi_get_psu_info(uint8_t idx, uint8_t cmd, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData[128] = { 0 }, tempData[128] = { 0 }; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x80, cmd }; //netfn = 0x06; cmd = 0x52; + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + if (returnData[0] < (sizeof(returnData) - 2)) { + snprintf(tempData, returnData[0] + 1, "%s", returnData + 1); + return sprintf(retbuf, "%s\n", tempData); + } + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_vin_type(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0; + + uint8_t returnData = 0; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x01, 0xd8 }; // read line status + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), &returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + switch (returnData) + { + case 0x7: //LVDC + case 0x3: //HVDC + return sprintf(retbuf, "DC\n"); + default: + return sprintf(retbuf, "AC\n"); + } + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +int32_t ipmi_get_pout_max(uint8_t idx, uint8_t *retbuf) +{ + uint8_t psu_slot = 0; + int32_t rv = 0, pout_max = 0; + + uint8_t returnData[2] = { 0 }, tempData[2] = { 0 }; + uint8_t msg_data[] = { 0x06, 0x52, 0x0f, 0x00, 0x02, 0xa7 }; + + if (strstr(g_sensor_data[idx].sensor_idstring, "PSU1")) psu_slot = 1; + else psu_slot = 2; + + msg_data[3] = (psu_slot == 1) ? 0xb0 : 0xb2; + if (ipmi_check_psu_present(psu_slot)) { + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + } + else { + /* MFR_POUT_MAX has 2 data format: Direct and Linear Data (see PMbus spec). + Query command is needed to tell the data format, but since we have not use PSU + whose output power is over 0x07ff (2047), just check the first 5 bits*/ + if (returnData[1] & 0xf8 == 0) // Direct + pout_max = (returnData[1] << 8) | returnData[0]; + else // Linear Data + pout_max = (((returnData[1] & 0x07) << 8) | returnData[0]) << ((returnData[1] & 0xf8) >> 3); + return sprintf(retbuf, "%d\n", pout_max); + } + } + else { + //printk("Error ! cannot detect PSU%d\n", psu_slot); + } + + return sprintf(retbuf, "N/A\n"); +} + +void ipmi_fan_control(uint8_t cmd_data1, uint8_t cmd_data2, uint8_t *retbuf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_TSOL, GET_FAN_INFO, cmd_data1, cmd_data2 }; //netfn = IPMI_NETFN_TSOL; cmd = GET_FAN_INFO; + + mutex_lock(&ipmi_lock); + if (cmd_data1) rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), NULL, 0); + else rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + sprintf(retbuf, "N/A\n"); + } + else { + sprintf(retbuf, "%s", returnData); + } +} + +static ssize_t show_label(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%s\n", g_sensor_data[attr->index + DEBUGUSE_SHIFT].sensor_idstring); +} + +static ssize_t show_crit_alarm(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return sprintf(buf, "%d\n", attr->index); +} + +static ssize_t show_input(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + int32_t rv = 0; + + uint8_t returnData[4] = ""; + uint8_t msg_data[] = { IPMI_NETFN_SE, GET_SENSOR_READING, 0x00 }; //netfn = IPMI_NETFN_SE; cmd = GET_SENSOR_READING; + + mutex_lock(&ipmi_lock); + msg_data[2] = g_sensor_data[attr->index + DEBUGUSE_SHIFT].addr; + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "0.0\n"); + } + else { + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, returnData[0], buf); + } +} + +static ssize_t show_lnr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnr, buf); +} + +static ssize_t show_lcr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lcr, buf); +} + +static ssize_t show_lnc(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].lowerinfo.lnc, buf); +} + +static ssize_t show_unr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unr, buf); +} + +static ssize_t show_ucr(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.ucr, buf); +} + +static ssize_t show_unc(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_sdr_parsing_value(attr->index + DEBUGUSE_SHIFT, g_sensor_data[attr->index + DEBUGUSE_SHIFT].upperinfo.unc, buf); +} + +static ssize_t show_model(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9a, buf); +} + +static ssize_t show_sn(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x9e, buf); +} + +static ssize_t show_mfrid(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_psu_info(attr->index + DEBUGUSE_SHIFT, 0x99, buf); +} + +static ssize_t show_vin_type(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_vin_type(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pout_max(struct device *dev, struct device_attribute *devattr, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + return ipmi_get_pout_max(attr->index + DEBUGUSE_SHIFT, buf); +} + +static ssize_t show_pwm(struct device *dev, struct device_attribute *devattr, char *buf) +{ + uint8_t returnData[10] = { 0 }; + ipmi_fan_control(0x00, 0x00, returnData); + return sprintf(buf, "%d\n", returnData[0]); +} + +static ssize_t store_pwm(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + if (g_fan_control_mode == 1) ipmi_fan_control(0x01, store_input, returnData); + + return count; +} + +static ssize_t show_controlmode(struct device *dev, struct device_attribute *devattr, char *buf) +{ + return sprintf(buf, "%d\n", g_fan_control_mode); +} + +static ssize_t store_controlmode(struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) +{ + uint8_t store_input = 0; + uint8_t returnData[10] = { 0 }; + simple_atoi(buf, &store_input); + g_fan_control_mode = store_input; + if (g_fan_control_mode == 3) ipmi_fan_control(0x7f, 0xff, returnData); + + return count; +} + +static ssize_t show_direction(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { IPMI_NETFN_STORAGE, GET_FRU_INFO, 0x00, 0x19, 0x00, 0x01 }; //netfn = IPMI_NETFN_STORAGE; cmd = GET_FRU_INFO; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + if (rv) { + printk("BMC down at (%d)!!\n", __LINE__); + return sprintf(buf, "N/A\n"); + } + else { + return sprintf(buf, "%c\n", returnData[1]); + } +} + +static ssize_t show_fanpresent(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int32_t rv = 0; + int32_t fan_idx = 0, fan_present = 0; + + uint8_t returnData[10] = { 0 }; + uint8_t msg_data[] = { 0x36, 0xB9, 0x4C, 0x1C, 0x00, 0x02 }; //netfn = 0x36; cmd = 0xB9; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + fan_idx = (g_sensor_data[attr->index].sensor_idstring[8] - '0') - 1; + + mutex_lock(&ipmi_lock); + rv = ipmi_send_system_cmd(msg_data, sizeof(msg_data), returnData, 1); + mutex_unlock(&ipmi_lock); + + fan_present = ((returnData[0] >> fan_idx) & 0x1) ? 0 : 1; + + return sprintf(buf, "%d\n", fan_present); +} + +static ssize_t show_psupresent(struct device *dev, struct device_attribute *devattr, char *buf) +{ + int32_t psu_idx = 0; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); + + psu_idx = g_sensor_data[attr->index].sensor_idstring[3] - '0'; + + return sprintf(buf, "%d\n", ipmi_check_psu_present(psu_idx)); +} + +static ssize_t(*const attr_show_func_ptr[SENSOR_ATTR_MAX]) (struct device *dev, struct device_attribute *devattr, char *buf) = +{ + show_label, show_crit_alarm, show_input + , show_lnc, show_lcr, show_lnr + , show_unc, show_ucr, show_unr + , show_model, show_sn, show_pwm + , show_controlmode, show_direction, show_fanpresent + , show_psupresent, show_mfrid, show_vin_type + , show_pout_max +}; + +static ssize_t(*const attr_store_func_ptr[SENSOR_ATTR_MAX]) (struct device *dev, struct device_attribute *devattr, const char *buf, size_t count) = +{ + NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, NULL + , NULL, NULL, store_pwm + , store_controlmode, NULL, NULL + , NULL, NULL, NULL + , NULL +}; + +static const char *const sensor_attrnames[SENSOR_ATTR_MAX] = +{ + "%s%d_label", "%s%d_crit_alarm", "%s%d_input" + , "%s%d_lncrit", "%s%d_lcrit", "%s%d_min" + , "%s%d_ncrit", "%s%d_crit", "%s%d_max" + , "%s%d_model", "%s%d_sn", "%s%d_pwm" + , "%s%d_controlmode", "%s%d_direction", "%s%d_present" + , "%s%d_present", "%s%d_mfrid", "%s%d_vin_type" + , "%s%d_pout_max" +}; + +static int32_t create_sensor_attrs(int32_t attr_no) +{ + int32_t i = 0, j = 0; + + struct attr_info *attrdata = &g_sensor_data[attr_no].attrinfo; + +#if enable_debug_msg + printk("##### %s:%d attr_no %d\n", __FUNCTION__, __LINE__, attr_no); +#endif + + for (i = 0; i < SENSOR_ATTR_MAX; i++) { + if ((g_sensor_data[attr_no].capability >> i) & 0x01) { + snprintf(attrdata->attr_name[j], SENSOR_ATTR_NAME_LENGTH, sensor_attrnames[i], attrdata->attr_type_str, attr_no - DEBUGUSE_SHIFT); + + sysfs_attr_init(&attrdata->sd_attrs[j].dev_attr.attr); + attrdata->sd_attrs[j].dev_attr.attr.name = attrdata->attr_name[j]; + attrdata->sd_attrs[j].dev_attr.show = attr_show_func_ptr[i]; + attrdata->sd_attrs[j].dev_attr.store = attr_store_func_ptr[i]; + + attrdata->sd_attrs[j].dev_attr.attr.mode = S_IRUGO; + if (attrdata->sd_attrs[j].dev_attr.store) attrdata->sd_attrs[j].dev_attr.attr.mode |= S_IWUSR; + + attrdata->sd_attrs[j].index = attr_no - DEBUGUSE_SHIFT; + attrdata->attrs[j] = &attrdata->sd_attrs[j].dev_attr.attr; + j++; + + data->total_create_sysfs++; + } + } + + attrdata->attrs[j] = NULL; + attrdata->attr_group.attrs = attrdata->attrs; + + g_sensor_data[attr_no].attrinfo.attr_exist = 1; + + return sysfs_create_group(&data->ipmi_hwmon_dev->kobj, &attrdata->attr_group); +} + +static int32_t remove_sensor_attrs(void) +{ + int32_t i = 0; + + for (i = 0; i < data->total_sensor_id; i++) { + if (g_sensor_data[i].attrinfo.attr_exist) { + sysfs_remove_group(&data->ipmi_hwmon_dev->kobj, &g_sensor_data[i].attrinfo.attr_group); + } + } + return 0; +} + +int32_t ipmi_init_sdr_sensors_data(void) +{ + int32_t sdr_idx = 0; + int32_t err = 0; + + struct ipmi_sdr_iterator *itr = NULL; + struct sdr_get_rs *header = NULL; + + uint8_t *rec = NULL; + + mutex_lock(&ipmi_lock); + + itr = kzalloc(sizeof(struct ipmi_sdr_iterator), GFP_KERNEL); + if (itr == NULL) { + printk("%s(%d): kzalloc failure.\n", __func__, __LINE__); + goto itr_malloc_fail; + } + + header = kzalloc(sizeof(struct sdr_get_rs), GFP_KERNEL); + if (header == NULL) { + printk("%s(%d): malloc failure.\n", __func__, __LINE__); + goto header_malloc_fail; + } + + err = ipmi_sdr_start(itr); + if (err) { + printk("%s(%d): ipmi_sdr_start fail.\n", __func__, __LINE__); + goto ipmi_sdr_start_fail; + } + + data->total_sensor_id = itr->total; + rec = kzalloc(GET_SDR_ENTIRE_RECORD, GFP_KERNEL); + if (rec == NULL) { + printk("%s(%d): kzalloc failure\n", __func__, __LINE__); + goto rec_malloc_fail; + } + + g_sensor_data = kzalloc(itr->total * sizeof(struct ipmi_sensor_data), GFP_KERNEL); + if (g_sensor_data == NULL) { + printk("%s(%d): malloc failure", __func__, __LINE__); + goto g_sensor_data_malloc_fail; + } + + memset(g_sensor_data, 0x0, itr->total * sizeof(struct ipmi_sensor_data)); + + for (sdr_idx = 0; sdr_idx < itr->total; sdr_idx++) { + err = ipmi_sdr_get_header(itr, header); + if (err) { + if (err == 0xC5) { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_header_fail; + } + + + memset(rec, 0, GET_SDR_ENTIRE_RECORD); + err = ipmi_sdr_get_record(header, itr, rec); + if (err) { + if (err == 0xC5) { + /* C5h : Reservation Invalid */ +#if enable_debug_msg + printk("ipmi: reservation number given was invalid or the reservation was lost\n"); + printk("ipmi: retry\n"); +#endif + ipmi_sdr_get_reservation(&(itr->reservation)); + sdr_idx--; + continue; + } + printk("ipmi: Get SDR header fail,so break this request\n"); + goto ipmi_sdr_get_record_fail; + } + + itr->next = header->next; + + switch (header->type) + { + case SDR_RECORD_TYPE_FULL_SENSOR: + /* prepare (threshold, factor)data whilie init, for reduce reading step and improve operate speed */ + g_sensor_data[sdr_idx].addr = rec[2]; + g_sensor_data[sdr_idx].capability = SENSOR_GET_CAP_LABEL /*| SENSOR_GET_CAP_ALARM */ | SENSOR_GET_CAP_INPUT; + g_sensor_data[sdr_idx].headerinfo.header_type = header->type; + g_sensor_data[sdr_idx].headerinfo.header_byte = header->length; + + ipmi_sdr_set_sensor_threshold(sdr_idx, (struct sdr_record_full_sensor*) rec); + ipmi_sdr_set_sensor_factor(sdr_idx, (struct sdr_record_full_sensor*) rec); + + if (sdr_idx >= DEBUGUSE_SHIFT) { + err = create_sensor_attrs(sdr_idx); + if (err) { + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; + printk("[err : %d]sysfs_create_group fail in [%d] %s\n", err, sdr_idx, g_sensor_data[sdr_idx].sensor_idstring); + goto create_sysfs_fail; + } + } + + data->total_suport_sensor++; + + break; + case SDR_RECORD_TYPE_COMPACT_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_EVENTONLY_SENSOR: /* not supporrt now */ + case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR: /* not supporrt now */ + default: + g_sensor_data[sdr_idx].attrinfo.attr_exist = 0; +#if enable_debug_msg + printk("ID[%d] : not support type [%d]\n", sdr_idx, header->type); +#endif + break; + } + } + + printk("quanta_hwmon_ipmi : detected [%d] sensor, create [%d] sysfs\n", data->total_suport_sensor, data->total_create_sysfs); + +create_sysfs_fail: +ipmi_sdr_get_header_fail: +ipmi_sdr_get_record_fail: +g_sensor_data_malloc_fail: + if (header) { + kfree(header); + header = NULL; + } + if (rec) { + kfree(rec); + rec = NULL; + } + +rec_malloc_fail: +ipmi_sdr_start_fail: +header_malloc_fail: + if (itr) { + kfree(itr); + itr = NULL; + } + +itr_malloc_fail: + mutex_unlock(&ipmi_lock); + + return err; +} + +static int32_t __init quanta_hwmon_ipmi_init(void) +{ + int32_t err = 0; + + init_completion(&g_read_complete); + + data = kzalloc(sizeof(struct quanta_hwmon_ipmi_data), GFP_KERNEL); + if (NULL == data) { + printk("alloc data fail\n"); + goto alloc_err; + } + + data->ipmi_platform_dev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + err = IS_ERR(data->ipmi_platform_dev); + if (err) { + printk("platform device register fail (err : %d)\n", err); + goto device_reg_err; + } + + data->ipmi_hwmon_dev = hwmon_device_register_with_groups(NULL, DRVNAME, NULL, NULL); + err = IS_ERR(data->ipmi_hwmon_dev); + if (err) { + printk("hwmon register fail\n"); + goto hwmon_register_err; + } + + err = ipmi_create_user(0, &ipmi_hndlrs, NULL, &ipmi_mh_user); + if (err) { + printk("warning: create user fail, watchdog broken (err : %d)\n", err); + goto ipmi_create_err; + } + + mutex_init(&ipmi_lock); + err = ipmi_init_sdr_sensors_data(); + if (err) { + printk("init sensor data fail (err : %d)\n", err); + goto init_sensor_err; + } + + return 0; + +init_sensor_err: + kfree(g_sensor_data); +ipmi_create_err: + hwmon_device_unregister(data->ipmi_hwmon_dev); +hwmon_register_err: + platform_device_unregister(data->ipmi_platform_dev); +device_reg_err: + kfree(data); +alloc_err: + return err; +} + +static void __exit quanta_hwmon_ipmi_exit(void) +{ + remove_sensor_attrs(); + hwmon_device_unregister(data->ipmi_hwmon_dev); + platform_device_unregister(data->ipmi_platform_dev); + + mutex_lock(&ipmi_lock); + ipmi_destroy_user(ipmi_mh_user); + mutex_unlock(&ipmi_lock); + + kfree(g_sensor_data); + kfree(data); + return; +} + +module_init(quanta_hwmon_ipmi_init); +module_exit(quanta_hwmon_ipmi_exit); + +MODULE_AUTHOR("Charcar~~Charcar~Charlie li li"); +MODULE_VERSION("2.0"); +MODULE_DESCRIPTION("Quanta BMC hardware monitor driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/setup.py index b2f1b39fcd..ad2b11a671 100644 --- a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/setup.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/setup.py @@ -1,7 +1,6 @@ #!/usr/bin/env python import os -import sys from setuptools import setup os.listdir diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/__init__.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/__init__.py new file mode 100644 index 0000000000..4bfefa0fb6 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/chassis.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/chassis.py new file mode 100644 index 0000000000..33f67b0b9d --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/chassis.py @@ -0,0 +1,217 @@ +#!/usr/bin/env python +# +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import sys + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.psu import Psu + from sonic_platform.sfp import Sfp + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.thermal import Thermal + +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Chassis(ChassisBase): + + def __init__(self): + ChassisBase.__init__(self) + self.__num_of_psus = 2 + self.__num_of_ports = 32 + self.__num_of_fan_drawers = 6 + self.__fan_per_drawer = 2 + self.__num_of_thermals = 19 + self.__xcvr_presence = {} + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize watchdog + #self._watchdog = Watchdog() + + # Initialize FAN + fan_index = 1 + for drawer_index in range(1, self.__num_of_fan_drawers + 1): + drawer_fan_list = [] + for index in range(0, self.__fan_per_drawer): + fan = Fan(fan_index, False) + fan_index += 1 + self._fan_list.append(fan) + drawer_fan_list.append(fan) + fan_drawer = FanDrawer(drawer_index, drawer_fan_list) + self._fan_drawer_list.append(fan_drawer) + + # Initialize thermal + for index in range(1, self.__num_of_thermals + 1): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + # Initialize PSU and PSU_FAN + for index in range(1, self.__num_of_psus + 1): + psu = Psu(index) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(1, self.__num_of_ports + 1): + sfp = Sfp(index, 'QSFP') + self._sfp_list.append(sfp) + self.__xcvr_presence[index] = self._sfp_list[index-1].get_presence() + + +############################################## +# Device methods +############################################## + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + For Quanta IX8C the index in sfputil.py starts from 1, so override + + Args: + index: An integer, the index (1-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 1. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + if (index == 0): + raise IndexError + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("override: SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + + return sfp + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self._eeprom.modelstr() + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_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 + +############################################## +# Chassis methods +############################################## + + 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. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + 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. + """ + #raise NotImplementedError + return (ChassisBase.REBOOT_CAUSE_HARDWARE_OTHER, "Invalid Reason") + + def get_change_event(self, timeout=0): + """ + Currently only support transceiver change events + """ + + start_ms = time.time() * 1000 + xcvr_change_event_dict = {} + event = False + + while True: + time.sleep(0.5) + for index in range(1, self.__num_of_ports + 1): + cur_xcvr_presence = self._sfp_list[index-1].get_presence() + if cur_xcvr_presence != self.__xcvr_presence[index]: + if cur_xcvr_presence is True: + xcvr_change_event_dict[str(index)] = '1' + self.__xcvr_presence[index] = True + elif cur_xcvr_presence is False: + xcvr_change_event_dict[str(index)] = '0' + self.__xcvr_presence[index] = False + event = True + + if event is True: + return True, {'sfp':xcvr_change_event_dict} + + if timeout: + now_ms = time.time() * 1000 + if (now_ms - start_ms >= timeout): + return True, {'sfp':xcvr_change_event_dict} + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/eeprom.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/eeprom.py new file mode 100644 index 0000000000..1c044638ed --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/eeprom.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + # Display vendor extension for Quanta platforms + _TLV_DISPLAY_VENDOR_EXT = True + + def __init__(self): + self.__eeprom_path = "/sys/bus/i2c/devices/3-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + 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] + + if tlv[0] == self._TLV_CODE_VENDOR_EXT: + value = str((tlv[2] << 24) | (tlv[3] << 16) | + (tlv[4] << 8) | tlv[5]) + value += tlv[6:6 + tlv[1]].decode('ascii') + else: + value = self.decoder(None, tlv)[30:] + + 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): + (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): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or results[1] != 6: + return super(TlvInfoDecoder, self).switchaddrstr(e) + + return ":".join(["{:02x}".format(T) for T in results[2]]).upper() + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2].decode('ascii') + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + + def decoder(self, s, t): + ''' + Return a string representing the contents of the TLV field. The format of + the string is: + 1. The name of the field left justified in 20 characters + 2. The type code in hex right justified in 5 characters + 3. The length in decimal right justified in 4 characters + 4. The value, left justified in however many characters it takes + The vailidity of EEPROM contents and the TLV field has been verified + prior to calling this function. The 's' parameter is unused + ''' + if t[0] == self._TLV_CODE_PRODUCT_NAME: + name = "Product Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PART_NUMBER: + name = "Part Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERIAL_NUMBER: + name = "Serial Number" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_BASE: + name = "Base MAC Address" + value = ":".join(["{:02x}".format(T) for T in t[2:8]]).upper() + elif t[0] == self._TLV_CODE_MANUF_DATE: + name = "Manufacture Date" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DEVICE_VERSION: + name = "Device Version" + value = str(t[2]) + elif t[0] == self._TLV_CODE_LABEL_REVISION: + name = "Label Revision" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_PLATFORM_NAME: + name = "Platform Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_ONIE_VERSION: + name = "ONIE Version" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MAC_SIZE: + name = "MAC Addresses" + value = str((t[2] << 8) | t[3]) + elif t[0] == self._TLV_CODE_MANUF_NAME: + name = "Manufacturer" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_MANUF_COUNTRY: + name = "Manufacture Country" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_NAME: + name = "Vendor Name" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_DIAG_VERSION: + name = "Diag Version" + # Quanta legacy format of diag version + if t[1] == 4: + value = "{}.{}.{}.{}".format('{:02x}'.format(t[2])[0], '{:02x}'.format(t[2])[1], + '{:02x}'.format(t[3])[0], '{:02x}'.format(t[3])[1]) + else: + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_SERVICE_TAG: + name = "Service Tag" + value = t[2:2 + t[1]].decode("ascii") + elif t[0] == self._TLV_CODE_VENDOR_EXT: + name = "Vendor Extension" + value = "" + if self._TLV_DISPLAY_VENDOR_EXT: + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + elif t[0] == self._TLV_CODE_CRC_32 and len(t) == 6: + name = "CRC-32" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + # Quanta specific codes below here. + # These decodes are lifted from their U-Boot codes + elif t[0] == self._TLV_CODE_QUANTA_MAGIC and len(t) == 3: + name = "Magic Number" + value = "0x%02X" % t[2] + elif t[0] == self._TLV_CODE_QUANTA_CRC and len(t) == 4: + name = "QUANTA-CRC" + value = "0x%04X" % ((t[2] << 8) + t[3]) + elif t[0] == self._TLV_CODE_QUANTA_CARD_TYPE and len(t) == 6: + name = "Card Type" + value = "0x%08X" % ((t[2] << 24) | (t[3] << 16) | (t[4] << 8) | t[5]) + elif t[0] == self._TLV_CODE_QUANTA_HW_VERSION and len(t) == 6: + name = "Hardware Version" + value = "%d.%d" % (t[2], t[3]) + elif t[0] == self._TLV_CODE_QUANTA_SW_VERSION and len(t) == 6: + name = "Software Version" + value = "%d.%d.%d.%d" % ((t[2] >> 4), (t[2] & 0xF), (t[3] >> 4), (t[3] & 0xF)) + elif t[0] == self._TLV_CODE_QUANTA_MANUF_DATE and len(t) == 6: + name = "Manufacture Date" + value = "%04d/%d/%d" % (((t[2] << 8) | t[3]), t[4], t[5]) + elif t[0] == self._TLV_CODE_QUANTA_MODEL_NAME: + name = "Model Name" + value = t[2:2 + t[1]].decode("ascii") + else: + name = "Unknown" + value = "" + for c in t[2:2 + t[1]]: + value += "0x%02X " % c + return name, value + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/fan.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/fan.py new file mode 100644 index 0000000000..e668013df9 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/fan.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta IX9 +# +# Module contains an implementation of SONiC Platform Base API and +# provides the FAN information +# +############################################################################# + +try: + import logging + import os + from sonic_platform_base.fan_base import FanBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +############### +# Global +############### +HWMON_DIR = "/sys/class/hwmon/hwmon2/" +FAN_INDEX_START = 18 +NUM_FANTRAYS = 6 +FANS_PERTRAY = 2 + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, index, is_psu_fan=False): + self.is_psu_fan = is_psu_fan + self.fan_index = index + self.psu_fan_index_mapping = { + 1:37, + 2:47, + } + self.psu_index_mapping = { + 1:39, + 2:49, + } + if self.is_psu_fan: + self.fan_presence_attr = "power{}_present".format(self.psu_index_mapping[index]) + self.fan_pwm_attr = "fan{}_pwm".format(self.psu_fan_index_mapping[index]) + self.fan_rpm_attr = "fan{}_input".format(self.psu_fan_index_mapping[index]) + self.fan_direction_attr = "fan{}_direction".format(self.psu_fan_index_mapping[index]) + else: + self.fan_presence_attr = "fan{}_present".format(FAN_INDEX_START+(index-1)) + self.fan_pwm_attr = "fan{}_pwm".format(FAN_INDEX_START+(index-1)) + self.fan_rpm_attr = "fan{}_input".format(FAN_INDEX_START+(index-1)) + self.fan_direction_attr = "fan{}_direction".format(FAN_INDEX_START+(index-1)) + + +####################### +# private function +####################### + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + + #################### + # Device base + #################### + + 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.fan_index) + else: + fantray_index = (self.fan_index-1)/FANS_PERTRAY+1 + fan_index_intray = self.fan_index - ((fantray_index-1)*FANS_PERTRAY) + return "Fantray{}_{}".format(fantray_index, fan_index_intray) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.fan_presence_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == '1'): + return True + else: + return False + + return None + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR' and attr_rv != '0.0'): + return True + else: + return False + else: + return False + + ################# + # fan base + ################# + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + attr_path = HWMON_DIR + self.fan_direction_attr + attr_rv = self.__get_attr_value(attr_path) + + if attr_rv == '2': + return self.FAN_DIRECTION_INTAKE + else: + return self.FAN_DIRECTION_EXHAUST + + def get_speed(self): + """ + Retrieves the speed of fan as a percentage of full speed + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + if self.get_presence(): + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + else: + return 0 + + def get_speed_rpm(self): + """ + Retrieves the speed of fan in revolutions per minute (RPM) + + Returns: + An integer, speed of the fan in RPM + """ + attr_path = HWMON_DIR + self.fan_rpm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + attr_path = HWMON_DIR + self.fan_pwm_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return int(float(attr_rv)) + else: + return False + + def get_speed_tolerance(self): + """ + Retrieves the speed tolerance of the fan + + Returns: + An integer, the percentage of variance from target speed which is + considered tolerable + """ + return 25 + + def set_status_led(self, color): + """ + Sets the state of the fan module status LED + + Args: + color: A string representing the color with which to set the + fan module status LED + + Returns: + bool: True if status LED state is set successfully, False if not + """ + return True + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + return None diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/fan_drawer.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..75e954576a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/fan_drawer.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index, fan_list): + FanDrawerBase.__init__(self) + + self._fan_list = fan_list + self._index = index + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return 'Fan {}'.format(self._index) + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/platform.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/platform.py new file mode 100644 index 0000000000..a2ffe0a47e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +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): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/psu.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/psu.py new file mode 100644 index 0000000000..1043a4fe18 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/psu.py @@ -0,0 +1,319 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import logging + 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") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +class Psu(PsuBase): + def __init__(self, index): + PsuBase.__init__(self) + fan = Fan(index, True) + self._fan_list.append(fan) + + self.psu_index_mapping = { + 1:39, + 2:49, + } + self.psu_powerin_index_mapping = { + 1:38, + 2:48, + } + self.psu_currentout_index_mapping = { + 1:36, + 2:46, + } + self.psu_currentin_index_mapping = { + 1:35, + 2:45, + } + self.psu_voltageout_index_mapping = { + 1:44, + 2:54, + } + self.psu_voltagein_index_mapping = { + 1:43, + 2:53, + } + self.index = index + self.psu_presence_attr = "power{}_present".format(self.psu_index_mapping[self.index]) + self.psu_status_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_power_in_attr = "power{}_input".format(self.psu_powerin_index_mapping[self.index]) + self.psu_power_out_attr = "power{}_input".format(self.psu_index_mapping[self.index]) + self.psu_voltage_out_attr = "in{}_input".format(self.psu_voltageout_index_mapping[self.index]) + self.psu_current_out_attr = "curr{}_input".format(self.psu_currentout_index_mapping[self.index]) + self.psu_voltage_in_attr = "in{}_input".format(self.psu_voltagein_index_mapping[self.index]) + self.psu_current_in_attr = "curr{}_input".format(self.psu_currentin_index_mapping[self.index]) + self.psu_serial_attr = "power{}_sn".format(self.psu_index_mapping[self.index]) + self.psu_model_attr = "power{}_model".format(self.psu_index_mapping[self.index]) + self.psu_mfr_id_attr = "power{}_mfrid".format(self.psu_index_mapping[self.index]) + self.psu_capacity_attr = "power{}_pout_max".format(self.psu_index_mapping[self.index]) + self.psu_type_attr = "power{}_vin_type".format(self.psu_index_mapping[self.index]) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + fd.close() + return retval + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return "PSU{}".format(self.index) + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + attr_path = HWMON_DIR+self.psu_presence_attr + attr_normal = '1' + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (attr_rv == attr_normal): + presence = True + + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = "N/A" + attr_path = HWMON_DIR+self.psu_model_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + model = attr_rv + + return model + + def get_mfr_id(self): + """ + Retrieves the manufacturer's name (or id) of the device + + Returns: + string: Manufacturer's id of device + """ + mfr_id = "N/A" + attr_path = HWMON_DIR+self.psu_mfr_id_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + mfr_id = attr_rv + + return mfr_id + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = "N/A" + attr_path = HWMON_DIR+self.psu_serial_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + attr_path = HWMON_DIR+self.psu_status_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + if (int(attr_rv) != 0): + status = True + + return status + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_out = float(attr_rv) / 1000 + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + attr_path = HWMON_DIR+self.psu_current_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_out = float(attr_rv) / 1000 + + return current_out + + def get_input_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_in = 0.0 + attr_path = HWMON_DIR+self.psu_voltage_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + voltage_in = float(attr_rv) / 1000 + + return voltage_in + + def get_input_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_in = 0.0 + attr_path = HWMON_DIR+self.psu_current_in_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + current_in = float(attr_rv) / 1000 + + return current_in + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + attr_path = HWMON_DIR+self.psu_power_out_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + attr_rv, dummy = attr_rv.split('.', 1) + power_out = float(attr_rv) / 1000 + + return power_out + + 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. + """ + return self.get_status() + + def get_status_led(self): + """ + Gets the state of the PSU status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + if self.get_powergood_status(): + return self.STATUS_LED_COLOR_GREEN + else: + return self.STATUS_LED_COLOR_OFF + + def get_type(self): + """ + Gets the type of the PSU + + Returns: + A string, the type of PSU (AC/DC) + """ + type = "AC" + attr_path = HWMON_DIR+self.psu_type_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + type = attr_rv + + return type + + def get_capacity(self): + """ + Gets the capacity (maximum output power) of the PSU in watts + + Returns: + An integer, the capacity of PSU + """ + capacity = 0 + attr_path = HWMON_DIR+self.psu_capacity_attr + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + try: + capacity = int(attr_rv) + except ValueError: + capacity = 0 + + return capacity + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/sfp.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/sfp.py new file mode 100644 index 0000000000..e4505f509a --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/sfp.py @@ -0,0 +1,2130 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import time +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.inf8628 import inf8628InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from sonic_py_common.logger import Logger + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# to improve performance we retrieve all eeprom data via a single ethtool command +# in function get_transceiver_info and get_transceiver_bulk_status +# XCVR_INTERFACE_DATA_SIZE stands for the max size to be read +# this variable is only used by get_transceiver_info. +# please be noted that each time some new value added to the function +# we should make sure that it falls into the area +# [XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE] or +# adjust XCVR_INTERFACE_MAX_SIZE to contain the new data +# It's same for [QSFP_DOM_BULK_DATA_START, QSFP_DOM_BULK_DATA_SIZE] and +# [SFP_DOM_BULK_DATA_START, SFP_DOM_BULK_DATA_SIZE] which are used by +# get_transceiver_bulk_status +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# definitions of the offset for values in OSFP info eeprom +OSFP_TYPE_OFFSET = 0 +OSFP_VENDOR_NAME_OFFSET = 129 +OSFP_VENDOR_PN_OFFSET = 148 +OSFP_HW_REV_OFFSET = 164 +OSFP_VENDOR_SN_OFFSET = 166 + +# definitions of the offset for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +#definitions of the offset and width for values in DOM info eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +QSFP_MODULE_UPPER_PAGE3_START = 384 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 + + +SFP_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 42 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 58 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 26 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 0 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 + +# identifier value of xSFP module which is in the first byte of the EEPROM +# if the identifier value falls into SFP_TYPE_CODE_LIST the module is treated as a SFP module and parsed according to 8472 +# for QSFP_TYPE_CODE_LIST the module is treated as a QSFP module and parsed according to 8436/8636 +# Originally the type (SFP/QSFP) of each module is determined according to the SKU dictionary +# where the type of each FP port is defined. The content of EEPROM is parsed according to its type. +# However, sometimes the SFP module can be fit in an adapter and then pluged into a QSFP port. +# In this case the EEPROM content is in format of SFP but parsed as QSFP, causing failure. +# To resolve that issue the type field of the xSFP module is also fetched so that we can know exectly what type the +# module is. Currently only the following types are recognized as SFP/QSFP module. +# Meanwhile, if the a module's identifier value can't be recognized, it will be parsed according to the SKU dictionary. +# This is because in the future it's possible that some new identifier value which is not regonized but backward compatible +# with the current format and by doing so it can be parsed as much as possible. +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +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_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +# Global logger class instance +logger = Logger() + +class Sfp(SfpBase): + """Platform-specific Sfp class""" + + # Port number + PORT_START = 1 + PORT_END = 32 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + # Path to QSFP sysfs + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_HWSKU_PATH = "/usr/share/sonic/hwsku" + HOST_CHK_CMD = "docker > /dev/null 2>&1" + + PLATFORM = "x86_64-quanta_ix9_bwde-r0" + HWSKU = "Quanta-IX9-32X" + + def __init__(self, sfp_index, sfp_type): + # Init index + self.index = sfp_index + self.port_num = self.index + #self.dom_supported = False + self.sfp_type = sfp_type + self.reset_path = "/sys/class/cpld-qsfpdd/port-"+str(self.port_num)+"/reset" + self.lpmode_path = "/sys/class/cpld-qsfpdd/port-"+str(self.port_num)+"/lpmode" + # Init eeprom path + eeprom_path = '/sys/bus/i2c/devices/{0}-0050/eeprom' + self.port_to_eeprom_mapping = {} + self.port_to_i2c_mapping = { + 1 : 13, + 2 : 14, + 3 : 15, + 4 : 16, + 5 : 17, + 6 : 18, + 7 : 19, + 8 : 20, + 9 : 21, + 10 : 22, + 11 : 23, + 12 : 24, + 13 : 25, + 14 : 26, + 15 : 27, + 16 : 28, + 17 : 29, + 18 : 30, + 19 : 31, + 20 : 32, + 21 : 33, + 22 : 34, + 23 : 35, + 24 : 36, + 25 : 37, + 26 : 38, + 27 : 39, + 28 : 40, + 29 : 41, + 30 : 42, + 31 : 43, + 32 : 44, + } + + for x in range(self.PORT_START, self.PORT_END + 1): + port_eeprom_path = eeprom_path.format(self.port_to_i2c_mapping[x]) + self.port_to_eeprom_mapping[x] = port_eeprom_path + + self._detect_sfp_type(sfp_type) + + self.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', 'vendor_date', 'vendor_oui', 'application_advertisement'] + + SfpBase.__init__(self) + + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def __read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + return data.strip() + except IOError: + pass + return "" + + def __is_host(self): + return os.system(self.HOST_CHK_CMD) == 0 + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self.PLATFORM]) + hwsku_path = "/".join([platform_path, self.HWSKU] + ) if self.__is_host() else self.PMON_HWSKU_PATH + return "/".join([hwsku_path, "port_config.ini"]) + + def get_presence(self): + """ + Retrieves the presence of the SFP module + Returns: + bool: True if SFP module is present, False if not + """ + # Check for invalid port_num + if self.port_num < self.PORT_START or self.port_num > self.PORT_END: + return False + + try: + reg_file = open("/sys/class/cpld-qsfpdd/port-"+str(self.port_num)+"/module_present") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + reg_value = reg_file.readline().rstrip() + if reg_value == '1': + return True + + return False + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + for n in range(0, num_bytes): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + eeprom_raw = None + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def _detect_sfp_type(self, sfp_type): + eeprom_raw = [] + eeprom_raw = self._read_eeprom_specific_bytes(XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + else: + # we don't regonize this identifier value, treat the xSFP module as the default type + self.sfp_type = sfp_type + logger.log_info("Identifier value of {} module {} is {} which isn't regonized and will be treated as default type ({})".format( + sfp_type, self.index, eeprom_raw[0], sfp_type + )) + else: + # eeprom_raw being None indicates the module is not present. + # in this case we treat it as the default type according to the SKU + self.sfp_type = sfp_type + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + if self.sfp_type == QSFP_TYPE: + self.calibration = 1 + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + offset = 128 + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes((offset + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qsfp_version_compliance_raw = self._read_eeprom_specific_bytes(QSFP_VERSION_COMPLIANCE_OFFSET, QSFP_VERSION_COMPLIANCE_WIDTH) + qsfp_version_compliance = int(qsfp_version_compliance_raw[0], 16) + dom_capability = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + if qsfp_version_compliance >= 0x08: + self.dom_temp_supported = dom_capability['data']['Temp_support']['value'] == 'On' + self.dom_volt_supported = dom_capability['data']['Voltage_support']['value'] == 'On' + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = dom_capability['data']['Tx_power_support']['value'] == 'On' + else: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = dom_capability['data']['Rx_power_support']['value'] == 'On' + self.dom_tx_power_supported = True + self.dom_supported = True + self.calibration = 1 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + qsfp_option_value_raw = self._read_eeprom_specific_bytes(QSFP_OPTION_VALUE_OFFSET, QSFP_OPTION_VALUE_WIDTH) + if qsfp_option_value_raw is not None: + optional_capability = sfpd_obj.parse_option_params(qsfp_option_value_raw, 0) + self.dom_tx_disable_supported = optional_capability['data']['TxDisable']['value'] == 'On' + dom_status_indicator = sfpd_obj.parse_dom_status_indicator(qsfp_version_compliance_raw, 1) + self.qsfp_page3_available = dom_status_indicator['data']['FlatMem']['value'] == 'Off' + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.qsfp_page3_available = False + + elif self.sfp_type == QSFP_DD_TYPE: + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes((offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + self.dom_rx_tx_power_bias_supported = True + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + + elif self.sfp_type == SFP_TYPE: + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + return None + sfp_dom_capability_raw = self._read_eeprom_specific_bytes(XCVR_DOM_CAPABILITY_OFFSET, XCVR_DOM_CAPABILITY_WIDTH) + if sfp_dom_capability_raw is not None: + sfp_dom_capability = int(sfp_dom_capability_raw[0], 16) + self.dom_supported = (sfp_dom_capability & 0x40 != 0) + if self.dom_supported: + self.dom_temp_supported = True + self.dom_volt_supported = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + if sfp_dom_capability & 0x20 != 0: + self.calibration = 1 + elif sfp_dom_capability & 0x10 != 0: + self.calibration = 2 + else: + self.calibration = 0 + else: + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + self.dom_tx_disable_supported = (int(sfp_dom_capability_raw[1], 16) & 0x40 != 0) + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ================================================================================ + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + mominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + application_advertisement |1*255VCHAR |supported applications advertisement + ================================================================================ + """ + + transceiver_info_dict = {} + compliance_code_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + if not self.get_presence(): + return transceiver_info_dict + + self._detect_sfp_type(self.sfp_type) + + transceiver_info_dict = {} + compliance_code_dict = {} + + # ToDo: OSFP tranceiver info parsing not fully supported. + # in inf8628.py lack of some memory map definition + # will be implemented when the inf8628 memory map ready + if self.sfp_type == OSFP_TYPE: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_OSFP + + sfpi_obj = inf8628InterfaceId() + if sfpi_obj is None: + return None + + sfp_type_raw = self._read_eeprom_specific_bytes((offset + OSFP_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return None + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + OSFP_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + OSFP_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + OSFP_HW_REV_OFFSET), vendor_rev_width) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + OSFP_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + transceiver_info_dict['type'] = sfp_type_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = 'N/A' + transceiver_info_dict['vendor_date'] = 'N/A' + transceiver_info_dict['connector'] = 'N/A' + transceiver_info_dict['encoding'] = 'N/A' + transceiver_info_dict['ext_identifier'] = 'N/A' + transceiver_info_dict['ext_rateselect_compliance'] = 'N/A' + transceiver_info_dict['cable_type'] = 'N/A' + transceiver_info_dict['cable_length'] = 'N/A' + transceiver_info_dict['specification_compliance'] = 'N/A' + transceiver_info_dict['nominal_bit_rate'] = 'N/A' + transceiver_info_dict['application_advertisement'] = 'N/A' + + elif self.sfp_type == QSFP_TYPE: + offset = 128 + vendor_rev_width = XCVR_HW_REV_WIDTH_QSFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_QSFP + + sfpi_obj = sff8436InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + sfp_type_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + if sfp_type_raw is not None: + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + else: + return None + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + if sfp_vendor_name_raw is not None: + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + else: + return None + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + if sfp_vendor_pn_raw is not None: + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + else: + return None + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + if sfp_vendor_rev_raw is not None: + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + else: + return None + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + if sfp_vendor_sn_raw is not None: + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + else: + return None + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + else: + return None + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + if sfp_vendor_date_raw is not None: + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + else: + return None + + sfp_connector_raw = self._read_eeprom_specific_bytes((offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + if sfp_connector_raw is not None: + sfp_connector_data = sfpi_obj.parse_connector(sfp_connector_raw, 0) + else: + return None + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes((offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + if sfp_ext_identifier_raw is not None: + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden(sfp_ext_identifier_raw, 0) + else: + return None + + sfp_cable_len_raw = self._read_eeprom_specific_bytes((offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + if sfp_cable_len_raw is not None: + sfp_cable_len_data = sfpi_obj.parse_cable_len(sfp_cable_len_raw, 0) + else: + return None + + sfp_media_type_raw = self._read_eeprom_specific_bytes(XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type(sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return None + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes((XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes((XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + sfp_application_type_second_list + else: + return None + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return None + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application(sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return None + + transceiver_info_dict['type'] = str(sfp_type_data['data']['type']['value']) + transceiver_info_dict['manufacturer'] = str(sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str(sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str(sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = str(sfp_vendor_sn_data['data']['Vendor SN']['value']) + transceiver_info_dict['vendor_oui'] = str(sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str(sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str(sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str(sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str(sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + + else: + offset = 0 + vendor_rev_width = XCVR_HW_REV_WIDTH_SFP + interface_info_bulk_width = XCVR_INTFACE_BULK_WIDTH_SFP + + sfpi_obj = sff8472InterfaceId() + if sfpi_obj is None: + print("Error: sfp_object open failed") + return None + + if self.sfp_type != QSFP_DD_TYPE: + # Add retry for xcvr eeprom to get ready + max_retry = 10 + for i in range(0,max_retry): + sfp_interface_bulk_raw = self._read_eeprom_specific_bytes( + offset + XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE) + if sfp_interface_bulk_raw is not None: + break + else: + if not self.get_presence(): + return transceiver_info_dict + elif i == max_retry-1: + pass + else: + time.sleep(0.5) + + if sfp_interface_bulk_raw is None: + return transceiver_info_dict + + start = XCVR_INTFACE_BULK_OFFSET - XCVR_INTERFACE_DATA_START + end = start + interface_info_bulk_width + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_NAME_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_NAME_WIDTH + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_PN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_PN_WIDTH + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_HW_REV_OFFSET - XCVR_INTERFACE_DATA_START + end = start + vendor_rev_width + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_SN_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_SN_WIDTH + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_OUI_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_OUI_WIDTH + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_interface_bulk_raw[start : end], 0) + + start = XCVR_VENDOR_DATE_OFFSET - XCVR_INTERFACE_DATA_START + end = start + XCVR_VENDOR_DATE_WIDTH + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_interface_bulk_raw[start : end], 0) + + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['application_advertisement'] = 'N/A' + + if self.sfp_type == QSFP_TYPE: + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + sfp_ext_specification_compliance_raw = self._read_eeprom_specific_bytes(offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance(sfp_ext_specification_compliance_raw[0 : 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + else: + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + return transceiver_info_dict + + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + RX LOS |BOOLEAN |RX lost-of-signal status, + | |True if has RX los, False if not. + TX FAULT |BOOLEAN |TX fault status, + | |True if has TX fault, False if not. + Reset status |BOOLEAN |reset status, + | |True if SFP in reset, False if not. + LP mode |BOOLEAN |low power mode status, + | |True in lp mode, False if not. + TX disable |BOOLEAN |TX disable status, + | |True TX disabled, False if not. + TX disabled channel |HEX |disabled TX channles in hex, + | |bits 0 to 3 represent channel 0 + | |to channel 3. + Temperature |INT |module temperature in Celsius + Voltage |INT |supply voltage in mV + TX bias |INT |TX Bias Current in mA + RX power |INT |received optical power in mW + TX power |INT |TX output power in mW + ======================================================================== + """ + transceiver_dom_info_dict = {} + + dom_info_dict_keys = ['temperature', 'voltage', + 'rx1power', 'rx2power', + 'rx3power', 'rx4power', + 'rx5power', 'rx6power', + 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', + 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', + 'tx3power', 'tx4power', + 'tx5power', 'tx6power', + 'tx7power', 'tx8power' + ] + transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes((offset + QSFP_DOM_BULK_DATA_START), QSFP_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_TEMPE_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start : end], 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_VOLT_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start : end], 0) + volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + start = QSFP_CHANNL_MON_OFFSET - QSFP_DOM_BULK_DATA_START + end = start + QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_data_raw[start : end], 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value']) + transceiver_dom_info_dict['tx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value']) + transceiver_dom_info_dict['tx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value']) + transceiver_dom_info_dict['tx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value']) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value']) + transceiver_dom_info_dict['rx2power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value']) + transceiver_dom_info_dict['rx3power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value']) + transceiver_dom_info_dict['rx4power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value']) + + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start : end], 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start : end], 0) + volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + offset = 512 + dom_data_raw = self._read_eeprom_specific_bytes(offset + QSFP_DD_CHANNL_MON_OFFSET, QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value'])) + transceiver_dom_info_dict['tx2power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value'])) + transceiver_dom_info_dict['tx3power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value'])) + transceiver_dom_info_dict['tx4power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value'])) + transceiver_dom_info_dict['tx5power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX5Power']['value'])) + transceiver_dom_info_dict['tx6power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX6Power']['value'])) + transceiver_dom_info_dict['tx7power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX7Power']['value'])) + transceiver_dom_info_dict['tx8power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX8Power']['value'])) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value'])) + transceiver_dom_info_dict['rx2power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value'])) + transceiver_dom_info_dict['rx3power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value'])) + transceiver_dom_info_dict['rx4power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value'])) + transceiver_dom_info_dict['rx5power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX5Power']['value'])) + transceiver_dom_info_dict['rx6power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX6Power']['value'])) + transceiver_dom_info_dict['rx7power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX7Power']['value'])) + transceiver_dom_info_dict['rx8power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX8Power']['value'])) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str(dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str(dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str(dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str(dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str(dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str(dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str(dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str(dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + else: + if not self.dom_supported: + return transceiver_dom_info_dict + + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + sfpd_obj._calibration_type = self.calibration + + dom_data_raw = self._read_eeprom_specific_bytes((offset + SFP_DOM_BULK_DATA_START), SFP_DOM_BULK_DATA_SIZE) + + start = SFP_TEMPE_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start: end], 0) + + start = SFP_VOLT_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start: end], 0) + + start = SFP_CHANNL_MON_OFFSET - SFP_DOM_BULK_DATA_START + end = start + SFP_CHANNL_MON_WIDTH + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_data_raw[start: end], 0) + + transceiver_dom_info_dict['temperature'] = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + transceiver_dom_info_dict['voltage'] = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + transceiver_dom_info_dict['rx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['RXPower']['value']) + transceiver_dom_info_dict['tx1bias'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TXBias']['value']) + transceiver_dom_info_dict['tx1power'] = self._convert_string_to_num(dom_channel_monitor_data['data']['TXPower']['value']) + + return transceiver_dom_info_dict + + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = {} + + dom_info_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning' + ] + transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if self.sfp_type == OSFP_TYPE: + pass + + elif self.sfp_type == QSFP_TYPE: + if not self.dom_supported or not self.qsfp_page3_available: + return transceiver_dom_threshold_info_dict + + # Dom Threshold data starts from offset 384 + # Revert offset back to 0 once data is retrieved + offset = QSFP_MODULE_UPPER_PAGE3_START + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_THRESHOLD_OFFSET), + QSFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is None: + return transceiver_dom_threshold_info_dict + dom_channel_threshold_data = sfpd_obj.parse_channel_threshold_values(dom_channel_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + + elif self.sfp_type == QSFP_DD_TYPE: + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = 384 + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + else: + offset = SFP_MODULE_ADDRA2_OFFSET + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = sff8472Dom(None, self.calibration) + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + else: + return transceiver_dom_threshold_info_dict + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + return False + elif self.sfp_type == OSFP_TYPE or self.sfp_type == QSFP_DD_TYPE: + try: + reg_file = open(self.reset_path) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return None + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return True + else: + return False + else: + return None + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 512 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + rx_los_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x02 != 0) + else: + return None + return rx_los_list + + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + tx_fault_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + + elif self.sfp_type == QSFP_DD_TYPE: + return None + # page 11h + #if self.dom_rx_tx_power_bias_supported: + # offset = 512 + # dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET), QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH) + # if dom_channel_monitor_raw is not None: + # tx_fault_data = int(dom_channel_monitor_raw[0], 8) + # tx_fault_list.append(tx_fault_data & 0x01 != 0) + # tx_fault_list.append(tx_fault_data & 0x02 != 0) + # tx_fault_list.append(tx_fault_data & 0x04 != 0) + # tx_fault_list.append(tx_fault_data & 0x08 != 0) + # tx_fault_list.append(tx_fault_data & 0x10 != 0) + # tx_fault_list.append(tx_fault_data & 0x20 != 0) + # tx_fault_list.append(tx_fault_data & 0x40 != 0) + # tx_fault_list.append(tx_fault_data & 0x80 != 0) + + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + else: + return None + return tx_fault_list + + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + + for QSFP, the disable states of each channel which are the lower 4 bits in byte 85 page a0 + for SFP, the TX Disable State and Soft TX Disable Select is ORed as the tx_disable status returned + These two bits are bit 7 & 6 in byte 110 page a2 respectively + """ + if not self.dom_supported: + return None + + tx_disable_list = [] + if self.sfp_type == OSFP_TYPE: + return None + elif self.sfp_type == QSFP_TYPE: + offset = 0 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_DISABLE_STATUS_OFFSET), QSFP_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + + elif self.sfp_type == QSFP_DD_TYPE: + if self.dom_rx_tx_power_bias_supported: + offset = 128 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET), QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0x01 != 0) + tx_disable_list.append(tx_disable_data & 0x02 != 0) + tx_disable_list.append(tx_disable_data & 0x04 != 0) + tx_disable_list.append(tx_disable_data & 0x08 != 0) + tx_disable_list.append(tx_disable_data & 0x10 != 0) + tx_disable_list.append(tx_disable_data & 0x20 != 0) + tx_disable_list.append(tx_disable_data & 0x40 != 0) + tx_disable_list.append(tx_disable_data & 0x80 != 0) + + else: + offset = 256 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_STATUS_OFFSET), SFP_CHANNL_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_disable_data = int(dom_channel_monitor_raw[0], 16) + tx_disable_list.append(tx_disable_data & 0xC0 != 0) + else: + return None + return tx_disable_list + + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return 0 + elif self.sfp_type == QSFP_TYPE: + tx_disable_list = self.get_tx_disable() + if tx_disable_list is None: + return 0 + tx_disabled = 0 + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disabled |= 1 << i + else: + return None + + return tx_disabled + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this QSFP module + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + return False + elif self.sfp_type == OSFP_TYPE: + try: + reg_file = open(self.lpmode_path) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + reg_value = int(reg_file.readline().rstrip()) + reg_file.close() + if reg_value == 0: + return False + else: + return True + else: + return None + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + offset = 0 + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return False + + dom_control_raw = self._read_eeprom_specific_bytes( + (offset + QSFP_POWEROVERRIDE_OFFSET), QSFP_POWEROVERRIDE_WIDTH) + if dom_control_raw is not None: + if int(dom_control_raw[0],16) & (0x01 << QSFP_POWEROVERRIDE_BIT): + return True + else: + return False + else: + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + An integer number of current temperature in Celsius + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + else: + return None + + elif self.sfp_type == QSFP_DD_TYPE: + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + return None + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = 1 + + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + else: + return None + + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + An integer number of supply voltage in mV + """ + if not self.dom_supported: + return None + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + return None + + if self.sfp_type == QSFP_DD_TYPE: + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + return None + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + sfpd_obj._calibration_type = self.calibration + + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + else: + return None + + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + if self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Bias']['value'])) + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = 512 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias(dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX8Bias']['value'])) + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + sfpd_obj._calibration_type = self.calibration + + if self.dom_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TXBias']['value'])) + else: + return None + else: + return None + + return tx_bias_list + + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value'])) + else: + return None + else: + return None + + elif self.sfp_type == QSFP_DD_TYPE: + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = 512 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power(dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX8Power']['value'])) + + else: + offset = 256 + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['RXPower']['value'])) + else: + return None + else: + return None + return rx_power_list + + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + if self.sfp_type == OSFP_TYPE: + # OSFP not supported on our platform yet. + return None + + elif self.sfp_type == QSFP_TYPE: + offset = 0 + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_power_supported: + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value'])) + else: + return None + else: + return None + + elif self.sfp_type == QSFP_DD_TYPE: + return None + # page 11 + #if self.dom_rx_tx_power_bias_supported: + # offset = 512 + # sfpd_obj = qsfp_dd_Dom() + # if sfpd_obj is None: + # return None + # + # if self.dom_tx_power_supported: + # dom_tx_power_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TX_POWER_OFFSET), QSFP_DD_TX_POWER_WIDTH) + # if dom_tx_power_raw is not None: + # dom_tx_power_data = sfpd_obj.parse_dom_tx_power(dom_tx_power_raw, 0) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX1Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX2Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX3Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX4Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX5Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX6Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX7Power']['value'])) + # tx_power_list.append(self._convert_string_to_num(dom_tx_power_data['data']['TX8Power']['value'])) + + else: + offset = 256 + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + if self.dom_supported: + sfpd_obj._calibration_type = self.calibration + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TXPower']['value'])) + else: + return None + else: + return None + return tx_power_list + + + def reset(self): + """ + Reset SFP and return all user module settings to their default state. + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + return False + elif self.sfp_type == OSFP_TYPE: + try: + reg_file = open(self.reset_path, "r+") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + # Flip the value back write back to the register to take port out of reset + try: + reg_file = open(self.reset_path, "r+") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + if self.dom_tx_disable_supported: + offset = 256 + sysfs_sfp_i2c_client_eeprom_path = self.port_to_eeprom_mapping[self.port_num] + status_control_raw = self._read_eeprom_specific_bytes( + (offset + SFP_STATUS_CONTROL_OFFSET), SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else ( + status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open( + sysfs_sfp_i2c_client_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(offset + SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + else: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + channel_mask = 0x0f + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + else: + return None + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + Returns: + A boolean, True if successful, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + if self.dom_tx_disable_supported: + sysfsfile_eeprom = None + try: + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom = open( + self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + else: + return False + else: + return None + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if not self.get_presence(): + return False + # SFP doesn't support this feature + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + return False + elif self.sfp_type == OSFP_TYPE: + try: + reg_file = open(self.lpmode_path, "r+") + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + # LPMode is active high; set or clear the bit accordingly + if lpmode: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + else: + return None + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + if not self.get_presence(): + return False + + if self.sfp_type == SFP_TYPE: + return False + elif self.sfp_type == QSFP_TYPE: + try: + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + # Write to eeprom + sysfsfile_eeprom = open(self.port_to_eeprom_mapping[self.port_num], "r+b") + sysfsfile_eeprom.seek(QSFP_POWEROVERRIDE_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + finally: + if sysfsfile_eeprom is not None: + sysfsfile_eeprom.close() + time.sleep(0.01) + else: + return None + + return True + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + sfputil_helper = SfpUtilHelper() + sfputil_helper.read_porttab_mappings(self.__get_path_to_port_config_file()) + print ("self.index{}".format(self.index)) + name = sfputil_helper.logical[self.index-1] or "Unknown" + return name + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/thermal.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/thermal.py new file mode 100644 index 0000000000..5fb2097492 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/thermal.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python + +############################################################################# +# Quanta +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Thermal information +# +############################################################################# + +import logging +import os + +try: + from sonic_platform_base.thermal_base import ThermalBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +HWMON_DIR = "/sys/class/hwmon/hwmon2/" + +thermal_index_mapping = { + 1:40, + 2:41, + 3:42, + 4:50, + 5:51, + 6:52, + 7:73, + 8:74, + 9:75, + 10:76, + 11:77, + 12:78, + 13:79, + 14:80, + 15:81, + 16:82, + 17:83, + 18:84, + 19:85 +} + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + def __init__(self, thermal_index): + self.index = thermal_index + self.temp_attr = "temp{}_input".format(thermal_index_mapping[self.index]) + self.high_th_attr = "temp{}_ncrit".format(thermal_index_mapping[self.index]) + self.high_crit_th_attr = "temp{}_crit".format(thermal_index_mapping[self.index]) + self.name_attr = "temp{}_label".format(thermal_index_mapping[self.index]) + + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open " + attr_path + " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return attr_rv + else: + return None + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + attr_path = HWMON_DIR + self.name_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return True + else: + return False + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + if (self.get_temperature() != None): + return True + else: + return False + + 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 + """ + attr_path = HWMON_DIR + self.temp_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + 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 + """ + attr_path = HWMON_DIR + self.high_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + + def get_high_critical_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 + """ + attr_path = HWMON_DIR + self.high_crit_th_attr + attr_rv = self.__get_attr_value(attr_path) + + if (attr_rv != 'ERR'): + return float(attr_rv) / 1000 + else: + return None + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/watchdog.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/watchdog.py new file mode 100644 index 0000000000..282f356f4e --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform/watchdog.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python + +############################################################################# +# +# Watchdog contains an implementation of SONiC Platform Base Watchdog API +# +############################################################################# +import fcntl +import os +import array + +try: + from sonic_platform_base.watchdog_base import WatchdogBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +""" ioctl constants """ +IO_WRITE = 0x40000000 +IO_READ = 0x80000000 +IO_READ_WRITE = 0xC0000000 +IO_SIZE_INT = 0x00040000 +IO_SIZE_40 = 0x00280000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDR_40 = IO_READ | IO_SIZE_40 | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +""" Watchdog ioctl commands """ +WDIOC_GETSUPPORT = 0 | WDR_40 +WDIOC_GETSTATUS = 1 | WDR_INT +WDIOC_GETBOOTSTATUS = 2 | WDR_INT +WDIOC_GETTEMP = 3 | WDR_INT +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_SETPRETIMEOUT = 8 | WDWR_INT +WDIOC_GETPRETIMEOUT = 9 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +""" Watchdog status constants """ +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +WDT_COMMON_ERROR = -1 +WD_MAIN_IDENTITY = "iTCO_wdt" +WDT_SYSFS_PATH = "/sys/class/watchdog/" + +DEFAULT_TIMEOUT=180 + +class Watchdog(WatchdogBase): + + def __init__(self): + + self.watchdog, self.wdt_main_dev_name = self._get_wdt() + self.status_path = "/sys/class/watchdog/%s/status" % self.wdt_main_dev_name + self.state_path = "/sys/class/watchdog/%s/state" % self.wdt_main_dev_name + self.timeout_path = "/sys/class/watchdog/%s/timeout" % self.wdt_main_dev_name + # Set default value + self._disable() + self.armed = False + self.timeout = DEFAULT_TIMEOUT + + def _is_wd_main(self, dev): + """ + Checks watchdog identity + """ + identity = self._read_file( + "{}/{}/identity".format(WDT_SYSFS_PATH, dev)) + return identity == WD_MAIN_IDENTITY + + def _get_wdt(self): + """ + Retrieves watchdog device + """ + wdt_main_dev_list = [dev for dev in os.listdir( + "/dev/") if dev.startswith("watchdog") and self._is_wd_main(dev)] + if not wdt_main_dev_list: + return None + wdt_main_dev_name = wdt_main_dev_list[0] + watchdog_device_path = "/dev/{}".format(wdt_main_dev_name) + self.watchdog = os.open(watchdog_device_path, os.O_RDWR) + return self.watchdog, wdt_main_dev_name + + def _read_file(self, file_path): + """ + Read text file + """ + try: + with open(file_path, "r") as fd: + txt = fd.read() + except IOError: + return WDT_COMMON_ERROR + return txt.strip() + + def _enable(self): + """ + Turn on the watchdog timer + """ + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _disable(self): + """ + Turn off the watchdog timer + """ + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def _settimeout(self, seconds): + """ + Set watchdog timer timeout + @param seconds - timeout in seconds + @return is the actual set timeout + """ + req = array.array('I', [seconds]) + fcntl.ioctl(self.watchdog, WDIOC_SETTIMEOUT, req, True) + return int(req[0]) + + def _gettimeout(self, timeout_path): + """ + Get watchdog timeout + @return watchdog timeout + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMEOUT, req, True) + + return int(req[0]) + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + req = array.array('I', [0]) + fcntl.ioctl(self.watchdog, WDIOC_GETTIMELEFT, req, True) + + return int(req[0]) + + ################################################################# + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of 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 , 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. + """ + + ret = WDT_COMMON_ERROR + if seconds < 0: + return ret + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.armed: + self._keepalive() + else: + self._settimeout(seconds) + self._enable() + self.armed = True + ret = self.timeout + except IOError as e: + pass + + return ret + + def disarm(self): + """ + Disarm the hardware watchdog + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + disarmed = False + if self.is_armed(): + try: + self._disable() + self.armed = False + disarmed = True + except IOError: + pass + + return disarmed + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + Returns: + A boolean, True if watchdog is armed, False if not + """ + + return self.armed + + 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 thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + + timeleft = WDT_COMMON_ERROR + + if self.armed: + try: + timeleft = self._gettimeleft() + except IOError: + pass + + return timeleft + + def __del__(self): + """ + Close watchdog + """ + + os.close(self.watchdog) + + + diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform_setup.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform_setup.py new file mode 100644 index 0000000000..b1ba374776 --- /dev/null +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/sonic_platform_setup.py @@ -0,0 +1,24 @@ +import os +from setuptools import setup +os.listdir + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Quanta Platforms', + license='Apache 2.0', + packages=['sonic_platform'], + classifiers=[ + 'Development Status :: 3 - Alpha', + 'Environment :: Plugins', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: Apache Software License', + 'Natural Language :: English', + 'Operating System :: POSIX :: Linux', + 'Programming Language :: Python :: 3.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/utils/quanta_ix9_util.py b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/utils/quanta_ix9_util.py index 4c31aa8584..0554ccbf1b 100755 --- a/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/utils/quanta_ix9_util.py +++ b/platform/broadcom/sonic-platform-modules-quanta/ix9-32x/utils/quanta_ix9_util.py @@ -31,9 +31,6 @@ import os import commands import sys, getopt import logging -import re -import time -from collections import namedtuple DEBUG = False args = [] @@ -123,46 +120,87 @@ instantiate =[ 'echo 40 > /sys/class/gpio/export', 'echo out > /sys/class/gpio/gpio40/direction', 'echo 1 > /sys/class/gpio/gpio40/value', +#Set 1 to release reset pins (low active) +'echo 1 > /sys/class/cpld-qsfpdd/port-1/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-2/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-3/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-4/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-5/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-6/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-7/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-8/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-9/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-10/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-11/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-12/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-13/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-14/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-15/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-16/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-17/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-18/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-19/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-20/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-21/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-22/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-23/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-24/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-25/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-26/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-27/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-28/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-29/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-30/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-31/reset', +'echo 1 > /sys/class/cpld-qsfpdd/port-32/reset' ] drivers =[ 'lpc_ich', 'i2c-i801', 'i2c-dev', -'i2c-mux-pca954x', +'i2c-mux-pca954x force_deselect_on_exit=1', 'gpio-pca953x', +'optoe', 'qci_cpld_qsfpdd', 'qci_cpld_led', 'qci_platform_ix9', +'quanta_hwmon_ipmi', 'ipmi_devintf' ] - +un_drivers =[ +'lpc_ich', +'i2c-i801', +'i2c-dev', +'i2c-mux-pca954x', +'gpio-pca953x', +'optoe', +'qci_cpld_qsfpdd', +'qci_cpld_led', +'qci_platform_ix9', +'quanta_hwmon_ipmi', +'ipmi_devintf' +] def system_install(): global FORCE - #remove default drivers to avoid modprobe order conflicts - status, output = exec_cmd("rmmod i2c_ismt ", 1) - status, output = exec_cmd("rmmod i2c-i801 ", 1) #setup driver dependency - status, output = exec_cmd("depmod -a ", 1) + exec_cmd("depmod -a ", 1) #install drivers for i in range(0,len(drivers)): - status, output = exec_cmd("modprobe "+drivers[i], 1) + status, output = exec_cmd("modprobe " + drivers[i], 1) if status: print output if FORCE == 0: return status - #remove net rules for generating new net rules - status, output = exec_cmd("systemctl stop systemd-udevd.service ", 1) - status, output = exec_cmd("rm /etc/udev/rules.d/70-persistent-net.rules ", 1) - status, output = exec_cmd("rmmod ixgbe ", 1) - status, output = exec_cmd("rmmod igb ", 1) - status, output = exec_cmd("modprobe igb ", 1) - status, output = exec_cmd("modprobe ixgbe ", 1) - status, output = exec_cmd("systemctl start systemd-udevd.service ", 1) + #reload ethernet drivers in correct order + exec_cmd("rmmod ixgbe ", 1) + exec_cmd("rmmod igb ", 1) + exec_cmd("modprobe igb ", 1) + exec_cmd("modprobe ixgbe ", 1) #instantiate devices for i in range(0,len(instantiate)): @@ -174,7 +212,7 @@ def system_install(): #QSFPDD for 1~32 port for port_number in range(1,33): - bus_number = port_number + 31 + bus_number = port_number + 12 os.system("echo %d >/sys/bus/i2c/devices/%d-0050/port_name" % (port_number, bus_number)) return @@ -191,6 +229,11 @@ def install(): if status: if FORCE == 0: return status + status, output = exec_cmd("pip3 install /usr/share/sonic/device/x86_64-quanta_ix9_bwde-r0/sonic_platform-1.0-py3-none-any.whl",1) + if status: + print output + if FORCE == 0: + return status else: print " ix9 driver already installed...." return @@ -198,20 +241,29 @@ def install(): def uninstall(): global FORCE #uninstall drivers - for i in range(len(drivers)-1,-1,-1): - status, output = exec_cmd("rmmod "+drivers[i], 1) + for i in range(len(un_drivers) - 1, -1, -1): + status, output = exec_cmd("rmmod " + un_drivers[i], 1) if status: print output if FORCE == 0: return status + + status, output = exec_cmd("pip3 uninstall sonic-platform -y ",1) + if status: + print output + if FORCE == 0: + return status + return def device_found(): - ret1, log = exec_cmd("ls "+i2c_prefix+"i2c-0", 0) - return ret1 + ret1, log1 = exec_cmd("cat /proc/modules | grep ix9 > /tmp/chkdriver.log", 0) + ret2, log2 = exec_cmd("cat /tmp/chkdriver.log | grep ix9", 0) + + if ret1 == 0 and len(log2) > 0: + return True + else: + return False if __name__ == "__main__": main() - - -