diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers.json.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_def.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_def.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_def.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_t0.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_t0.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_t1.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/buffers_defaults_t1.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/hwsku.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/hwsku.json new file mode 100644 index 0000000000..53a33ec587 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/hwsku.json @@ -0,0 +1,132 @@ +{ + "interfaces": { + "Ethernet0": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet4": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet8": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet12": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet16": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet20": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet24": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet28": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet32": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet36": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet40": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet44": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet48": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet52": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet56": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet60": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet64": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet68": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet72": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet76": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet80": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet84": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet88": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet92": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet96": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet100": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet104": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet108": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet112": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet116": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet120": { + "default_brkout_mode": "2x100G", + "fec": "rs" + }, + "Ethernet124": { + "default_brkout_mode": "2x100G", + "fec": "rs" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/lanes_polarity.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/lanes_polarity.json new file mode 100644 index 0000000000..bcbe69e306 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/lanes_polarity.json @@ -0,0 +1,900 @@ +{ + "pn_list": [ + { + "rx_inverse": true, + "lane": "0_0", + "fp_port": 14, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "0_1", + "fp_port": 14, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "0_2", + "fp_port": 14, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "0_3", + "fp_port": 14, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "0_4", + "fp_port": 14, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "0_5", + "fp_port": 14, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "0_6", + "fp_port": 14, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "0_7", + "fp_port": 14, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "1_0", + "fp_port": 13, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "1_1", + "fp_port": 13, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "1_2", + "fp_port": 13, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "1_3", + "fp_port": 13, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "1_4", + "fp_port": 13, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "1_5", + "fp_port": 13, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "1_6", + "fp_port": 13, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "1_7", + "fp_port": 13, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "2_0", + "fp_port": 4, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "2_1", + "fp_port": 4, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "2_2", + "fp_port": 4, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "2_3", + "fp_port": 4, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "2_4", + "fp_port": 4, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "2_5", + "fp_port": 4, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "2_6", + "fp_port": 4, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "2_7", + "fp_port": 4, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "3_0", + "fp_port": 3, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "3_1", + "fp_port": 3, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "3_2", + "fp_port": 3, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "3_3", + "fp_port": 3, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "3_4", + "fp_port": 3, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "3_5", + "fp_port": 3, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "3_6", + "fp_port": 3, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "3_7", + "fp_port": 3, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "4_0", + "fp_port": 11, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "4_1", + "fp_port": 11, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "4_2", + "fp_port": 11, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "4_3", + "fp_port": 11, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "4_4", + "fp_port": 11, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "4_5", + "fp_port": 11, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "4_6", + "fp_port": 11, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "4_7", + "fp_port": 11, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "5_0", + "fp_port": 12, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "5_1", + "fp_port": 12, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "5_2", + "fp_port": 12, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "5_3", + "fp_port": 12, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "5_4", + "fp_port": 12, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "5_5", + "fp_port": 12, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "5_6", + "fp_port": 12, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "5_7", + "fp_port": 12, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "6_0", + "fp_port": 5, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "6_1", + "fp_port": 5, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "6_2", + "fp_port": 5, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "6_3", + "fp_port": 5, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "6_4", + "fp_port": 5, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "6_5", + "fp_port": 5, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "6_6", + "fp_port": 5, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "6_7", + "fp_port": 5, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "7_0", + "fp_port": 6, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "7_1", + "fp_port": 6, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "7_2", + "fp_port": 6, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "7_3", + "fp_port": 6, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "7_4", + "fp_port": 6, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "7_5", + "fp_port": 6, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "7_6", + "fp_port": 6, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "7_7", + "fp_port": 6, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "8_0", + "fp_port": 15, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "8_1", + "fp_port": 15, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "8_2", + "fp_port": 15, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "8_3", + "fp_port": 15, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "8_4", + "fp_port": 15, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "8_5", + "fp_port": 15, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "8_6", + "fp_port": 15, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "8_7", + "fp_port": 15, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "9_0", + "fp_port": 16, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "9_1", + "fp_port": 16, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "9_2", + "fp_port": 16, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "9_3", + "fp_port": 16, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "9_4", + "fp_port": 16, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "9_5", + "fp_port": 16, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "9_6", + "fp_port": 16, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "9_7", + "fp_port": 16, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "10_0", + "fp_port": 9, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "10_1", + "fp_port": 9, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "10_2", + "fp_port": 9, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "10_3", + "fp_port": 9, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "10_4", + "fp_port": 9, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "10_5", + "fp_port": 9, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "10_6", + "fp_port": 9, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "10_7", + "fp_port": 9, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "11_0", + "fp_port": 10, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "11_1", + "fp_port": 10, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "11_2", + "fp_port": 10, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "11_3", + "fp_port": 10, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "11_4", + "fp_port": 10, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "11_5", + "fp_port": 10, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "11_6", + "fp_port": 10, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "11_7", + "fp_port": 10, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "12_0", + "fp_port": 2, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "12_1", + "fp_port": 2, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "12_2", + "fp_port": 2, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "12_3", + "fp_port": 2, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "12_4", + "fp_port": 2, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "12_5", + "fp_port": 2, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "12_6", + "fp_port": 2, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "12_7", + "fp_port": 2, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "13_0", + "fp_port": 1, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "13_1", + "fp_port": 1, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "13_2", + "fp_port": 1, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "13_3", + "fp_port": 1, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "13_4", + "fp_port": 1, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "13_5", + "fp_port": 1, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "13_6", + "fp_port": 1, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "13_7", + "fp_port": 1, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "14_0", + "fp_port": 8, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "14_1", + "fp_port": 8, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "14_2", + "fp_port": 8, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "14_3", + "fp_port": 8, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "14_4", + "fp_port": 8, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "14_5", + "fp_port": 8, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "14_6", + "fp_port": 8, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "14_7", + "fp_port": 8, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "15_0", + "fp_port": 7, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "15_1", + "fp_port": 7, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "15_2", + "fp_port": 7, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "15_3", + "fp_port": 7, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "15_4", + "fp_port": 7, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "15_5", + "fp_port": 7, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "15_6", + "fp_port": 7, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "15_7", + "fp_port": 7, + "tx_inverse": false, + "offset": 8 + } + ] +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/pg_profile_lookup.ini b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/pg_profile_lookup.ini new file mode 100644 index 0000000000..1050abe886 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/pg_profile_lookup.ini @@ -0,0 +1,18 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1518 0 15680 1 9408 + 100000 5m 1518 0 34624 1 9408 + 200000 5m 1518 0 62368 1 9408 + 400000 5m 1518 0 117536 1 9408 + 10000 40m 1518 0 16928 1 9408 + 100000 40m 1518 0 38816 1 9408 + 200000 40m 1518 0 71904 1 9408 + 400000 40m 1518 0 135520 1 9408 + 10000 100m 1518 0 18848 1 9408 + 100000 100m 1518 0 46496 1 9408 + 200000 100m 1518 0 87168 1 9408 + 400000 100m 1518 0 166688 1 9408 + 10000 300m 1518 0 25184 1 9408 + 100000 300m 1518 0 72384 1 9408 + 200000 300m 1518 0 138112 1 9408 + 400000 300m 1518 0 268640 1 9408 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/port_config.ini b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/port_config.ini new file mode 100644 index 0000000000..f93de5208b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed +Ethernet0 0,1,2,3 Eth1/1 1 100000 +Ethernet4 4,5,6,7 Eth2/1 2 100000 +Ethernet8 8,9,10,11 Eth3/1 3 100000 +Ethernet12 12,13,14,15 Eth4/1 4 100000 +Ethernet16 16,17,18,19 Eth5/1 5 100000 +Ethernet20 20,21,22,23 Eth6/1 6 100000 +Ethernet24 24,25,26,27 Eth7/1 7 100000 +Ethernet28 28,29,30,31 Eth8/1 8 100000 +Ethernet32 32,33,34,35 Eth9/1 9 100000 +Ethernet36 36,37,38,39 Eth10/1 10 100000 +Ethernet40 40,41,42,43 Eth11/1 11 100000 +Ethernet44 44,45,46,47 Eth12/1 12 100000 +Ethernet48 48,49,50,51 Eth13/1 13 100000 +Ethernet52 52,53,54,55 Eth14/1 14 100000 +Ethernet56 56,57,58,59 Eth15/1 15 100000 +Ethernet60 60,61,62,63 Eth16/1 16 100000 +Ethernet64 64,65,66,67 Eth17/1 17 100000 +Ethernet68 68,69,70,71 Eth18/1 18 100000 +Ethernet72 72,73,74,75 Eth19/1 19 100000 +Ethernet76 76,77,78,79 Eth20/1 20 100000 +Ethernet80 80,81,82,83 Eth21/1 21 100000 +Ethernet84 84,85,86,87 Eth22/1 22 100000 +Ethernet88 88,89,90,91 Eth23/1 23 100000 +Ethernet92 92,93,94,95 Eth24/1 24 100000 +Ethernet96 96,97,98,99 Eth25/1 25 100000 +Ethernet100 100,101,102,103 Eth26/1 26 100000 +Ethernet104 104,105,106,107 Eth27/1 27 100000 +Ethernet108 108,109,110,111 Eth28/1 28 100000 +Ethernet112 112,113,114,115 Eth29/1 29 100000 +Ethernet116 116,117,118,119 Eth30/1 30 100000 +Ethernet120 120,121,122,123 Eth31/1 31 100000 +Ethernet124 124,125,126,127 Eth32/1 32 100000 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/qos.json.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/qos.json.j2 new file mode 100644 index 0000000000..04def202c4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/qos.json.j2 @@ -0,0 +1,206 @@ +{% set port_names_list = [] %} +{% for port in PORT %} + {%- if port_names_list.append(port) %}{% endif %} +{% endfor %} +{% set port_names = port_names_list | join(',') -%} + + +{ + "TC_TO_QUEUE_MAP":{ + "AZURE":{ + "0":"0", + "1":"1", + "2":"2", + "3":"3", + "4":"4", + "5":"5", + "6":"6", + "7":"7" + } + }, + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "0" + } + }, + "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" + } + }, + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "1" + } + }, + "QUEUE": { +{% for port in port_names_list %} + "{{ port }}|3": { + "scheduler" : "scheduler.1", + "wred_profile" : "AZURE_LOSSLESS" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|4": { + "scheduler" : "scheduler.1", + "wred_profile" : "AZURE_LOSSLESS" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|0": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|1": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|2": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|5": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|6": { + "scheduler": "scheduler.0" + }{% if not loop.last %},{% endif %} + +{% endfor %} + }, + "PORT_QOS_MAP": { +{% for port in port_names_list %} + "{{ port }}": { + "tc_to_pg_map": "AZURE", + "pfc_to_pg_map": "AZURE", + "tc_to_queue_map": "AZURE", + "dscp_to_tc_map": "AZURE", + "pfc_to_queue_map": "AZURE", + "pfcwd_sw_enable" : "3,4", + "pfc_enable": "3,4" + }{% if not loop.last %},{% endif %} + +{% endfor %} + }, + "WRED_PROFILE": { + "AZURE_LOSSLESS" : { + "wred_green_enable" : "true", + "wred_yellow_enable" : "true", + "wred_red_enable" : "true", + "ecn" : "ecn_all", + "green_max_threshold" : "2097152", + "green_min_threshold" : "1048576", + "yellow_max_threshold" : "2097152", + "yellow_min_threshold" : "1048576", + "red_max_threshold" : "2097152", + "red_min_threshold" : "1048576", + "green_drop_probability" : "5", + "yellow_drop_probability": "5", + "red_drop_probability" : "5" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/sai.profile b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/sai.profile new file mode 100644 index 0000000000..2d4d56037f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/xdrv_config.json diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/xdrv_config.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/xdrv_config.json new file mode 100644 index 0000000000..48bc7542b8 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/xdrv_config.json @@ -0,0 +1,14 @@ +{ + "flush_reg_mem_access_file": false, + "qqm_number": 4, + "bm_size": 64, + "version": "0.0", + "reg_mem_access_file": false, + "device_list": [ + { + "ip": "localhost", + "id": 0, + "port": 49153 + } + ] +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/xlink_cfg.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/xlink_cfg.json new file mode 100644 index 0000000000..8f3ebab40b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x100G/xlink_cfg.json @@ -0,0 +1,144 @@ +{ + "driver": "xdrv_config.json", + "lanes_polarity": "lanes_polarity.json", + "version": "0.0", + "management_ports": [ + 136 + ], + "network_ports": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127 + ], + + "ucode": "ucode.json", + + "serdes_config": "serdes_config.json", + + "tables_config": "xsw_auto_table_properties.json" +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers.json.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_def.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_def.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_def.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_t0.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_t0.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_t1.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/buffers_defaults_t1.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/hwsku.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/hwsku.json new file mode 100644 index 0000000000..40c4e0139d --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/hwsku.json @@ -0,0 +1,132 @@ +{ + "interfaces": { + "Ethernet0": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet4": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet8": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet12": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet16": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet20": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet24": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet28": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet32": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet36": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet40": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet44": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet48": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet52": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet56": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet60": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet64": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet68": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet72": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet76": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet80": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet84": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet88": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet92": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet96": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet100": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet104": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet108": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet112": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet116": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet120": { + "default_brkout_mode": "2x400G", + "fec": "rs" + }, + "Ethernet124": { + "default_brkout_mode": "2x400G", + "fec": "rs" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/lanes_polarity.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/lanes_polarity.json new file mode 100644 index 0000000000..bcbe69e306 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/lanes_polarity.json @@ -0,0 +1,900 @@ +{ + "pn_list": [ + { + "rx_inverse": true, + "lane": "0_0", + "fp_port": 14, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "0_1", + "fp_port": 14, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "0_2", + "fp_port": 14, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "0_3", + "fp_port": 14, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "0_4", + "fp_port": 14, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "0_5", + "fp_port": 14, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "0_6", + "fp_port": 14, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "0_7", + "fp_port": 14, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "1_0", + "fp_port": 13, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "1_1", + "fp_port": 13, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "1_2", + "fp_port": 13, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "1_3", + "fp_port": 13, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "1_4", + "fp_port": 13, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "1_5", + "fp_port": 13, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "1_6", + "fp_port": 13, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "1_7", + "fp_port": 13, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "2_0", + "fp_port": 4, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "2_1", + "fp_port": 4, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "2_2", + "fp_port": 4, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "2_3", + "fp_port": 4, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "2_4", + "fp_port": 4, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "2_5", + "fp_port": 4, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "2_6", + "fp_port": 4, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "2_7", + "fp_port": 4, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "3_0", + "fp_port": 3, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "3_1", + "fp_port": 3, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "3_2", + "fp_port": 3, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "3_3", + "fp_port": 3, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "3_4", + "fp_port": 3, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "3_5", + "fp_port": 3, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "3_6", + "fp_port": 3, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "3_7", + "fp_port": 3, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "4_0", + "fp_port": 11, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "4_1", + "fp_port": 11, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "4_2", + "fp_port": 11, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "4_3", + "fp_port": 11, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "4_4", + "fp_port": 11, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "4_5", + "fp_port": 11, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "4_6", + "fp_port": 11, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "4_7", + "fp_port": 11, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "5_0", + "fp_port": 12, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "5_1", + "fp_port": 12, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "5_2", + "fp_port": 12, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "5_3", + "fp_port": 12, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "5_4", + "fp_port": 12, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "5_5", + "fp_port": 12, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "5_6", + "fp_port": 12, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "5_7", + "fp_port": 12, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "6_0", + "fp_port": 5, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "6_1", + "fp_port": 5, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "6_2", + "fp_port": 5, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "6_3", + "fp_port": 5, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "6_4", + "fp_port": 5, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "6_5", + "fp_port": 5, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "6_6", + "fp_port": 5, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "6_7", + "fp_port": 5, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "7_0", + "fp_port": 6, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "7_1", + "fp_port": 6, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "7_2", + "fp_port": 6, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "7_3", + "fp_port": 6, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "7_4", + "fp_port": 6, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "7_5", + "fp_port": 6, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "7_6", + "fp_port": 6, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "7_7", + "fp_port": 6, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "8_0", + "fp_port": 15, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "8_1", + "fp_port": 15, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "8_2", + "fp_port": 15, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "8_3", + "fp_port": 15, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "8_4", + "fp_port": 15, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "8_5", + "fp_port": 15, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "8_6", + "fp_port": 15, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "8_7", + "fp_port": 15, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "9_0", + "fp_port": 16, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "9_1", + "fp_port": 16, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "9_2", + "fp_port": 16, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "9_3", + "fp_port": 16, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "9_4", + "fp_port": 16, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "9_5", + "fp_port": 16, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "9_6", + "fp_port": 16, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "9_7", + "fp_port": 16, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "10_0", + "fp_port": 9, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "10_1", + "fp_port": 9, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "10_2", + "fp_port": 9, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "10_3", + "fp_port": 9, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "10_4", + "fp_port": 9, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "10_5", + "fp_port": 9, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "10_6", + "fp_port": 9, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "10_7", + "fp_port": 9, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "11_0", + "fp_port": 10, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "11_1", + "fp_port": 10, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "11_2", + "fp_port": 10, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "11_3", + "fp_port": 10, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "11_4", + "fp_port": 10, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "11_5", + "fp_port": 10, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "11_6", + "fp_port": 10, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "11_7", + "fp_port": 10, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "12_0", + "fp_port": 2, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "12_1", + "fp_port": 2, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "12_2", + "fp_port": 2, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "12_3", + "fp_port": 2, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "12_4", + "fp_port": 2, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "12_5", + "fp_port": 2, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "12_6", + "fp_port": 2, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "12_7", + "fp_port": 2, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "13_0", + "fp_port": 1, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "13_1", + "fp_port": 1, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "13_2", + "fp_port": 1, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "13_3", + "fp_port": 1, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "13_4", + "fp_port": 1, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "13_5", + "fp_port": 1, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "13_6", + "fp_port": 1, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "13_7", + "fp_port": 1, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "14_0", + "fp_port": 8, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "14_1", + "fp_port": 8, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "14_2", + "fp_port": 8, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "14_3", + "fp_port": 8, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "14_4", + "fp_port": 8, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "14_5", + "fp_port": 8, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "14_6", + "fp_port": 8, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "14_7", + "fp_port": 8, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "15_0", + "fp_port": 7, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "15_1", + "fp_port": 7, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "15_2", + "fp_port": 7, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "15_3", + "fp_port": 7, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "15_4", + "fp_port": 7, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "15_5", + "fp_port": 7, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "15_6", + "fp_port": 7, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "15_7", + "fp_port": 7, + "tx_inverse": false, + "offset": 8 + } + ] +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/pg_profile_lookup.ini b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/pg_profile_lookup.ini new file mode 100644 index 0000000000..1050abe886 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/pg_profile_lookup.ini @@ -0,0 +1,18 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1518 0 15680 1 9408 + 100000 5m 1518 0 34624 1 9408 + 200000 5m 1518 0 62368 1 9408 + 400000 5m 1518 0 117536 1 9408 + 10000 40m 1518 0 16928 1 9408 + 100000 40m 1518 0 38816 1 9408 + 200000 40m 1518 0 71904 1 9408 + 400000 40m 1518 0 135520 1 9408 + 10000 100m 1518 0 18848 1 9408 + 100000 100m 1518 0 46496 1 9408 + 200000 100m 1518 0 87168 1 9408 + 400000 100m 1518 0 166688 1 9408 + 10000 300m 1518 0 25184 1 9408 + 100000 300m 1518 0 72384 1 9408 + 200000 300m 1518 0 138112 1 9408 + 400000 300m 1518 0 268640 1 9408 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/port_config.ini b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/port_config.ini new file mode 100644 index 0000000000..a6930bbad9 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/port_config.ini @@ -0,0 +1,33 @@ +# name lanes alias index speed +Ethernet0 0,1,2,3 Eth1/1 1 400000 +Ethernet4 4,5,6,7 Eth2/1 2 400000 +Ethernet8 8,9,10,11 Eth3/1 3 400000 +Ethernet12 12,13,14,15 Eth4/1 4 400000 +Ethernet16 16,17,18,19 Eth5/1 5 400000 +Ethernet20 20,21,22,23 Eth6/1 6 400000 +Ethernet24 24,25,26,27 Eth7/1 7 400000 +Ethernet28 28,29,30,31 Eth8/1 8 400000 +Ethernet32 32,33,34,35 Eth9/1 9 400000 +Ethernet36 36,37,38,39 Eth10/1 10 400000 +Ethernet40 40,41,42,43 Eth11/1 11 400000 +Ethernet44 44,45,46,47 Eth12/1 12 400000 +Ethernet48 48,49,50,51 Eth13/1 13 400000 +Ethernet52 52,53,54,55 Eth14/1 14 400000 +Ethernet56 56,57,58,59 Eth15/1 15 400000 +Ethernet60 60,61,62,63 Eth16/1 16 400000 +Ethernet64 64,65,66,67 Eth17/1 17 400000 +Ethernet68 68,69,70,71 Eth18/1 18 400000 +Ethernet72 72,73,74,75 Eth19/1 19 400000 +Ethernet76 76,77,78,79 Eth20/1 20 400000 +Ethernet80 80,81,82,83 Eth21/1 21 400000 +Ethernet84 84,85,86,87 Eth22/1 22 400000 +Ethernet88 88,89,90,91 Eth23/1 23 400000 +Ethernet92 92,93,94,95 Eth24/1 24 400000 +Ethernet96 96,97,98,99 Eth25/1 25 400000 +Ethernet100 100,101,102,103 Eth26/1 26 400000 +Ethernet104 104,105,106,107 Eth27/1 27 400000 +Ethernet108 108,109,110,111 Eth28/1 28 400000 +Ethernet112 112,113,114,115 Eth29/1 29 400000 +Ethernet116 116,117,118,119 Eth30/1 30 400000 +Ethernet120 120,121,122,123 Eth31/1 31 400000 +Ethernet124 124,125,126,127 Eth32/1 32 400000 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/qos.json.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/qos.json.j2 new file mode 100644 index 0000000000..04def202c4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/qos.json.j2 @@ -0,0 +1,206 @@ +{% set port_names_list = [] %} +{% for port in PORT %} + {%- if port_names_list.append(port) %}{% endif %} +{% endfor %} +{% set port_names = port_names_list | join(',') -%} + + +{ + "TC_TO_QUEUE_MAP":{ + "AZURE":{ + "0":"0", + "1":"1", + "2":"2", + "3":"3", + "4":"4", + "5":"5", + "6":"6", + "7":"7" + } + }, + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "0" + } + }, + "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" + } + }, + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "1" + } + }, + "QUEUE": { +{% for port in port_names_list %} + "{{ port }}|3": { + "scheduler" : "scheduler.1", + "wred_profile" : "AZURE_LOSSLESS" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|4": { + "scheduler" : "scheduler.1", + "wred_profile" : "AZURE_LOSSLESS" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|0": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|1": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|2": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|5": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|6": { + "scheduler": "scheduler.0" + }{% if not loop.last %},{% endif %} + +{% endfor %} + }, + "PORT_QOS_MAP": { +{% for port in port_names_list %} + "{{ port }}": { + "tc_to_pg_map": "AZURE", + "pfc_to_pg_map": "AZURE", + "tc_to_queue_map": "AZURE", + "dscp_to_tc_map": "AZURE", + "pfc_to_queue_map": "AZURE", + "pfcwd_sw_enable" : "3,4", + "pfc_enable": "3,4" + }{% if not loop.last %},{% endif %} + +{% endfor %} + }, + "WRED_PROFILE": { + "AZURE_LOSSLESS" : { + "wred_green_enable" : "true", + "wred_yellow_enable" : "true", + "wred_red_enable" : "true", + "ecn" : "ecn_all", + "green_max_threshold" : "2097152", + "green_min_threshold" : "1048576", + "yellow_max_threshold" : "2097152", + "yellow_min_threshold" : "1048576", + "red_max_threshold" : "2097152", + "red_min_threshold" : "1048576", + "green_drop_probability" : "5", + "yellow_drop_probability": "5", + "red_drop_probability" : "5" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/sai.profile b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/sai.profile new file mode 100644 index 0000000000..2d4d56037f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/xdrv_config.json diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/xdrv_config.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/xdrv_config.json new file mode 100644 index 0000000000..48bc7542b8 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/xdrv_config.json @@ -0,0 +1,14 @@ +{ + "flush_reg_mem_access_file": false, + "qqm_number": 4, + "bm_size": 64, + "version": "0.0", + "reg_mem_access_file": false, + "device_list": [ + { + "ip": "localhost", + "id": 0, + "port": 49153 + } + ] +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/xlink_cfg.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/xlink_cfg.json new file mode 100644 index 0000000000..8f3ebab40b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-Q32x400G/xlink_cfg.json @@ -0,0 +1,144 @@ +{ + "driver": "xdrv_config.json", + "lanes_polarity": "lanes_polarity.json", + "version": "0.0", + "management_ports": [ + 136 + ], + "network_ports": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127 + ], + + "ucode": "ucode.json", + + "serdes_config": "serdes_config.json", + + "tables_config": "xsw_auto_table_properties.json" +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers.json.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers.json.j2 new file mode 100644 index 0000000000..b67cf577ab --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers.json.j2 @@ -0,0 +1,3 @@ +{%- set default_topo = 't1' %} +{%- include 'buffers_config.j2' %} + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_def.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_def.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_def.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_t0.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_t0.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_t0.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_t1.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_t1.j2 new file mode 100644 index 0000000000..04a291d2b4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/buffers_defaults_t1.j2 @@ -0,0 +1,62 @@ +{%- set default_cable = '5m' %} +{% set ingress_pool_size = '8493465' %} +{% set egress_pool_size = '8493465' %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"ingress_lossless_pool", + "xon": "18432", + "xoff": "40560", + "size":"41808", + "dynamic_th":"0" + }, + "ingress_lossy_profile": { + "pool":"ingress_lossless_pool", + "size":"3584", + "dynamic_th":"3" + }, + "egress_lossy_profile": { + "pool": "egress_lossless_pool", + "size": "1518", + "dynamic_th": "3" + } + }, +{%- endmacro %} + +{%- macro generate_pg_profils(port_names_list_active) %} + "BUFFER_PG": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0": { + "profile" : "ingress_lossy_profile" + }, + "{{ port }}|3-4": { + "profile" : "ingress_lossless_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + }, +{%- endmacro %} + +{%- macro generate_queue_buffers(port_names_list_active) %} + "BUFFER_QUEUE": { +{% for port in port_names_list_active.split(',') %} + "{{ port }}|0-7": { + "profile" : "egress_lossy_profile" + } + {% if not loop.last %},{% endif %} +{% endfor %} + } +{%- endmacro %} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/hwsku.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/hwsku.json new file mode 100644 index 0000000000..be90fde98b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/hwsku.json @@ -0,0 +1,132 @@ +{ + "interfaces": { + "Ethernet0": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet4": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet8": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet12": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet16": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet20": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet24": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet28": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet32": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet36": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet40": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet44": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet48": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet52": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet56": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet60": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet64": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet68": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet72": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet76": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet80": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet84": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet88": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet92": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet96": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet100": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet104": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet108": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet112": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet116": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet120": { + "default_brkout_mode": "8x100G", + "fec": "rs" + }, + "Ethernet124": { + "default_brkout_mode": "8x100G", + "fec": "rs" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/lanes_polarity.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/lanes_polarity.json new file mode 100644 index 0000000000..bcbe69e306 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/lanes_polarity.json @@ -0,0 +1,900 @@ +{ + "pn_list": [ + { + "rx_inverse": true, + "lane": "0_0", + "fp_port": 14, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "0_1", + "fp_port": 14, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "0_2", + "fp_port": 14, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "0_3", + "fp_port": 14, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "0_4", + "fp_port": 14, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "0_5", + "fp_port": 14, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "0_6", + "fp_port": 14, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "0_7", + "fp_port": 14, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "1_0", + "fp_port": 13, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "1_1", + "fp_port": 13, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "1_2", + "fp_port": 13, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "1_3", + "fp_port": 13, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "1_4", + "fp_port": 13, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "1_5", + "fp_port": 13, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "1_6", + "fp_port": 13, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "1_7", + "fp_port": 13, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "2_0", + "fp_port": 4, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "2_1", + "fp_port": 4, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "2_2", + "fp_port": 4, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "2_3", + "fp_port": 4, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "2_4", + "fp_port": 4, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "2_5", + "fp_port": 4, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "2_6", + "fp_port": 4, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "2_7", + "fp_port": 4, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "3_0", + "fp_port": 3, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "3_1", + "fp_port": 3, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "3_2", + "fp_port": 3, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "3_3", + "fp_port": 3, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "3_4", + "fp_port": 3, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "3_5", + "fp_port": 3, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "3_6", + "fp_port": 3, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "3_7", + "fp_port": 3, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "4_0", + "fp_port": 11, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "4_1", + "fp_port": 11, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "4_2", + "fp_port": 11, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "4_3", + "fp_port": 11, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "4_4", + "fp_port": 11, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "4_5", + "fp_port": 11, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "4_6", + "fp_port": 11, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "4_7", + "fp_port": 11, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "5_0", + "fp_port": 12, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "5_1", + "fp_port": 12, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "5_2", + "fp_port": 12, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "5_3", + "fp_port": 12, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "5_4", + "fp_port": 12, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "5_5", + "fp_port": 12, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "5_6", + "fp_port": 12, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "5_7", + "fp_port": 12, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "6_0", + "fp_port": 5, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "6_1", + "fp_port": 5, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "6_2", + "fp_port": 5, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "6_3", + "fp_port": 5, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "6_4", + "fp_port": 5, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "6_5", + "fp_port": 5, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "6_6", + "fp_port": 5, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "6_7", + "fp_port": 5, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "7_0", + "fp_port": 6, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "7_1", + "fp_port": 6, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "7_2", + "fp_port": 6, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "7_3", + "fp_port": 6, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "7_4", + "fp_port": 6, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "7_5", + "fp_port": 6, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "7_6", + "fp_port": 6, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "7_7", + "fp_port": 6, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "8_0", + "fp_port": 15, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "8_1", + "fp_port": 15, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "8_2", + "fp_port": 15, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "8_3", + "fp_port": 15, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "8_4", + "fp_port": 15, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "8_5", + "fp_port": 15, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "8_6", + "fp_port": 15, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "8_7", + "fp_port": 15, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "9_0", + "fp_port": 16, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "9_1", + "fp_port": 16, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "9_2", + "fp_port": 16, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "9_3", + "fp_port": 16, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": false, + "lane": "9_4", + "fp_port": 16, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "9_5", + "fp_port": 16, + "tx_inverse": true, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "9_6", + "fp_port": 16, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "9_7", + "fp_port": 16, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "10_0", + "fp_port": 9, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "10_1", + "fp_port": 9, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "10_2", + "fp_port": 9, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "10_3", + "fp_port": 9, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "10_4", + "fp_port": 9, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "10_5", + "fp_port": 9, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "10_6", + "fp_port": 9, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "10_7", + "fp_port": 9, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "11_0", + "fp_port": 10, + "tx_inverse": true, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "11_1", + "fp_port": 10, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "11_2", + "fp_port": 10, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "11_3", + "fp_port": 10, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": false, + "lane": "11_4", + "fp_port": 10, + "tx_inverse": true, + "offset": 5 + }, + { + "rx_inverse": false, + "lane": "11_5", + "fp_port": 10, + "tx_inverse": true, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "11_6", + "fp_port": 10, + "tx_inverse": true, + "offset": 7 + }, + { + "rx_inverse": false, + "lane": "11_7", + "fp_port": 10, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "12_0", + "fp_port": 2, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "12_1", + "fp_port": 2, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "12_2", + "fp_port": 2, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "12_3", + "fp_port": 2, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "12_4", + "fp_port": 2, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "12_5", + "fp_port": 2, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "12_6", + "fp_port": 2, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "12_7", + "fp_port": 2, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "13_0", + "fp_port": 1, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "13_1", + "fp_port": 1, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "13_2", + "fp_port": 1, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "13_3", + "fp_port": 1, + "tx_inverse": false, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "13_4", + "fp_port": 1, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "13_5", + "fp_port": 1, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "13_6", + "fp_port": 1, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": true, + "lane": "13_7", + "fp_port": 1, + "tx_inverse": false, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "14_0", + "fp_port": 8, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": true, + "lane": "14_1", + "fp_port": 8, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": true, + "lane": "14_2", + "fp_port": 8, + "tx_inverse": true, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "14_3", + "fp_port": 8, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "14_4", + "fp_port": 8, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "14_5", + "fp_port": 8, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": true, + "lane": "14_6", + "fp_port": 8, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "14_7", + "fp_port": 8, + "tx_inverse": true, + "offset": 8 + }, + { + "rx_inverse": true, + "lane": "15_0", + "fp_port": 7, + "tx_inverse": false, + "offset": 1 + }, + { + "rx_inverse": false, + "lane": "15_1", + "fp_port": 7, + "tx_inverse": false, + "offset": 2 + }, + { + "rx_inverse": false, + "lane": "15_2", + "fp_port": 7, + "tx_inverse": false, + "offset": 3 + }, + { + "rx_inverse": false, + "lane": "15_3", + "fp_port": 7, + "tx_inverse": true, + "offset": 4 + }, + { + "rx_inverse": true, + "lane": "15_4", + "fp_port": 7, + "tx_inverse": false, + "offset": 5 + }, + { + "rx_inverse": true, + "lane": "15_5", + "fp_port": 7, + "tx_inverse": false, + "offset": 6 + }, + { + "rx_inverse": false, + "lane": "15_6", + "fp_port": 7, + "tx_inverse": false, + "offset": 7 + }, + { + "rx_inverse": true, + "lane": "15_7", + "fp_port": 7, + "tx_inverse": false, + "offset": 8 + } + ] +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/pg_profile_lookup.ini b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/pg_profile_lookup.ini new file mode 100644 index 0000000000..1050abe886 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/pg_profile_lookup.ini @@ -0,0 +1,18 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold xon_offset + 10000 5m 1518 0 15680 1 9408 + 100000 5m 1518 0 34624 1 9408 + 200000 5m 1518 0 62368 1 9408 + 400000 5m 1518 0 117536 1 9408 + 10000 40m 1518 0 16928 1 9408 + 100000 40m 1518 0 38816 1 9408 + 200000 40m 1518 0 71904 1 9408 + 400000 40m 1518 0 135520 1 9408 + 10000 100m 1518 0 18848 1 9408 + 100000 100m 1518 0 46496 1 9408 + 200000 100m 1518 0 87168 1 9408 + 400000 100m 1518 0 166688 1 9408 + 10000 300m 1518 0 25184 1 9408 + 100000 300m 1518 0 72384 1 9408 + 200000 300m 1518 0 138112 1 9408 + 400000 300m 1518 0 268640 1 9408 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/port_config.ini b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/port_config.ini new file mode 100644 index 0000000000..9db14f140f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/port_config.ini @@ -0,0 +1,129 @@ +# name lanes alias index speed +Ethernet0 0 Eth1/1 1 100000 +Ethernet1 1 Eth1/2 1 100000 +Ethernet2 2 Eth1/3 1 100000 +Ethernet3 3 Eth1/4 1 100000 +Ethernet4 4 Eth2/1 2 100000 +Ethernet5 5 Eth2/2 2 100000 +Ethernet6 6 Eth2/3 2 100000 +Ethernet7 7 Eth2/4 2 100000 +Ethernet8 8 Eth3/1 3 100000 +Ethernet9 9 Eth3/2 3 100000 +Ethernet10 10 Eth3/3 3 100000 +Ethernet11 11 Eth3/4 3 100000 +Ethernet12 12 Eth4/1 4 100000 +Ethernet13 13 Eth4/2 4 100000 +Ethernet14 14 Eth4/3 4 100000 +Ethernet15 15 Eth4/4 4 100000 +Ethernet16 16 Eth5/1 5 100000 +Ethernet17 17 Eth5/2 5 100000 +Ethernet18 18 Eth5/3 5 100000 +Ethernet19 19 Eth5/4 5 100000 +Ethernet20 20 Eth6/1 6 100000 +Ethernet21 21 Eth6/2 6 100000 +Ethernet22 22 Eth6/3 6 100000 +Ethernet23 23 Eth6/4 6 100000 +Ethernet24 24 Eth7/1 7 100000 +Ethernet25 25 Eth7/2 7 100000 +Ethernet26 26 Eth7/3 7 100000 +Ethernet27 27 Eth7/4 7 100000 +Ethernet28 28 Eth8/1 8 100000 +Ethernet29 29 Eth8/2 8 100000 +Ethernet30 30 Eth8/3 8 100000 +Ethernet31 31 Eth8/4 8 100000 +Ethernet32 32 Eth9/1 9 100000 +Ethernet33 33 Eth9/2 9 100000 +Ethernet34 34 Eth9/3 9 100000 +Ethernet35 35 Eth9/4 9 100000 +Ethernet36 36 Eth10/1 10 100000 +Ethernet37 37 Eth10/2 10 100000 +Ethernet38 38 Eth10/3 10 100000 +Ethernet39 39 Eth10/4 10 100000 +Ethernet40 40 Eth11/1 11 100000 +Ethernet41 41 Eth11/2 11 100000 +Ethernet42 42 Eth11/3 11 100000 +Ethernet43 43 Eth11/4 11 100000 +Ethernet44 44 Eth12/1 12 100000 +Ethernet45 45 Eth12/2 12 100000 +Ethernet46 46 Eth12/3 12 100000 +Ethernet47 47 Eth12/4 12 100000 +Ethernet48 48 Eth13/1 13 100000 +Ethernet49 49 Eth13/2 13 100000 +Ethernet50 50 Eth13/3 13 100000 +Ethernet51 51 Eth13/4 13 100000 +Ethernet52 52 Eth14/1 14 100000 +Ethernet53 53 Eth14/2 14 100000 +Ethernet54 54 Eth14/3 14 100000 +Ethernet55 55 Eth14/4 14 100000 +Ethernet56 56 Eth15/1 15 100000 +Ethernet57 57 Eth15/2 15 100000 +Ethernet58 58 Eth15/3 15 100000 +Ethernet59 59 Eth15/4 15 100000 +Ethernet60 60 Eth16/1 16 100000 +Ethernet61 61 Eth16/2 16 100000 +Ethernet62 62 Eth16/3 16 100000 +Ethernet63 63 Eth16/4 16 100000 +Ethernet64 64 Eth17/1 17 100000 +Ethernet65 65 Eth17/2 17 100000 +Ethernet66 66 Eth17/3 17 100000 +Ethernet67 67 Eth17/4 17 100000 +Ethernet68 68 Eth18/1 18 100000 +Ethernet69 69 Eth18/2 18 100000 +Ethernet70 70 Eth18/3 18 100000 +Ethernet71 71 Eth18/4 18 100000 +Ethernet72 72 Eth19/1 19 100000 +Ethernet73 73 Eth19/2 19 100000 +Ethernet74 74 Eth19/3 19 100000 +Ethernet75 75 Eth19/4 19 100000 +Ethernet76 76 Eth20/1 20 100000 +Ethernet77 77 Eth20/2 20 100000 +Ethernet78 78 Eth20/3 20 100000 +Ethernet79 79 Eth20/4 20 100000 +Ethernet80 80 Eth21/1 21 100000 +Ethernet81 81 Eth21/2 21 100000 +Ethernet82 82 Eth21/3 21 100000 +Ethernet83 83 Eth21/4 21 100000 +Ethernet84 84 Eth22/1 22 100000 +Ethernet85 85 Eth22/2 22 100000 +Ethernet86 86 Eth22/3 22 100000 +Ethernet87 87 Eth22/4 22 100000 +Ethernet88 88 Eth23/1 23 100000 +Ethernet89 89 Eth23/2 23 100000 +Ethernet90 90 Eth23/3 23 100000 +Ethernet91 91 Eth23/4 23 100000 +Ethernet92 92 Eth24/1 24 100000 +Ethernet93 93 Eth24/2 24 100000 +Ethernet94 94 Eth24/3 24 100000 +Ethernet95 95 Eth24/4 24 100000 +Ethernet96 96 Eth25/1 25 100000 +Ethernet97 97 Eth25/2 25 100000 +Ethernet98 98 Eth25/3 25 100000 +Ethernet99 99 Eth25/4 25 100000 +Ethernet100 100 Eth26/1 26 100000 +Ethernet101 101 Eth26/2 26 100000 +Ethernet102 102 Eth26/3 26 100000 +Ethernet103 103 Eth26/4 26 100000 +Ethernet104 104 Eth27/1 27 100000 +Ethernet105 105 Eth27/2 27 100000 +Ethernet106 106 Eth27/3 27 100000 +Ethernet107 107 Eth27/4 27 100000 +Ethernet108 108 Eth28/1 28 100000 +Ethernet109 109 Eth28/2 28 100000 +Ethernet110 110 Eth28/3 28 100000 +Ethernet111 111 Eth28/4 28 100000 +Ethernet112 112 Eth29/1 29 100000 +Ethernet113 113 Eth29/2 29 100000 +Ethernet114 114 Eth29/3 29 100000 +Ethernet115 115 Eth29/4 29 100000 +Ethernet116 116 Eth30/1 30 100000 +Ethernet117 117 Eth30/2 30 100000 +Ethernet118 118 Eth30/3 30 100000 +Ethernet119 119 Eth30/4 30 100000 +Ethernet120 120 Eth31/1 31 100000 +Ethernet121 121 Eth31/2 31 100000 +Ethernet122 122 Eth31/3 31 100000 +Ethernet123 123 Eth31/4 31 100000 +Ethernet124 124 Eth32/1 32 100000 +Ethernet125 125 Eth32/2 32 100000 +Ethernet126 126 Eth32/3 32 100000 +Ethernet127 127 Eth32/4 32 100000 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/qos.json.j2 b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/qos.json.j2 new file mode 100644 index 0000000000..04def202c4 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/qos.json.j2 @@ -0,0 +1,206 @@ +{% set port_names_list = [] %} +{% for port in PORT %} + {%- if port_names_list.append(port) %}{% endif %} +{% endfor %} +{% set port_names = port_names_list | join(',') -%} + + +{ + "TC_TO_QUEUE_MAP":{ + "AZURE":{ + "0":"0", + "1":"1", + "2":"2", + "3":"3", + "4":"4", + "5":"5", + "6":"6", + "7":"7" + } + }, + "MAP_PFC_PRIORITY_TO_QUEUE": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "TC_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "0", + "2": "0", + "3": "3", + "4": "4", + "5": "0", + "6": "0", + "7": "0" + } + }, + "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" + } + }, + "PFC_PRIORITY_TO_PRIORITY_GROUP_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "SCHEDULER": { + "scheduler.0": { + "type" : "DWRR", + "weight": "1" + }, + "scheduler.1": { + "type" : "DWRR", + "weight": "1" + } + }, + "QUEUE": { +{% for port in port_names_list %} + "{{ port }}|3": { + "scheduler" : "scheduler.1", + "wred_profile" : "AZURE_LOSSLESS" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|4": { + "scheduler" : "scheduler.1", + "wred_profile" : "AZURE_LOSSLESS" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|0": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|1": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|2": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|5": { + "scheduler": "scheduler.0" + }, +{% endfor %} +{% for port in port_names_list %} + "{{ port }}|6": { + "scheduler": "scheduler.0" + }{% if not loop.last %},{% endif %} + +{% endfor %} + }, + "PORT_QOS_MAP": { +{% for port in port_names_list %} + "{{ port }}": { + "tc_to_pg_map": "AZURE", + "pfc_to_pg_map": "AZURE", + "tc_to_queue_map": "AZURE", + "dscp_to_tc_map": "AZURE", + "pfc_to_queue_map": "AZURE", + "pfcwd_sw_enable" : "3,4", + "pfc_enable": "3,4" + }{% if not loop.last %},{% endif %} + +{% endfor %} + }, + "WRED_PROFILE": { + "AZURE_LOSSLESS" : { + "wred_green_enable" : "true", + "wred_yellow_enable" : "true", + "wred_red_enable" : "true", + "ecn" : "ecn_all", + "green_max_threshold" : "2097152", + "green_min_threshold" : "1048576", + "yellow_max_threshold" : "2097152", + "yellow_min_threshold" : "1048576", + "red_max_threshold" : "2097152", + "red_min_threshold" : "1048576", + "green_drop_probability" : "5", + "yellow_drop_probability": "5", + "red_drop_probability" : "5" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/sai.profile b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/sai.profile new file mode 100644 index 0000000000..2d4d56037f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/sai.profile @@ -0,0 +1 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/hwsku/xdrv_config.json diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/xdrv_config.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/xdrv_config.json new file mode 100644 index 0000000000..48bc7542b8 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/xdrv_config.json @@ -0,0 +1,14 @@ +{ + "flush_reg_mem_access_file": false, + "qqm_number": 4, + "bm_size": 64, + "version": "0.0", + "reg_mem_access_file": false, + "device_list": [ + { + "ip": "localhost", + "id": 0, + "port": 49153 + } + ] +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/xlink_cfg.json b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/xlink_cfg.json new file mode 100644 index 0000000000..8f3ebab40b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/Accton-AS9647-32D-S128x100G/xlink_cfg.json @@ -0,0 +1,144 @@ +{ + "driver": "xdrv_config.json", + "lanes_polarity": "lanes_polarity.json", + "version": "0.0", + "management_ports": [ + 136 + ], + "network_ports": [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 13, + 14, + 15, + 16, + 17, + 18, + 19, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 47, + 48, + 49, + 50, + 51, + 52, + 53, + 54, + 55, + 56, + 57, + 58, + 59, + 60, + 61, + 62, + 63, + 64, + 65, + 66, + 67, + 68, + 69, + 70, + 71, + 72, + 73, + 74, + 75, + 76, + 77, + 78, + 79, + 80, + 81, + 82, + 83, + 84, + 85, + 86, + 87, + 88, + 89, + 90, + 91, + 92, + 93, + 94, + 95, + 96, + 97, + 98, + 99, + 100, + 101, + 102, + 103, + 104, + 105, + 106, + 107, + 108, + 109, + 110, + 111, + 112, + 113, + 114, + 115, + 116, + 117, + 118, + 119, + 120, + 121, + 122, + 123, + 124, + 125, + 126, + 127 + ], + + "ucode": "ucode.json", + + "serdes_config": "serdes_config.json", + + "tables_config": "xsw_auto_table_properties.json" +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/custom.json b/device/accton/x86_64-accton_as9647_32d-r0/custom.json new file mode 100644 index 0000000000..05b16cc640 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/custom.json @@ -0,0 +1,10 @@ +{ + "ASIC_SENSORS": { + "ASIC_SENSORS_POLLER_STATUS": { + "admin_status": "enable" + }, + "ASIC_SENSORS_POLLER_INTERVAL": { + "interval": "30" + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/default_sku b/device/accton/x86_64-accton_as9647_32d-r0/default_sku new file mode 100644 index 0000000000..487dd0b8ce --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/default_sku @@ -0,0 +1 @@ +Accton-AS9647-32D-Q32x400G t1 diff --git a/device/accton/x86_64-accton_as9647_32d-r0/pcie.yaml b/device/accton/x86_64-accton_as9647_32d-r0/pcie.yaml new file mode 100644 index 0000000000..414f82da0c --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/pcie.yaml @@ -0,0 +1,429 @@ +- bus: '00' + dev: '00' + fn: '0' + id: 09a2 + name: 'System peripheral: Intel Corporation Device 09a2 (rev 04)' +- bus: '00' + dev: '00' + fn: '1' + id: 09a4 + name: 'System peripheral: Intel Corporation Device 09a4 (rev 04)' +- bus: '00' + dev: '00' + fn: '2' + id: 09a3 + name: 'System peripheral: Intel Corporation Device 09a3 (rev 04)' +- bus: '00' + dev: '00' + fn: '3' + id: 09a5 + name: 'System peripheral: Intel Corporation Device 09a5 (rev 04)' +- bus: '00' + dev: '00' + fn: '4' + id: 0998 + name: 'Host bridge: Intel Corporation Device 0998' +- bus: '00' + dev: '01' + fn: '0' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '1' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '2' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '3' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '4' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '5' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '6' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '01' + fn: '7' + id: '0b00' + name: 'System peripheral: Intel Corporation Device 0b00' +- bus: '00' + dev: '02' + fn: '0' + id: 09a6 + name: 'System peripheral: Intel Corporation Device 09a6' +- bus: '00' + dev: '02' + fn: '1' + id: 09a7 + name: 'System peripheral: Intel Corporation Device 09a7' +- bus: '00' + dev: '02' + fn: '4' + id: '3456' + name: 'Non-Essential Instrumentation [1300]: Intel Corporation Device 3456 (rev + 01)' +- bus: '00' + dev: '06' + fn: '0' + id: 18da + name: 'PCI bridge: Intel Corporation Device 18da (rev 11)' +- bus: '00' + dev: 09 + fn: '0' + id: 18a4 + name: 'PCI bridge: Intel Corporation Device 18a4 (rev 11)' +- bus: '00' + dev: 0b + fn: '0' + id: 18a6 + name: 'PCI bridge: Intel Corporation Device 18a6 (rev 11)' +- bus: '00' + dev: 0e + fn: '0' + id: 18f2 + name: 'SATA controller: Intel Corporation Device 18f2 (rev 11)' +- bus: '00' + dev: 0f + fn: '0' + id: 18ac + name: 'System peripheral: Intel Corporation Device 18ac (rev 11)' +- bus: '00' + dev: '14' + fn: '0' + id: 18ad + name: 'PCI bridge: Intel Corporation Device 18ad (rev 11)' +- bus: '00' + dev: '18' + fn: '0' + id: 18d3 + name: 'Communication controller: Intel Corporation Device 18d3 (rev 11)' +- bus: '00' + dev: '18' + fn: '1' + id: 18d4 + name: 'Communication controller: Intel Corporation Device 18d4 (rev 11)' +- bus: '00' + dev: '18' + fn: '4' + id: 18d6 + name: 'Communication controller: Intel Corporation Device 18d6 (rev 11)' +- bus: '00' + dev: 1a + fn: '0' + id: 18d8 + name: 'Serial controller: Intel Corporation Device 18d8 (rev 11)' +- bus: '00' + dev: 1a + fn: '1' + id: 18d8 + name: 'Serial controller: Intel Corporation Device 18d8 (rev 11)' +- bus: '00' + dev: 1a + fn: '2' + id: 18d8 + name: 'Serial controller: Intel Corporation Device 18d8 (rev 11)' +- bus: '00' + dev: 1a + fn: '3' + id: 18d9 + name: 'Unassigned class [ff00]: Intel Corporation Device 18d9 (rev 11)' +- bus: '00' + dev: 1d + fn: '0' + id: 0998 + name: 'Host bridge: Intel Corporation Device 0998' +- bus: '00' + dev: 1e + fn: '0' + id: 18d0 + name: 'USB controller: Intel Corporation Device 18d0 (rev 11)' +- bus: '00' + dev: 1f + fn: '0' + id: 18dc + name: 'ISA bridge: Intel Corporation Device 18dc (rev 11)' +- bus: '00' + dev: 1f + fn: '4' + id: 18df + name: 'SMBus: Intel Corporation Device 18df (rev 11)' +- bus: '00' + dev: 1f + fn: '5' + id: 18e0 + name: 'Serial bus controller [0c80]: Intel Corporation Device 18e0 (rev 11)' +- bus: '01' + dev: '00' + fn: '0' + id: 18ee + name: 'Co-processor: Intel Corporation Device 18ee (rev 11)' +- bus: '02' + dev: '00' + fn: '0' + id: e001 + name: 'Ethernet controller: Altera Corporation Device e001 (rev 09)' +- bus: '03' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '04' + dev: '00' + fn: '0' + id: '1533' + name: 'Ethernet controller: Intel Corporation I210 Gigabit Network Connection (rev + 03)' +- bus: '14' + dev: '00' + fn: '0' + id: 09a2 + name: 'System peripheral: Intel Corporation Device 09a2 (rev 04)' +- bus: '14' + dev: '00' + fn: '1' + id: 09a4 + name: 'System peripheral: Intel Corporation Device 09a4 (rev 04)' +- bus: '14' + dev: '00' + fn: '2' + id: 09a3 + name: 'System peripheral: Intel Corporation Device 09a3 (rev 04)' +- bus: '14' + dev: '00' + fn: '3' + id: 09a5 + name: 'System peripheral: Intel Corporation Device 09a5 (rev 04)' +- bus: '14' + dev: '00' + fn: '4' + id: 0998 + name: 'Host bridge: Intel Corporation Device 0998' +- bus: '14' + dev: '02' + fn: '0' + id: 347a + name: 'PCI bridge: Intel Corporation Device 347a (rev 06)' +- bus: '14' + dev: '03' + fn: '0' + id: 347b + name: 'PCI bridge: Intel Corporation Device 347b (rev 06)' +- bus: '15' + dev: '00' + fn: '0' + id: '0002' + name: 'Non-VGA unclassified device: Device 1e6c:0002 (rev 01)' +- bus: '16' + dev: '00' + fn: '0' + id: '5013' + name: 'Non-Volatile memory controller: Phison Electronics Corporation PS5013 E13 + NVMe Controller (rev 01)' +- bus: f3 + dev: '00' + fn: '0' + id: 09a2 + name: 'System peripheral: Intel Corporation Device 09a2 (rev 04)' +- bus: f3 + dev: '00' + fn: '1' + id: 09a4 + name: 'System peripheral: Intel Corporation Device 09a4 (rev 04)' +- bus: f3 + dev: '00' + fn: '2' + id: 09a3 + name: 'System peripheral: Intel Corporation Device 09a3 (rev 04)' +- bus: f3 + dev: '00' + fn: '3' + id: 09a5 + name: 'System peripheral: Intel Corporation Device 09a5 (rev 04)' +- bus: f3 + dev: '00' + fn: '4' + id: 0998 + name: 'Host bridge: Intel Corporation Device 0998' +- bus: f3 + dev: '04' + fn: '0' + id: 18d1 + name: 'PCI bridge: Intel Corporation Device 18d1' +- bus: f4 + dev: '00' + fn: '0' + id: 124c + name: 'Ethernet controller: Intel Corporation Ethernet Connection E823-L for backplane' +- bus: f4 + dev: '00' + fn: '1' + id: 124c + name: 'Ethernet controller: Intel Corporation Ethernet Connection E823-L for backplane' +- bus: f4 + dev: '00' + fn: '2' + id: 124c + name: 'Ethernet controller: Intel Corporation Ethernet Connection E823-L for backplane' +- bus: f4 + dev: '00' + fn: '3' + id: 124c + name: 'Ethernet controller: Intel Corporation Ethernet Connection E823-L for backplane' +- bus: fe + dev: '00' + fn: '0' + id: '3450' + name: 'System peripheral: Intel Corporation Device 3450' +- bus: fe + dev: '00' + fn: '1' + id: '3451' + name: 'System peripheral: Intel Corporation Device 3451' +- bus: fe + dev: '00' + fn: '2' + id: '3452' + name: 'System peripheral: Intel Corporation Device 3452' +- bus: fe + dev: '00' + fn: '3' + id: 0998 + name: 'Host bridge: Intel Corporation Device 0998' +- bus: fe + dev: '00' + fn: '5' + id: '3455' + name: 'System peripheral: Intel Corporation Device 3455' +- bus: fe + dev: 0b + fn: '0' + id: '3448' + name: 'System peripheral: Intel Corporation Device 3448' +- bus: fe + dev: 0b + fn: '1' + id: '3448' + name: 'System peripheral: Intel Corporation Device 3448' +- bus: fe + dev: 0b + fn: '2' + id: 344b + name: 'System peripheral: Intel Corporation Device 344b' +- bus: fe + dev: 0c + fn: '0' + id: 344a + name: 'Performance counters: Intel Corporation Device 344a' +- bus: fe + dev: 1a + fn: '0' + id: '2880' + name: 'Performance counters: Intel Corporation Device 2880' +- bus: ff + dev: '00' + fn: '0' + id: 344c + name: 'System peripheral: Intel Corporation Device 344c' +- bus: ff + dev: '00' + fn: '1' + id: 344c + name: 'System peripheral: Intel Corporation Device 344c' +- bus: ff + dev: '00' + fn: '2' + id: 344c + name: 'System peripheral: Intel Corporation Device 344c' +- bus: ff + dev: '00' + fn: '3' + id: 344c + name: 'System peripheral: Intel Corporation Device 344c' +- bus: ff + dev: 0a + fn: '0' + id: 344d + name: 'System peripheral: Intel Corporation Device 344d' +- bus: ff + dev: 0a + fn: '1' + id: 344d + name: 'System peripheral: Intel Corporation Device 344d' +- bus: ff + dev: 0a + fn: '2' + id: 344d + name: 'System peripheral: Intel Corporation Device 344d' +- bus: ff + dev: 0a + fn: '3' + id: 344d + name: 'System peripheral: Intel Corporation Device 344d' +- bus: ff + dev: 1d + fn: '0' + id: 344f + name: 'System peripheral: Intel Corporation Device 344f' +- bus: ff + dev: 1d + fn: '1' + id: '3457' + name: 'System peripheral: Intel Corporation Device 3457' +- bus: ff + dev: 1e + fn: '0' + id: '3458' + name: 'System peripheral: Intel Corporation Device 3458 (rev 01)' +- bus: ff + dev: 1e + fn: '1' + id: '3459' + name: 'System peripheral: Intel Corporation Device 3459 (rev 01)' +- bus: ff + dev: 1e + fn: '2' + id: 345a + name: 'System peripheral: Intel Corporation Device 345a (rev 01)' +- bus: ff + dev: 1e + fn: '3' + id: 345b + name: 'System peripheral: Intel Corporation Device 345b (rev 01)' +- bus: ff + dev: 1e + fn: '4' + id: 345c + name: 'System peripheral: Intel Corporation Device 345c (rev 01)' +- bus: ff + dev: 1e + fn: '5' + id: 345d + name: 'System peripheral: Intel Corporation Device 345d (rev 01)' +- bus: ff + dev: 1e + fn: '6' + id: 345e + name: 'System peripheral: Intel Corporation Device 345e (rev 01)' +- bus: ff + dev: 1e + fn: '7' + id: 345f + name: 'System peripheral: Intel Corporation Device 345f (rev 01)' diff --git a/device/accton/x86_64-accton_as9647_32d-r0/platform.json b/device/accton/x86_64-accton_as9647_32d-r0/platform.json new file mode 100644 index 0000000000..6251e82de5 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/platform.json @@ -0,0 +1,1037 @@ +{ + "chassis": { + "name": "Accton-AS9647-32D-Q32x400G", + "components": [ + { + "name": "BIOS" + }, + { + "name": "ONIE" + }, + { + "name": "CPLD1" + }, + { + "name": "CPLD2" + }, + { + "name": "CPLD3" + }, + { + "name": "CPLD4" + } + ], + "psus": [ + { + "name": "PSU-1", + "status_led": { + "controllable": true, + "colors": ["off", "green", "amber"] + }, + "voltage_high_threshold" : false, + "voltage_low_threshold" : false, + "fans": [ + { + "name": "PSU 1 fan 0", + "status_led": { + "controllable": true, + "colors": ["off", "green", "amber"] + }, + "speed": { + "controllable": false + } + } + ] + }, + { + "name": "PSU-2", + "status_led": { + "controllable": true, + "colors": ["off", "green", "amber"] + }, + "voltage_high_threshold" : false, + "voltage_low_threshold" : false, + "fans": [ + { + "name": "PSU 2 fan 0", + "status_led": { + "controllable": true, + "colors": ["off", "green", "amber"] + }, + "speed": { + "controllable": false + } + } + ] + } + ], + "fans": [ + { + "name": "FanTray 0 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 0 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 1 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 1 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 2 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 2 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 3 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 3 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 4 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 4 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 5 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 5 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "thermals": [ + { + "name": "PCB VDD_Core", + "controllable": false + }, + { + "name": "PCB FP Hotspot", + "controllable": false + }, + { + "name": "PCB Top Front", + "controllable": false + }, + { + "name": "PCB Bottom Front", + "controllable": false + }, + { + "name": "PCB Bottom Rear", + "controllable": false + }, + { + "name": "PCB OCXO", + "controllable": false + }, + { + "name": "PCB ASIC", + "controllable": false + }, + { + "name": "PCB Top Rear", + "controllable": false + }, + { + "name": "ASIC Temp 1", + "controllable": false + }, + { + "name": "ASIC Temp 2", + "controllable": false + }, + { + "name": "ASIC Temp 3", + "controllable": false + }, + { + "name": "CPU Temp", + "controllable": false + } + ], + "fan_drawers": [ + { + "name": "FanTray 0", + "fans": [ + { + "name": "FanTray 0 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 0 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 1", + "fans": [ + { + "name": "FanTray 1 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 1 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 2", + "fans": [ + { + "name": "FanTray 2 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 2 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 3", + "fans": [ + { + "name": "FanTray 3 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 3 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 4", + "fans": [ + { + "name": "FanTray 4 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 4 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 5", + "fans": [ + { + "name": "FanTray 5 fan 0", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + }, + { + "name": "FanTray 5 fan 1", + "speed": { + "controllable": true, + "delay": 10, + "minimum": 50, + "maximum": 100 + }, + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "status_led": { + "controllable": true, + "colors": ["off", "green", "red"] + } + } + ], + "sfps": [ + { + "name": "Ethernet0", + "thermals": [ + { + "name": "QSFP 1", + "controllable": false + } + ] + }, + { + "name": "Ethernet4", + "thermals": [ + { + "name": "QSFP 2", + "controllable": false + } + ] + }, + { + "name": "Ethernet8", + "thermals": [ + { + "name": "QSFP 3", + "controllable": false + } + ] + }, + { + "name": "Ethernet12", + "thermals": [ + { + "name": "QSFP 4", + "controllable": false + } + ] + }, + { + "name": "Ethernet16", + "thermals": [ + { + "name": "QSFP 5", + "controllable": false + } + ] + }, + { + "name": "Ethernet20", + "thermals": [ + { + "name": "QSFP 6", + "controllable": false + } + ] + }, + { + "name": "Ethernet24", + "thermals": [ + { + "name": "QSFP 7", + "controllable": false + } + ] + }, + { + "name": "Ethernet28", + "thermals": [ + { + "name": "QSFP 8", + "controllable": false + } + ] + }, + { + "name": "Ethernet32", + "thermals": [ + { + "name": "QSFP 9", + "controllable": false + } + ] + }, + { + "name": "Ethernet36", + "thermals": [ + { + "name": "QSFP 10", + "controllable": false + } + ] + }, + { + "name": "Ethernet40", + "thermals": [ + { + "name": "QSFP 11", + "controllable": false + } + ] + }, + { + "name": "Ethernet44", + "thermals": [ + { + "name": "QSFP 12", + "controllable": false + } + ] + }, + { + "name": "Ethernet48", + "thermals": [ + { + "name": "QSFP 13", + "controllable": false + } + ] + }, + { + "name": "Ethernet52", + "thermals": [ + { + "name": "QSFP 14", + "controllable": false + } + ] + }, + { + "name": "Ethernet56", + "thermals": [ + { + "name": "QSFP 15", + "controllable": false + } + ] + }, + { + "name": "Ethernet60", + "thermals": [ + { + "name": "QSFP 16", + "controllable": false + } + ] + }, + { + "name": "Ethernet64", + "thermals": [ + { + "name": "QSFP 17", + "controllable": false + } + ] + }, + { + "name": "Ethernet68", + "thermals": [ + { + "name": "QSFP 18", + "controllable": false + } + ] + }, + { + "name": "Ethernet72", + "thermals": [ + { + "name": "QSFP 19", + "controllable": false + } + ] + }, + { + "name": "Ethernet76", + "thermals": [ + { + "name": "QSFP 20", + "controllable": false + } + ] + }, + { + "name": "Ethernet80", + "thermals": [ + { + "name": "QSFP 21", + "controllable": false + } + ] + }, + { + "name": "Ethernet84", + "thermals": [ + { + "name": "QSFP 22", + "controllable": false + } + ] + }, + { + "name": "Ethernet88", + "thermals": [ + { + "name": "QSFP 23", + "controllable": false + } + ] + }, + { + "name": "Ethernet92", + "thermals": [ + { + "name": "QSFP 24", + "controllable": false + } + ] + }, + { + "name": "Ethernet96", + "thermals": [ + { + "name": "QSFP 25", + "controllable": false + } + ] + }, + { + "name": "Ethernet100", + "thermals": [ + { + "name": "QSFP 26", + "controllable": false + } + ] + }, + { + "name": "Ethernet104", + "thermals": [ + { + "name": "QSFP 27", + "controllable": false + } + ] + }, + { + "name": "Ethernet108", + "thermals": [ + { + "name": "QSFP 28", + "controllable": false + } + ] + }, + { + "name": "Ethernet112", + "thermals": [ + { + "name": "QSFP 29", + "controllable": false + } + ] + }, + { + "name": "Ethernet116", + "thermals": [ + { + "name": "QSFP 30", + "controllable": false + } + ] + }, + { + "name": "Ethernet120", + "thermals": [ + { + "name": "QSFP 31", + "controllable": false + } + ] + }, + { + "name": "Ethernet124", + "thermals": [ + { + "name": "QSFP 32", + "controllable": false + } + ] + } + ] + }, + "interfaces": { + "Ethernet0": { + "index": "1,1,1,1,2,2,2,2", + "lanes": "0,1,2,3,4,5,6,7", + "breakout_modes": { + "2x400G": ["Eth1/1", "Eth2/1"], + "4x200G": ["Eth1/1", "Eth1/2", "Eth2/1", "Eth2/2"], + "8x100G": ["Eth1/1", "Eth1/2", "Eth1/3", "Eth1/4", "Eth2/1", "Eth2/2", "Eth2/3", "Eth2/4"], + "1x400G": ["Eth1/1"], + "2x200G": ["Eth1/1", "Eth2/1"], + "4x100G": ["Eth1/1", "Eth1/2", "Eth2/1", "Eth2/2"], + "8x50G": ["Eth1/1", "Eth1/2", "Eth1/3", "Eth1/4", "Eth2/1", "Eth2/2", "Eth2/3", "Eth2/4"], + "2x100G": ["Eth1/1", "Eth2/1"], + "8x25G": ["Eth1/1", "Eth1/2", "Eth1/3", "Eth1/4", "Eth2/1", "Eth2/2", "Eth2/3", "Eth2/4"], + "8x10G": ["Eth1/1", "Eth1/2", "Eth1/3", "Eth1/4", "Eth2/1", "Eth2/2", "Eth2/3", "Eth2/4"] + } + }, + "Ethernet8": { + "index": "3,3,3,3,4,4,4,4", + "lanes": "8,9,10,11,12,13,14,15", + "breakout_modes": { + "2x400G": ["Eth3/1", "Eth4/1"], + "4x200G": ["Eth3/1", "Eth3/2", "Eth4/1", "Eth4/2"], + "8x100G": ["Eth3/1", "Eth3/2", "Eth3/3", "Eth3/4", "Eth4/1", "Eth4/2", "Eth4/3", "Eth4/4"], + "1x400G": ["Eth3/1"], + "2x200G": ["Eth3/1", "Eth4/1"], + "4x100G": ["Eth3/1", "Eth3/2", "Eth4/1", "Eth4/2"], + "8x50G": ["Eth3/1", "Eth3/2", "Eth3/3", "Eth3/4", "Eth4/1", "Eth4/2", "Eth4/3", "Eth4/4"], + "2x100G": ["Eth3/1", "Eth4/1"], + "8x25G": ["Eth3/1", "Eth3/2", "Eth3/3", "Eth3/4", "Eth4/1", "Eth4/2", "Eth4/3", "Eth4/4"], + "8x10G": ["Eth3/1", "Eth3/2", "Eth3/3", "Eth3/4", "Eth4/1", "Eth4/2", "Eth4/3", "Eth4/4"] + } + }, + "Ethernet16": { + "index": "5,5,5,5,6,6,6,6", + "lanes": "16,17,18,19,20,21,22,23", + "breakout_modes": { + "2x400G": ["Eth5/1", "Eth6/1"], + "4x200G": ["Eth5/1", "Eth5/2", "Eth6/1", "Eth6/2"], + "8x100G": ["Eth5/1", "Eth5/2", "Eth5/3", "Eth5/4", "Eth6/1", "Eth6/2", "Eth6/3", "Eth6/4"], + "1x400G": ["Eth5/1"], + "2x200G": ["Eth5/1", "Eth6/1"], + "4x100G": ["Eth5/1", "Eth5/2", "Eth6/1", "Eth6/2"], + "8x50G": ["Eth5/1", "Eth5/2", "Eth5/3", "Eth5/4", "Eth6/1", "Eth6/2", "Eth6/3", "Eth6/4"], + "2x100G": ["Eth5/1", "Eth6/1"], + "8x25G": ["Eth5/1", "Eth5/2", "Eth5/3", "Eth5/4", "Eth6/1", "Eth6/2", "Eth6/3", "Eth6/4"], + "8x10G": ["Eth5/1", "Eth5/2", "Eth5/3", "Eth5/4", "Eth6/1", "Eth6/2", "Eth6/3", "Eth6/4"] + } + }, + "Ethernet24": { + "index": "7,7,7,7,8,8,8,8", + "lanes": "24,25,26,27,28,29,30,31", + "breakout_modes": { + "2x400G": ["Eth7/1", "Eth8/1"], + "4x200G": ["Eth7/1", "Eth7/2", "Eth8/1", "Eth8/2"], + "8x100G": ["Eth7/1", "Eth7/2", "Eth7/3", "Eth7/4", "Eth8/1", "Eth8/2", "Eth8/3", "Eth8/4"], + "1x400G": ["Eth7/1"], + "2x200G": ["Eth7/1", "Eth8/1"], + "4x100G": ["Eth7/1", "Eth7/2", "Eth8/1", "Eth8/2"], + "8x50G": ["Eth7/1", "Eth7/2", "Eth7/3", "Eth7/4", "Eth8/1", "Eth8/2", "Eth8/3", "Eth8/4"], + "2x100G": ["Eth7/1", "Eth8/1"], + "8x25G": ["Eth7/1", "Eth7/2", "Eth7/3", "Eth7/4", "Eth8/1", "Eth8/2", "Eth8/3", "Eth8/4"], + "8x10G": ["Eth7/1", "Eth7/2", "Eth7/3", "Eth7/4", "Eth8/1", "Eth8/2", "Eth8/3", "Eth8/4"] + } + }, + "Ethernet32": { + "index": "9,9,9,9,10,10,10,10", + "lanes": "32,33,34,35,36,37,38,39", + "breakout_modes": { + "2x400G": ["Eth9/1", "Eth10/1"], + "4x200G": ["Eth9/1", "Eth9/2", "Eth10/1", "Eth10/2"], + "8x100G": ["Eth9/1", "Eth9/2", "Eth9/3", "Eth9/4", "Eth10/1", "Eth10/2", "Eth10/3", "Eth10/4"], + "1x400G": ["Eth9/1"], + "2x200G": ["Eth9/1", "Eth10/1"], + "4x100G": ["Eth9/1", "Eth9/2", "Eth10/1", "Eth10/2"], + "8x50G": ["Eth9/1", "Eth9/2", "Eth9/3", "Eth9/4", "Eth10/1", "Eth10/2", "Eth10/3", "Eth10/4"], + "2x100G": ["Eth9/1", "Eth10/1"], + "8x25G": ["Eth9/1", "Eth9/2", "Eth9/3", "Eth9/4", "Eth10/1", "Eth10/2", "Eth10/3", "Eth10/4"], + "8x10G": ["Eth9/1", "Eth9/2", "Eth9/3", "Eth9/4", "Eth10/1", "Eth10/2", "Eth10/3", "Eth10/4"] + } + }, + "Ethernet40": { + "index": "11,11,11,11,12,12,12,12", + "lanes": "40,41,42,43,44,45,46,47", + "breakout_modes": { + "2x400G": ["Eth11/1", "Eth12/1"], + "4x200G": ["Eth11/1", "Eth11/2", "Eth12/1", "Eth12/2"], + "8x100G": ["Eth11/1", "Eth11/2", "Eth11/3", "Eth11/4", "Eth12/1", "Eth12/2", "Eth12/3", "Eth12/4"], + "1x400G": ["Eth11/1"], + "2x200G": ["Eth11/1", "Eth12/1"], + "4x100G": ["Eth11/1", "Eth11/2", "Eth12/1", "Eth12/2"], + "8x50G": ["Eth11/1", "Eth11/2", "Eth11/3", "Eth11/4", "Eth12/1", "Eth12/2", "Eth12/3", "Eth12/4"], + "2x100G": ["Eth11/1", "Eth12/1"], + "8x25G": ["Eth11/1", "Eth11/2", "Eth11/3", "Eth11/4", "Eth12/1", "Eth12/2", "Eth12/3", "Eth12/4"], + "8x10G": ["Eth11/1", "Eth11/2", "Eth11/3", "Eth11/4", "Eth12/1", "Eth12/2", "Eth12/3", "Eth12/4"] + } + }, + "Ethernet48": { + "index": "13,13,13,13,14,14,14,14", + "lanes": "48,49,50,51,52,53,54,55", + "breakout_modes": { + "2x400G": ["Eth13/1", "Eth14/1"], + "4x200G": ["Eth13/1", "Eth13/2", "Eth14/1", "Eth14/2"], + "8x100G": ["Eth13/1", "Eth13/2", "Eth13/3", "Eth13/4", "Eth14/1", "Eth14/2", "Eth14/3", "Eth14/4"], + "1x400G": ["Eth13/1"], + "2x200G": ["Eth13/1", "Eth14/1"], + "4x100G": ["Eth13/1", "Eth13/2", "Eth14/1", "Eth14/2"], + "8x50G": ["Eth13/1", "Eth13/2", "Eth13/3", "Eth13/4", "Eth14/1", "Eth14/2", "Eth14/3", "Eth14/4"], + "2x100G": ["Eth13/1", "Eth14/1"], + "8x25G": ["Eth13/1", "Eth13/2", "Eth13/3", "Eth13/4", "Eth14/1", "Eth14/2", "Eth14/3", "Eth14/4"], + "8x10G": ["Eth13/1", "Eth13/2", "Eth13/3", "Eth13/4", "Eth14/1", "Eth14/2", "Eth14/3", "Eth14/4"] + } + }, + "Ethernet56": { + "index": "15,15,15,15,16,16,16,16", + "lanes": "56,57,58,59,60,61,62,63", + "breakout_modes": { + "2x400G": ["Eth15/1", "Eth16/1"], + "4x200G": ["Eth15/1", "Eth15/2", "Eth16/1", "Eth16/2"], + "8x100G": ["Eth15/1", "Eth15/2", "Eth15/3", "Eth15/4", "Eth16/1", "Eth16/2", "Eth16/3", "Eth16/4"], + "1x400G": ["Eth15/1"], + "2x200G": ["Eth15/1", "Eth16/1"], + "4x100G": ["Eth15/1", "Eth15/2", "Eth16/1", "Eth16/2"], + "8x50G": ["Eth15/1", "Eth15/2", "Eth15/3", "Eth15/4", "Eth16/1", "Eth16/2", "Eth16/3", "Eth16/4"], + "2x100G": ["Eth15/1", "Eth16/1"], + "8x25G": ["Eth15/1", "Eth15/2", "Eth15/3", "Eth15/4", "Eth16/1", "Eth16/2", "Eth16/3", "Eth16/4"], + "8x10G": ["Eth15/1", "Eth15/2", "Eth15/3", "Eth15/4", "Eth16/1", "Eth16/2", "Eth16/3", "Eth16/4"] + } + }, + "Ethernet64": { + "index": "17,17,17,17,18,18,18,18", + "lanes": "64,65,66,67,68,69,70,71", + "breakout_modes": { + "2x400G": ["Eth17/1", "Eth18/1"], + "4x200G": ["Eth17/1", "Eth17/2", "Eth18/1", "Eth18/2"], + "8x100G": ["Eth17/1", "Eth17/2", "Eth17/3", "Eth17/4", "Eth18/1", "Eth18/2", "Eth18/3", "Eth18/4"], + "1x400G": ["Eth17/1"], + "2x200G": ["Eth17/1", "Eth18/1"], + "4x100G": ["Eth17/1", "Eth17/2", "Eth18/1", "Eth18/2"], + "8x50G": ["Eth17/1", "Eth17/2", "Eth17/3", "Eth17/4", "Eth18/1", "Eth18/2", "Eth18/3", "Eth18/4"], + "2x100G": ["Eth17/1", "Eth18/1"], + "8x25G": ["Eth17/1", "Eth17/2", "Eth17/3", "Eth17/4", "Eth18/1", "Eth18/2", "Eth18/3", "Eth18/4"], + "8x10G": ["Eth17/1", "Eth17/2", "Eth17/3", "Eth17/4", "Eth18/1", "Eth18/2", "Eth18/3", "Eth18/4"] + } + }, + "Ethernet72": { + "index": "19,19,19,19,20,20,20,20", + "lanes": "72,73,74,75,76,77,78,79", + "breakout_modes": { + "2x400G": ["Eth19/1", "Eth20/1"], + "4x200G": ["Eth19/1", "Eth19/2", "Eth20/1", "Eth20/2"], + "8x100G": ["Eth19/1", "Eth19/2", "Eth19/3", "Eth19/4", "Eth20/1", "Eth20/2", "Eth20/3", "Eth20/4"], + "1x400G": ["Eth19/1"], + "2x200G": ["Eth19/1", "Eth20/1"], + "4x100G": ["Eth19/1", "Eth19/2", "Eth20/1", "Eth20/2"], + "8x50G": ["Eth19/1", "Eth19/2", "Eth19/3", "Eth19/4", "Eth20/1", "Eth20/2", "Eth20/3", "Eth20/4"], + "2x100G": ["Eth19/1", "Eth20/1"], + "8x25G": ["Eth19/1", "Eth19/2", "Eth19/3", "Eth19/4", "Eth20/1", "Eth20/2", "Eth20/3", "Eth20/4"], + "8x10G": ["Eth19/1", "Eth19/2", "Eth19/3", "Eth19/4", "Eth20/1", "Eth20/2", "Eth20/3", "Eth20/4"] + } + }, + "Ethernet80": { + "index": "21,21,21,21,22,22,22,22", + "lanes": "80,81,82,83,84,85,86,87", + "breakout_modes": { + "2x400G": ["Eth21/1", "Eth22/1"], + "4x200G": ["Eth21/1", "Eth21/2", "Eth22/1", "Eth22/2"], + "8x100G": ["Eth21/1", "Eth21/2", "Eth21/3", "Eth21/4", "Eth22/1", "Eth22/2", "Eth22/3", "Eth22/4"], + "1x400G": ["Eth21/1"], + "2x200G": ["Eth21/1", "Eth22/1"], + "4x100G": ["Eth21/1", "Eth21/2", "Eth22/1", "Eth22/2"], + "8x50G": ["Eth21/1", "Eth21/2", "Eth21/3", "Eth21/4", "Eth22/1", "Eth22/2", "Eth22/3", "Eth22/4"], + "2x100G": ["Eth21/1", "Eth22/1"], + "8x25G": ["Eth21/1", "Eth21/2", "Eth21/3", "Eth21/4", "Eth22/1", "Eth22/2", "Eth22/3", "Eth22/4"], + "8x10G": ["Eth21/1", "Eth21/2", "Eth21/3", "Eth21/4", "Eth22/1", "Eth22/2", "Eth22/3", "Eth22/4"] + } + }, + "Ethernet88": { + "index": "23,23,23,23,24,24,24,24", + "lanes": "88,89,90,91,92,93,94,95", + "breakout_modes": { + "2x400G": ["Eth23/1", "Eth24/1"], + "4x200G": ["Eth23/1", "Eth23/2", "Eth24/1", "Eth24/2"], + "8x100G": ["Eth23/1", "Eth23/2", "Eth23/3", "Eth23/4", "Eth24/1", "Eth24/2", "Eth24/3", "Eth24/4"], + "1x400G": ["Eth23/1"], + "2x200G": ["Eth23/1", "Eth24/1"], + "4x100G": ["Eth23/1", "Eth23/2", "Eth24/1", "Eth24/2"], + "8x50G": ["Eth23/1", "Eth23/2", "Eth23/3", "Eth23/4", "Eth24/1", "Eth24/2", "Eth24/3", "Eth24/4"], + "2x100G": ["Eth23/1", "Eth24/1"], + "8x25G": ["Eth23/1", "Eth23/2", "Eth23/3", "Eth23/4", "Eth24/1", "Eth24/2", "Eth24/3", "Eth24/4"], + "8x10G": ["Eth23/1", "Eth23/2", "Eth23/3", "Eth23/4", "Eth24/1", "Eth24/2", "Eth24/3", "Eth24/4"] + } + }, + "Ethernet96": { + "index": "25,25,25,25,26,26,26,26", + "lanes": "96,97,98,99,100,101,102,103", + "breakout_modes": { + "2x400G": ["Eth25/1", "Eth26/1"], + "4x200G": ["Eth25/1", "Eth25/2", "Eth26/1", "Eth26/2"], + "8x100G": ["Eth25/1", "Eth25/2", "Eth25/3", "Eth25/4", "Eth26/1", "Eth26/2", "Eth26/3", "Eth26/4"], + "1x400G": ["Eth25/1"], + "2x200G": ["Eth25/1", "Eth26/1"], + "4x100G": ["Eth25/1", "Eth25/2", "Eth26/1", "Eth26/2"], + "8x50G": ["Eth25/1", "Eth25/2", "Eth25/3", "Eth25/4", "Eth26/1", "Eth26/2", "Eth26/3", "Eth26/4"], + "2x100G": ["Eth25/1", "Eth26/1"], + "8x25G": ["Eth25/1", "Eth25/2", "Eth25/3", "Eth25/4", "Eth26/1", "Eth26/2", "Eth26/3", "Eth26/4"], + "8x10G": ["Eth25/1", "Eth25/2", "Eth25/3", "Eth25/4", "Eth26/1", "Eth26/2", "Eth26/3", "Eth26/4"] + } + }, + "Ethernet104": { + "index": "27,27,27,27,28,28,28,28", + "lanes": "104,105,106,107,108,109,110,111", + "breakout_modes": { + "2x400G": ["Eth27/1", "Eth28/1"], + "4x200G": ["Eth27/1", "Eth27/2", "Eth28/1", "Eth28/2"], + "8x100G": ["Eth27/1", "Eth27/2", "Eth27/3", "Eth27/4", "Eth28/1", "Eth28/2", "Eth28/3", "Eth28/4"], + "1x400G": ["Eth27/1"], + "2x200G": ["Eth27/1", "Eth28/1"], + "4x100G": ["Eth27/1", "Eth27/2", "Eth28/1", "Eth28/2"], + "8x50G": ["Eth27/1", "Eth27/2", "Eth27/3", "Eth27/4", "Eth28/1", "Eth28/2", "Eth28/3", "Eth28/4"], + "2x100G": ["Eth27/1", "Eth28/1"], + "8x25G": ["Eth27/1", "Eth27/2", "Eth27/3", "Eth27/4", "Eth28/1", "Eth28/2", "Eth28/3", "Eth28/4"], + "8x10G": ["Eth27/1", "Eth27/2", "Eth27/3", "Eth27/4", "Eth28/1", "Eth28/2", "Eth28/3", "Eth28/4"] + } + }, + "Ethernet112": { + "index": "29,29,29,29,30,30,30,30", + "lanes": "112,113,114,115,116,117,118,119", + "breakout_modes": { + "2x400G": ["Eth29/1", "Eth30/1"], + "4x200G": ["Eth29/1", "Eth29/2", "Eth30/1", "Eth30/2"], + "8x100G": ["Eth29/1", "Eth29/2", "Eth29/3", "Eth29/4", "Eth30/1", "Eth30/2", "Eth30/3", "Eth30/4"], + "1x400G": ["Eth29/1"], + "2x200G": ["Eth29/1", "Eth30/1"], + "4x100G": ["Eth29/1", "Eth29/2", "Eth30/1", "Eth30/2"], + "8x50G": ["Eth29/1", "Eth29/2", "Eth29/3", "Eth29/4", "Eth30/1", "Eth30/2", "Eth30/3", "Eth30/4"], + "2x100G": ["Eth29/1", "Eth30/1"], + "8x25G": ["Eth29/1", "Eth29/2", "Eth29/3", "Eth29/4", "Eth30/1", "Eth30/2", "Eth30/3", "Eth30/4"], + "8x10G": ["Eth29/1", "Eth29/2", "Eth29/3", "Eth29/4", "Eth30/1", "Eth30/2", "Eth30/3", "Eth30/4"] + } + }, + "Ethernet120": { + "index": "31,31,31,31,32,32,32,32", + "lanes": "120,121,122,123,124,125,126,127", + "breakout_modes": { + "2x400G": ["Eth31/1", "Eth32/1"], + "4x200G": ["Eth31/1", "Eth31/2", "Eth32/1", "Eth32/2"], + "8x100G": ["Eth31/1", "Eth31/2", "Eth31/3", "Eth31/4", "Eth32/1", "Eth32/2", "Eth32/3", "Eth32/4"], + "1x400G": ["Eth31/1"], + "2x200G": ["Eth31/1", "Eth32/1"], + "4x100G": ["Eth31/1", "Eth31/2", "Eth32/1", "Eth32/2"], + "8x50G": ["Eth31/1", "Eth31/2", "Eth31/3", "Eth31/4", "Eth32/1", "Eth32/2", "Eth32/3", "Eth32/4"], + "2x100G": ["Eth31/1", "Eth32/1"], + "8x25G": ["Eth31/1", "Eth31/2", "Eth31/3", "Eth31/4", "Eth32/1", "Eth32/2", "Eth32/3", "Eth32/4"], + "8x10G": ["Eth31/1", "Eth31/2", "Eth31/3", "Eth31/4", "Eth32/1", "Eth32/2", "Eth32/3", "Eth32/4"] + } + } + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/platform_asic b/device/accton/x86_64-accton_as9647_32d-r0/platform_asic new file mode 100644 index 0000000000..51a9cef596 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/platform_asic @@ -0,0 +1 @@ +xsight diff --git a/device/accton/x86_64-accton_as9647_32d-r0/plugins/led_control.py b/device/accton/x86_64-accton_as9647_32d-r0/plugins/led_control.py new file mode 100644 index 0000000000..e3cecb24f5 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/plugins/led_control.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# led_control.py +# +# Platform-specific LED control functionality for SONiC +# + +try: + from sonic_led.led_control_base import LedControlBase +except ImportError as e: + raise ImportError(str(e) + " - required module not found") + +class LedControl(LedControlBase): + """Platform specific LED control class""" + + def __init__(self): + pass + + def port_link_state_change(self, portname, state): + pass diff --git a/device/accton/x86_64-accton_as9647_32d-r0/pmon_daemon_control.json b/device/accton/x86_64-accton_as9647_32d-r0/pmon_daemon_control.json new file mode 100644 index 0000000000..f5ed717bad --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/pmon_daemon_control.json @@ -0,0 +1,4 @@ +{ + +} + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sensors.conf b/device/accton/x86_64-accton_as9647_32d-r0/sensors.conf new file mode 100644 index 0000000000..471b340ff3 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sensors.conf @@ -0,0 +1,22 @@ +# libsensors configuration file +# ----------------------------- + +chip "lm75-i2c-*-48" + label temp1 "Temp sensor 1" +chip "lm75-i2c-*-49" + label temp1 "Temp sensor 2" +chip "lm75-i2c-*-4a" + label temp1 "Temp sensor 3" +chip "lm75-i2c-*-4b" + label temp1 "Temp sensor 4" +chip "lm75-i2c-*-4c" + label temp1 "Temp sensor 5" +chip "lm75-i2c-*-4d" + label temp1 "Temp sensor 6" +chip "lm75-i2c-*-4e" + label temp1 "Temp sensor 7" +chip "lm75-i2c-*-4f" + label temp1 "Temp sensor 8" +chip "nvme-pci-*" + ignore temp2 + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/__init__.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/__init__.py new file mode 100644 index 0000000000..706e231324 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/__init__.py @@ -0,0 +1,2 @@ +__all__ = ['chassis', 'eeprom', 'platform', 'psu', 'sfp', 'thermal', 'fan', 'fan_drawer'] +from . import platform diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/chassis.py new file mode 100644 index 0000000000..801edcb9c5 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/chassis.py @@ -0,0 +1,356 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Chassis information which are available in the platform +# +############################################################################# + +import os +import time +import sys + +try: + from sonic_platform_base.chassis_base import ChassisBase + from .helper import APIHelper + from .thermal import logger +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NUM_FAN_TRAY = 6 +NUM_FAN = 2 +NUM_PSU = 2 +PORT_END = 32 +NUM_COMPONENT = 6 +POSITION_INDEX = 1 +HOST_REBOOT_CAUSE_PATH = "/host/reboot-cause/" +PMON_REBOOT_CAUSE_PATH = "/usr/share/sonic/platform/api_files/reboot-cause/" +REBOOT_CAUSE_FILE = "reboot-cause.txt" +PREV_REBOOT_CAUSE_FILE = "previous-reboot-cause.txt" +HOST_CHK_CMD = "docker > /dev/null 2>&1" +SYSLED_FNODE= "/sys/class/leds/as9647_32d_led::diag/brightness" +SYSLED_MODES = { + "0" : "STATUS_LED_COLOR_OFF", + "1" : "STATUS_LED_COLOR_GREEN", + "2" : "STATUS_LED_COLOR_GREEN_BLINK", + "3" : "STATUS_LED_COLOR_AMBER" + } + +class Chassis(ChassisBase): + """Platform-specific Chassis class""" + + def __init__(self): + ChassisBase.__init__(self) + self._api_helper = APIHelper() + self.is_host = self._api_helper.is_host() + self._watchdog = None + self._fan_watchdog = None + + self.config_data = {} + + self.__initialize_fan() + self.__initialize_psu() + self.__initialize_thermals() + self.__initialize_components() + self.__initialize_sfp() + self.__initialize_eeprom() + + def __initialize_sfp(self): + from sonic_platform.sfp import Sfp + for index in range(0, PORT_END): + sfp = Sfp(index) + self._sfp_list.append(sfp) + self.sfp_module_initialized = True + + def __initialize_fan(self): + from sonic_platform.fan_drawer import FanDrawer + for fant_index in range(NUM_FAN_TRAY): + fandrawer = FanDrawer(fant_index) + self._fan_drawer_list.append(fandrawer) + self._fan_list.extend(fandrawer._fan_list) + + def __initialize_psu(self): + from sonic_platform.psu import Psu + for index in range(0, NUM_PSU): + psu = Psu(index) + self._psu_list.append(psu) + + def __initialize_thermals(self): + from sonic_platform.thermal import Thermal + for index in range(0, Thermal.NUMBER_OF_THERMALS): + thermal = Thermal(index) + self._thermal_list.append(thermal) + + def __initialize_eeprom(self): + from sonic_platform.eeprom import Tlv + self._eeprom = Tlv() + + def __initialize_components(self): + from sonic_platform.component import Component + for index in range(0, NUM_COMPONENT): + component = Component(index) + self._component_list.append(component) + + def __is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + + return self._api_helper.hwsku + + def get_presence(self): + """ + Retrieves the presence of the Chassis + Returns: + bool: True if Chassis is present, False if not + """ + return True + + 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 True + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.get_mac() + + def get_serial(self): + """ + Retrieves the hardware serial number for the chassis + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.get_serial() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + """ + return self._eeprom.get_eeprom() + + 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. + """ + retval = (self.REBOOT_CAUSE_NON_HARDWARE, None) + + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + sw_reboot_cause = self._api_helper.read_txt_file(reboot_cause_path) or "Unknown" + if sw_reboot_cause != "Unknown": + return retval + + try: + cmd = "i2cget -f -y 0 0x21 0x30" + sts, res = self._api_helper.run_command(cmd) + if sts: + if res == '0x01': + retval = (self.REBOOT_CAUSE_POWER_LOSS, "Power On Reset") + elif res == '0x02': + retval = (self.REBOOT_CAUSE_WATCHDOG, "EC Watchdog Reset") + elif res == '0x04': + retval = (self.REBOOT_CAUSE_HARDWARE_BUTTON, "Power Button Reset") + elif res == '0x08': + retval = (self.REBOOT_CAUSE_HARDWARE_BUTTON, "Reset Button Reset") + elif res == '0x10': + retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "CPU Warm Reset") + elif res == '0x20': + retval = (self.REBOOT_CAUSE_HARDWARE_OTHER, "CPU Cold Reset") + elif res == '0x40': + retval = (self.REBOOT_CAUSE_WATCHDOG, "CPU Watchdog Reset") + elif res == '0x80': + retval = (self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER, "EC DIMM Critical Threshold Reset") + except Exception: + pass + + return retval + + def get_sfp(self, index): + """ + Retrieves sfp represented by (1-based) index + 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. + For example, 1 for Ethernet0, 2 for Ethernet4 and so on. + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + if not self.sfp_module_initialized: + self.__initialize_sfp() + + try: + sfp = self._sfp_list[index-1] + except IndexError: + sys.stderr.write("SFP index {} out of range (1-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_thermal_manager(self): + """ + Returns: + ThermalManager + """ + from .thermal_manager import ThermalManager + return ThermalManager + + def get_change_event(self, timeout=0): + """ + Returns: + Change events + """ + # SFP events + sfp_dict = {} + if not self.sfp_module_initialized: + self.__initialize_sfp() + + for index in range(0, PORT_END): + sfp_event = self._sfp_list[index].get_transceiver_change_event(2000) + if sfp_event is not None: + sfp_dict[index+1] = sfp_event + + if timeout == 0: + sleep_sec = 0.5 + else: + sleep_sec = timeout / float(1000) + + time.sleep(sleep_sec) + + return True, {'sfp': sfp_dict} + + def is_replaceable(self): + """ + Indicates whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._eeprom.get_pn() + + def get_num_fans(self): + """ + Retrieves number of chassis fans + Returns: + integer: Number of fans + """ + return len(self._fan_list) + + def get_all_fans(self): + """ + Retrieves list of fans + Returns: + list: List of fans + """ + return self._fan_list + + def get_num_fan_drawers(self): + """ + Retrieves number of fan drawers + Returns: + integer: Number of fan drawers + """ + return len(self._fan_drawer_list) + + def get_revision(self): + """ + Retrieves the hardware revision number for the chassis + Returns: + A string containing the hardware revision number for this chassis. + """ + return self._eeprom.get_revision() + + def get_num_components(self): + """ + Retrieves number of components + Returns: + integer: Number of components + """ + return NUM_COMPONENT + + def get_status_led(self): + val = self._api_helper.read_txt_file(SYSLED_FNODE) + return SYSLED_MODES[val] if val in SYSLED_MODES else "UNKNOWN" + + def set_status_led(self, color): + mode = None + for key, val in SYSLED_MODES.items(): + if val == color: + mode = key + break + if mode is None: + return False + else: + return self._api_helper.write_txt_file(SYSLED_FNODE, mode) + + def initizalize_system_led(self): + return True + + def get_position_in_parent(self): + return POSITION_INDEX + + def get_watchdog(self): + """ + Retrieves 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 WatchdogImplBase + watchdog_device_path = "/dev/watchdog0" + self._watchdog = WatchdogImplBase(watchdog_device_path) + except Exception as e: + logger.log_error("Failed to load watchdog: {}".format(e)) + + return self._watchdog + + def get_fan_watchdog(self): + """ + Retrieves fan watchdog class + Returns: + An object derived from WatchdogBase representing the fan watchdog device + """ + try: + if self._fan_watchdog is None: + from .fan_watchdog import Watchdog + self._fan_watchdog = Watchdog() + except Exception as e: + logger.log_error("Failed to load fan watchdog: {}".format(e)) + return None + + return self._fan_watchdog + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/component.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/component.py new file mode 100644 index 0000000000..2bed4a622b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/component.py @@ -0,0 +1,214 @@ +############################################################################# +# Accton +# +# Component contains an implementation of SONiC Platform Base API and +# provides the components firmware management function +# +############################################################################# + +import shlex +import subprocess +import sys +import os + +try: + from sonic_py_common import logger + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CPLD_ADDR_MAPPING = { + "CPLD1": "1-0068", + "CPLD2": "13-0061", + "CPLD3": "15-0062", + "CPLD4": "10-0066", +} +SYSFS_PATH = "/sys/bus/i2c/devices/" +BIOS_VERSION_PATH = "/sys/class/dmi/id/bios_version" +COMPONENT_LIST= [ + ("BIOS", "Basic Input/Output System"), + ("ONIE", "Open Network Install Environment"), + ("CPLD1", "FPGA Board Control"), + ("CPLD2", "QSFP Ports 1-16 Pins and LEDs"), + ("CPLD3", "QSFP Ports 17-32 Pins and LEDs"), + ("CPLD4", "Fans Control"), +] + +SYSLOG_IDENTIFIER = "component" +logger = logger.Logger(SYSLOG_IDENTIFIER) +logger.set_min_log_priority_debug() +logger.log_debug("Load {} module".format(__name__)) + +class Component(ComponentBase): + """Platform-specific Component class""" + + DEVICE_TYPE = "component" + + def __init__(self, component_index=0): + self._api_helper=APIHelper() + ComponentBase.__init__(self) + self.index = component_index + self.name = self.get_name() + + def __get_bios_version(self): + # Retrieves the BIOS firmware version + try: + with open(BIOS_VERSION_PATH, 'r') as fd: + bios_version = fd.read() + return bios_version.strip() + except Exception as e: + return None + + def __get_onie_version(self): + onie_mnt = "/tmp/onie" + user = subprocess.check_output("whoami", shell=True).decode(sys.stdout.encoding).strip() + sudo = "" if user == "root" else "sudo " + if not os.path.isdir(onie_mnt): + subprocess.call(sudo + "mkdir " + onie_mnt, shell=True) + if not os.path.ismount(onie_mnt): + subprocess.call(sudo + "mount LABEL=ONIE-BOOT " + onie_mnt, shell=True) + onie_version = subprocess.check_output("grep onie_version= /tmp/onie/grub/grub.cfg", shell=True) + onie_version = onie_version.decode(sys.stdout.encoding).strip().split("onie_version=", 1)[-1] + subprocess.call(sudo + "umount " + onie_mnt + " && " + sudo + "rm -rf " + onie_mnt, shell=True) + return onie_version + + def __get_cpld_version(self): + # Retrieves the CPLD firmware version + cpld_name = COMPONENT_LIST[self.index][0] + try: + cpld_path = "{}{}{}".format(SYSFS_PATH, CPLD_ADDR_MAPPING[cpld_name], '/version') + cpld_version_raw= self._api_helper.read_txt_file(cpld_path) + except Exception as e: + print('Get exception when read cpld (%s)', cpld_path) + + return cpld_version_raw + + def get_name(self): + """ + Retrieves the name of the component + Returns: + A string containing the name of the component + """ + return COMPONENT_LIST[self.index][0] + + def get_description(self): + """ + Retrieves the description of the component + Returns: + A string containing the description of the component + """ + return COMPONENT_LIST[self.index][1] + + def get_firmware_version(self): + """ + Retrieves the firmware version of module + Returns: + string: The firmware versions of the module + """ + fw_version = None + if self.name == "BIOS": + fw_version = self.__get_bios_version() + elif "ONIE" in self.name: + fw_version = self.__get_onie_version() + elif "CPLD" in self.name: + fw_version = self.__get_cpld_version() + + return fw_version + + def install_firmware(self, image_path): + """ + TODO: Need to implement + Install firmware to module + Args: + image_path: A string, path to firmware image + Returns: + A boolean, True if install successfully, False if not + """ + raise NotImplementedError + + def update_firmware(self, image_path): + """ + TODO: Need to implement + Updates firmware of the component + This API performs firmware update: it assumes firmware installation and loading in a single call. + In case platform component requires some extra steps (apart from calling Low Level Utility) + to load the installed firmware (e.g, reboot, power cycle, etc.) - this will be done automatically by API + Args: + image_path: A string, path to firmware image + Raises: + RuntimeError: update failed + """ + raise NotImplementedError + + def get_presence(self): + """ + Retrieves the presence of the component + Returns: + bool: True if component is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return 'N/A' + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return 'N/A' + + 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 True + + def get_position_in_parent(self): + """ + Returns: + integer: The 1-based relative physical position in parent device + """ + return 1 + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + + def get_available_firmware_version(self, image_path): + """ + TODO: Need to implement + Retrieves the available firmware version of the component + Note: the firmware version will be read from image + Args: + image_path: A string, path to firmware image + Returns: + A string containing the available firmware version of the component + """ + raise NotImplementedError + + def get_firmware_update_notification(self, image_path): + """ + Retrieves a notification on what should be done in order to complete + the component firmware update + Args: + image_path: A string, path to firmware image + Returns: + A string containing the component firmware update notification if required. + By default 'None' value will be used, which indicates that no actions are required + """ + return "None" + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/eeprom.py new file mode 100644 index 0000000000..106f609e87 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/eeprom.py @@ -0,0 +1,105 @@ +try: + import os + import sys + import re + from io import StringIO + + from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +CACHE_ROOT = '/var/cache/sonic/decode-syseeprom' +CACHE_FILE = 'syseeprom_cache' + + +class Tlv(eeprom_tlvinfo.TlvInfoDecoder): + + EEPROM_DECODE_HEADLINES = 6 + + def __init__(self): + self._eeprom_path = "/sys/bus/i2c/devices/16-0055/eeprom" + super(Tlv, self).__init__(self._eeprom_path, 0, '', True) + self._eeprom = self._load_eeprom() + + def __parse_output(self, decode_output): + decode_output.replace('\0', '') + lines = decode_output.split('\n') + lines = lines[self.EEPROM_DECODE_HEADLINES:] + _eeprom_info_dict = dict() + + for line in lines: + try: + match = re.search( + r'(0x[0-9a-fA-F]{2})([\s]+[\S]+[\s]+)([\S]+)', line) + if match is not None: + idx = match.group(1) + value = match.group(3).rstrip('\0') + + _eeprom_info_dict[idx] = value + except Exception: + pass + + return _eeprom_info_dict + + def _load_eeprom(self): + original_stdout = sys.stdout + sys.stdout = StringIO() + try: + self.read_eeprom_db() + except Exception: + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + return self.__parse_output(decode_output) + + status = self.check_status() + if 'ok' not in status: + return False + + if not os.path.exists(CACHE_ROOT): + try: + os.makedirs(CACHE_ROOT) + except Exception: + pass + + # + # only the eeprom classes that inherit from eeprom_base + # support caching. Others will work normally + # + try: + self.set_cache_name(os.path.join(CACHE_ROOT, CACHE_FILE)) + except Exception: + pass + + e = self.read_eeprom() + if e is None: + return 0 + + try: + self.update_cache(e) + except Exception: + pass + + self.decode_eeprom(e) + decode_output = sys.stdout.getvalue() + sys.stdout = original_stdout + + (is_valid, valid_crc) = self.is_checksum_valid(e) + if not is_valid: + return False + + return self.__parse_output(decode_output) + + def get_eeprom(self): + return self._eeprom + + def get_serial(self): + return self._eeprom.get('0x23', "Undefined.") + + def get_mac(self): + return self._eeprom.get('0x24', "Undefined.") + + def get_revision(self): + return self._eeprom.get('0x27', "Undefined.") + + def get_pn(self): + return self._eeprom.get('0x22', "Undefined.") diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan.py new file mode 100644 index 0000000000..9d678b7c48 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan.py @@ -0,0 +1,513 @@ +############################################################################# +# Edgecore +# +# 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_base import FanBase + from sonic_platform import platform + from .helper import APIHelper + from .thermal import logger +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +PSU_FAN_MAX_RPM = 30000 # Taken from SPEC FSH082-610G Rev A12 at "9. Fans Control Requirement" +TRAY_FRONT_FAN_MAX_RPM = 31000 +TRAY_REAR_FAN_MAX_RPM = 28000 + +# The tolerance was initially set to 15% RPM to cover the worst-case deviation of 13.15% RPM, +# which occurs at the minimum fan speed of 40% RPM. Later, it was increased to 20% to +# accommodate possible fan series–related speed variations. +TRAY_FANSPEED_TOLERANCE = 20 + +FP_FAN_LED_FILE = "/sys/class/leds/as9647_32d_led::fan/brightness" +CPLD_I2C_PATH = "/sys/bus/i2c/devices/10-0066/fan" +FAN_LED_MODE = CPLD_I2C_PATH + "_led_mode" +FAN_PERCENTAGE = CPLD_I2C_PATH + "_duty_cycle_percentage" +FAN_REQUESTED_PERCENTAGE = "/var/run/fan_requested_rpm_percentage" +FAN_CONFIGURED_PERCENTAGE = "/var/run/fan_configured_rpm_percentage" +PSU_I2C_PATH ="/sys/bus/i2c/devices/{}-00{}/" +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 3, + "addr": "59" + }, + 1: { + "num": 2, + "addr": "58" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 3, + "addr": "51" + }, + 1: { + "num": 2, + "addr": "50" + }, +} + +LED_DEBUG_MODE_OFF = "0" +LED_DEBUG_MODE_ON = "1" + +# Format: PWM DC Percentage, # PWM Code +FAN_PWM_CODE_SPEED_LIST = [ + 0.0, # 0 + 31.25, # 1 + 31.25, # 2 + 31.25, # 3 + 31.25, # 4 + 37.5, # 5 + 43.75, # 6 + 50.0, # 7 + 56.25, # 8 + 62.5, # 9 + 68.75, # 10 + 75.0, # 11 + 81.25, # 12 + 87.5, # 13 + 93.75, # 14 + 100.0 # 15 +] + +class Fan(FanBase): + """Platform-specific Fan class""" + + def __init__(self, fan_tray_index, fan_index=0, is_psu_fan=False, psu_index=0): + # Front panel fan LED + self.SYSFANLED_MODES = { + "0" : self.STATUS_LED_COLOR_OFF, + "1" : self.STATUS_LED_COLOR_GREEN, + "3" : self.STATUS_LED_COLOR_AMBER + } + # Fan drawer status LED + self.FANLED_MODES = { + "3" : self.STATUS_LED_COLOR_OFF, + "2" : self.STATUS_LED_COLOR_GREEN, + "1" : self.STATUS_LED_COLOR_RED + } + + self._api_helper=APIHelper() + self.fan_index = fan_index + self.fan_tray_index = fan_tray_index + self.is_psu_fan = is_psu_fan + if self.is_psu_fan: + self.psu_index = psu_index + self.psu_i2c_num = PSU_HWMON_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_HWMON_I2C_MAPPING[self.psu_index]['addr'] + self.psu_hwmon_path = PSU_I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + self.psu_i2c_num = PSU_CPLD_I2C_MAPPING[self.psu_index]['num'] + self.psu_i2c_addr = PSU_CPLD_I2C_MAPPING[self.psu_index]['addr'] + self.psu_cpld_path = PSU_I2C_PATH.format( + self.psu_i2c_num, self.psu_i2c_addr) + + FanBase.__init__(self) + + def get_name(self): + """ + Retrieves fan name + Returns: + A string with fan name either from fan tray or from psu + """ + if self.is_psu_fan: + fan_name = "PSU {} fan {}".format(self.psu_index+1, self.fan_index) + else: + fan_name = "FanTray {} fan {}".format(self.fan_tray_index, self.fan_index) + + return fan_name + + def get_model(self): + """ + Retrieves the fan model + Returns: + string: The model of the device + """ + return "R40W12BGNL9-07T17" + + def get_serial(self): + """ + Retrieves the fan serial + Returns: + string: The serial of the device + """ + return "N/A" + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_direction(self): + """ + Retrieves the direction of fan + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + if not self.is_psu_fan: + dir_str = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index+1, '_direction') + val = self._api_helper.read_txt_file(dir_str) + if val is not None: + if val == '0': #F2B + direction = self.FAN_DIRECTION_EXHAUST + else: + direction = self.FAN_DIRECTION_INTAKE + else: + direction = self.FAN_DIRECTION_EXHAUST + + else: #For PSU + direction = self.FAN_DIRECTION_EXHAUST # FIX_ME + + return direction + + 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) + """ + speed = 0 + if self.is_psu_fan: + psu_fan_path= "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm') + fan_speed_rpm = self._api_helper.read_txt_file(psu_fan_path) + if fan_speed_rpm is not None: + speed = (int(fan_speed_rpm, 10)) * 100 / PSU_FAN_MAX_RPM + if speed > 100: + speed = 100 + else: + return 0 + + elif self.get_presence(): + if 0 == self.fan_index: + speed_rpm = "_front_speed_rpm" + else: + speed_rpm = "_rear_speed_rpm" + speed = self._api_helper.read_txt_file( + "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index + 1, speed_rpm)) + if speed is None: + return 0 + + speed_max_rpm = TRAY_FRONT_FAN_MAX_RPM + if self.fan_index == 1: + speed_max_rpm = TRAY_REAR_FAN_MAX_RPM + speed = (int(speed, 10)) * 100 / speed_max_rpm + if speed > 100: + speed = 100 + + return int(speed) + + def get_target_speed(self): + """ + Retrieves the target (requested) speed of the fan. + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + speed = 0 + if self.is_psu_fan: + speed = 100 + elif self.get_presence(): + try: + speed = int(self._api_helper.read_txt_file(FAN_REQUESTED_PERCENTAGE)) + except: + pass + return int(speed) + + def _get_configured_speed(self): + """ + Retrieves the configured speed of the fan. + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + Notes: + This is a platform-specific function and does not belong to the base class. + This function was created to check speed tolerances against the configured + speed supported by the fan, rather than the requested target speed. + """ + speed = 0 + if self.is_psu_fan: + speed = 100 + elif self.get_presence(): + try: + speed = int(self._api_helper.read_txt_file(FAN_CONFIGURED_PERCENTAGE)) + except: + pass + return int(speed) + + 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 + """ + tolerance = TRAY_FANSPEED_TOLERANCE + if self.is_psu_fan: + tolerance = 100 + + return tolerance + + def is_under_speed(self): + """ + Calculates whether the fan speed falls below the low-speed threshold tolerance + + This function checks whether the current fan speed is below the allowed + tolerance relative to the target/configured fan speed. + This function uses the target fan speed for PSU fans and the configured + hardware-supported fan speed for all other fans. + + Returns: + A boolean, True if fan speed is under the low threshold, False if not + """ + speed = self.get_speed() + tolerance = self.get_speed_tolerance() + if self.is_psu_fan: + target_speed = self.get_target_speed() + else: + target_speed = self._get_configured_speed() + + for param, value in (('speed', speed), ('target speed', target_speed), ('speed tolerance', tolerance)): + if not isinstance(value, int): + logger.log_error(f'Fan {param} is not an integer value: {param}={value}') + return True + if value < 0 or value > 100: + logger.log_error(f'Fan {param} is not a valid percentage value: {param}={value}') + return True + + return speed * 100 < target_speed * (100 - tolerance) + + def is_over_speed(self): + """ + Calculates whether the fan speed exceeds the high-speed threshold tolerance + + This function checks whether the current fan speed exceeds the allowed + tolerance relative to the target/configured fan speed. + This function uses the target fan speed for PSU fans and the configured + hardware-supported fan speed for all other fans. + + Returns: + A boolean, True if fan speed is over the high threshold, False if not + """ + speed = self.get_speed() + tolerance = self.get_speed_tolerance() + if self.is_psu_fan: + target_speed = self.get_target_speed() + else: + target_speed = self._get_configured_speed() + + for param, value in (('speed', speed), ('target speed', target_speed), ('speed tolerance', tolerance)): + if not isinstance(value, int): + logger.log_error(f'Fan {param} is not an integer value: {param}={value}') + return True + if value < 0 or value > 100: + logger.log_error(f'Fan {param} is not a valid percentage value: {param}={value}') + return True + + return speed * 100 > target_speed * (100 + tolerance) + + def set_speed(self, speed): + """ + Sets the fan speed + Args: + speed: An integer, the percentage of full fan speed to set fan to, + in the range 0 (off) to 100 (full speed) + Returns: + A boolean, True if speed is set successfully, False if not + Notes: + This function accepts a speed value in RPM percentage and converts + it to a PWM percentage for the fan driver. + + The fan driver configures the fan speed based on predefined speed steps. + + The configured fan speed is converted from PWM to RPM, the difference + between the configured and measured RPM is then calculated and compared + against the allowed RPM tolerance. + + The equations for converting between RPM percentage and PWM percentage are: + For front fan: + RPM_Value = (279 * PWM_Percentage) + 3100 + RPM_Percentage = (RPM_Value / 31000) * 100 + For rear fan: + RPM Value = 252 * PWM Percentage + 2800 + RPM_Percentage = (RPM_Value / 28000) * 100 + + Since this function now accepts fan speed as a RPM percentage and the + thermal control logic uses increments of 10%, the valid input range + is 40% - 100%, as fan speeds below 40% are non-linear. This range is not + enforced here, as it is already handled by the fan driver. + The minimum RPM percentage of 40% is equivalent to PWM percentage of 33%. + """ + + if not self.is_psu_fan and self.get_presence(): + if self.fan_index == 0: + speed_rpm_max = TRAY_FRONT_FAN_MAX_RPM + slope = 279 + intercept = 3100 + else: + speed_rpm_max = TRAY_REAR_FAN_MAX_RPM + slope = 252 + intercept = 2800 + + # Calculation Flow: Requested RPM → Requested PWM → PWM Code → Actual PWM → Actual RPM + req_rpm_speed_perc = int(speed) + req_rpm_speed_val = int(req_rpm_speed_perc * speed_rpm_max / 100) + req_pwm_speed_perc = int((req_rpm_speed_val - intercept) / slope) + req_pwm_code = int(req_pwm_speed_perc * 100 / 625) - 1 + cfg_pwm_speed_perc = FAN_PWM_CODE_SPEED_LIST[req_pwm_code] + cfg_rpm_speed_val = int(cfg_pwm_speed_perc * slope + intercept) + cfg_rpm_speed_perc = int(cfg_rpm_speed_val / speed_rpm_max * 100) + sts1 = self._api_helper.write_txt_file(FAN_PERCENTAGE, req_pwm_speed_perc) + sts2 = self._api_helper.write_txt_file(FAN_REQUESTED_PERCENTAGE, req_rpm_speed_perc) + sts3 = self._api_helper.write_txt_file(FAN_CONFIGURED_PERCENTAGE, cfg_rpm_speed_perc) + return sts1 and sts2 and sts3 + + return False + + 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 + Notes: + The following notes are applicable only to fans that are not related to the PSU. + This function handle the fan drawer LED status, not the fan LED status. + This fan drawer LED status is managed by default in auto mode via the fan CPLD. + It can be controlled by software only when the `fan drawer LED mode` is set to + debug mode. + This function also manages the front panel fan LED status based on the status of + all fan drawer LEDs. + """ + if not self.is_psu_fan: + sts1 = False + + # This code is executed when the `fan drawer LED mode` is set to debug mode. + led_mode = self._api_helper.read_txt_file(FAN_LED_MODE) + if led_mode == LED_DEBUG_MODE_ON: + filename = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index + 1, '_led') + for key, val in self.FANLED_MODES.items(): + if val == color: + sts1 = self._api_helper.write_txt_file(filename, key) + else: + sts1 = True + + # Set the front panel fan LED based on the status of all fan drawer LEDs + fp_led_color = 'green' + fans = platform.Platform().get_chassis().get_all_fans() + for fan in fans: + if fan.get_status_led() == 'red': + # Force `amber` instead of `red` since there is no option for 'red' in hardware + fp_led_color = 'amber' + sts2 = self.set_front_panel_status_led(fp_led_color) + + return sts1 and sts2 + else: + if self.get_presence(): + platform_chassis = platform.Platform().get_chassis() + psu = platform_chassis.get_psu(self.psu_index) + return psu.set_status_led(color) + else: + return False + + def get_status_led(self): + """ + Gets the state of the fan module status LED + Args: + No + Returns: + string: representing the color with which is the status of + fan modules + Notes: + The following notes are applicable only to fans that are not related to the PSU. + This function read the fan drawer LED status, not the fan LED status. + This fan drawer LED status is managed by default in auto mode via the fan CPLD. + It can be controlled by software only when the `fan drawer LED mode` is set to + debug mode. + This fanction implements the fan drawer LED status to ensure the correct hardware + LED indication is displayed via the `show platform fan` command. + """ + if not self.is_psu_fan: + filename = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index + 1, '_led') + key = self._api_helper.read_txt_file(filename) + return self.FANLED_MODES.get(key, 'N/A') + else: + platform_chassis = platform.Platform().get_chassis() + psu = platform_chassis.get_psu(self.psu_index) + return psu.get_status_led() + + def set_front_panel_status_led(self, color): + """ + Sets the state of the front panel fan status LED + Args: + color: A string representing the color with which to set the + fan drawer status LED + Returns: + bool: True if status LED state is set successfully, False if not + """ + for key, val in self.SYSFANLED_MODES.items(): + if val == color: + return self._api_helper.write_txt_file(FP_FAN_LED_FILE, key) + return False + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + if self.is_psu_fan: + present_path = "{}{}".format(self.psu_cpld_path, 'psu_present') + else: + present_path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index + 1, '_present') + + val = self._api_helper.read_txt_file(present_path) + if val is not None: + return int(val, 10) == 1 + 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.is_psu_fan: + psu_fan_path = "{}{}".format(self.psu_hwmon_path, 'psu_fan1_speed_rpm') + val = self._api_helper.read_txt_file(psu_fan_path) + if val is not None: + return int(val, 10) != 0 + else: + return False + else: + path = "{}{}{}".format(CPLD_I2C_PATH, self.fan_tray_index + 1, '_fault') + val = self._api_helper.read_txt_file(path) + if val is not None: + return int(val, 10) == 0 + else: + return False + + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent device + """ + if self.is_psu_fan: + return (self.psu_index + 1) + else: + return (self.fan_index + 1) diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan_drawer.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan_drawer.py new file mode 100644 index 0000000000..adfe1dd84b --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan_drawer.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python + +######################################################################## +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Fan-Drawers' information available in the platform. +# +######################################################################## + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan + from sonic_platform import platform + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +FANS_PER_FANTRAY = 2 + +class FanDrawer(FanDrawerBase): + """Platform-specific Fan class""" + + def __init__(self, fantray_index): + + FanDrawerBase.__init__(self) + # FanTray is 0-based in platforms + self._api_helper=APIHelper() + self.fantrayindex = fantray_index + self.status_led_state = self.STATUS_LED_COLOR_OFF + for i in range(FANS_PER_FANTRAY): + self._fan_list.append(Fan(fantray_index, i)) + + def get_name(self): + """ + Retrieves the fan drawer name + Returns: + string: The name of the device + """ + return "FanTray {}".format(self.fantrayindex) + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_presence(self): + """ + Indicate presence of the device. + Returns: + bool: True if it is presented. + """ + if FANS_PER_FANTRAY == len(self._fan_list): + return True + else: + return False + + def get_model(self): + """ + Retrieves the fan_draver model + Returns: + string: The model of the device + + """ + return "R40W12BGNL9-07T17" + + def get_serial(self): + """ + Retrieves the fan_draver serial + Returns: + string: The serial of the device + + """ + return "N/A" + + def get_status(self): + """ + Returns Fan Status. + Returns: + bool: True if status Ok, False if not + """ + return True + + def get_maximum_consumed_power(self): + """ + Returns the maximum power could be consumed by fans in drawer. + Returns: + flat: maximum power + + """ + return 46.4 * FANS_PER_FANTRAY + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent device + """ + return (self.fantrayindex + 1) + + def set_status_led(self, color): + """ + Sets the state of the fan drawer status LED + Args: + color: A string representing the color with which to set the + fan drawer status LED + Returns: + bool: True if status LED state is set successfully, False if not + Notes: + The fan drawer LED status is managed in the `fan.py` module, as its + output is displayed through the `show platform fan` command. + """ + self.status_led_state = color + return True + + def get_status_led(self): + """ + Gets the state of the fan drawer LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + Notes: + The fan drawer LED status is managed in the `fan.py` module, as its + output is displayed through the `show platform fan` command. + """ + return self.status_led_state + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan_watchdog.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan_watchdog.py new file mode 100644 index 0000000000..f0c166b792 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/fan_watchdog.py @@ -0,0 +1,79 @@ +############################################################################# +# +# Module contains an implementation of SONiC Platform Base API and +# provides access to fan CPLD watchdog +# +############################################################################# + +try: + from sonic_platform_base.watchdog_base import WatchdogBase + from .helper import APIHelper + from .thermal import logger +except ImportError as e: + raise ImportError("%s - required module not found" % e) + +WD_ERROR = -1 +WD_ENABLE = 1 +WD_DISABLE = 0 +WD_MAX_PWM = 15 # Represent 100% PWM +WD_MAX_TIMEOUT_SEC = 255 + +class Watchdog(WatchdogBase): + """ + Platform-specific watchdog class for interfacing with the fan CPLD watchdog + """ + + def __init__(self): + self._api_helper = APIHelper() + + def _run_i2cset_cmd(self, bus, addr, reg, data): + cmd = "i2cset -f -y {} {} {} {}".format(bus, addr, reg, data) + sts, res = self._api_helper.run_command(cmd) + if not (sts and res == ''): + logger.log_error("Failed to run i2cset command: {}".format(cmd)) + return False + return True + + def _run_i2cget_cmd(self, bus, addr, reg): + cmd = "i2cget -f -y {} {} {}".format(bus, addr, reg) + sts, res = self._api_helper.run_command(cmd) + if not sts: + logger.log_error("Failed to run i2cget command: {}".format(cmd)) + return None + return res + + def arm(self, seconds): + ret_sts = WD_ERROR + if seconds <= 0: + return ret_sts + if seconds > WD_MAX_TIMEOUT_SEC: + logger.log_error("Invalid timeout ({}), must be ≤{}. Timeout forced to {}.".format( + seconds, WD_MAX_TIMEOUT_SEC, WD_MAX_TIMEOUT_SEC)) + seconds = WD_MAX_TIMEOUT_SEC + sts1 = self._run_i2cset_cmd('10', '0x66', '0x32', f'0x{WD_MAX_PWM:02X}') # Set max PWM + sts2 = self._run_i2cset_cmd('10', '0x66', '0x33', f'0x{WD_ENABLE:02X}') # Enable WD + sts3 = self._run_i2cset_cmd('10', '0x66', '0x31', f'0x{seconds:02X}') # Set timeout + if all([sts1, sts2, sts3]): + ret_sts = seconds + return ret_sts + + def disarm(self): + self._run_i2cset_cmd('10', '0x66', '0x33', f'0x{WD_DISABLE:02X}') # Disable WD + return True + + def is_armed(self): + armed = False + try: + armed = int(self._run_i2cget_cmd('10', '0x66', '0x33'), 16) == WD_ENABLE + except (ValueError, TypeError) as e: + logger.log_error("Failed to check if watchdog is armed: {}".format(e)) + return armed + + def get_remaining_time(self): + remaining_time = WD_ERROR + if self.is_armed(): + try: + remaining_time = int(self._run_i2cget_cmd('10', '0x66', '0x31'), 16) + except (ValueError, TypeError) as e: + logger.log_error("Failed to get remaining time: {}".format(e)) + return remaining_time diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/helper.py new file mode 100644 index 0000000000..52c91fba20 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/helper.py @@ -0,0 +1,54 @@ +import os +import shlex +import subprocess +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + + +class APIHelper(): + + def __init__(self): + (self.platform, self.hwsku) = device_info.get_platform_and_hwsku() + + def is_host(self): + return os.system(HOST_CHK_CMD) == 0 + + def is_sonic(self): + return os.path.exists("/etc/sonic/config_db.json") + + def run_command(self, cmd): + status = True + result = "" + try: + args = shlex.split(cmd) + p = subprocess.Popen( + args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + result = err.strip() + except Exception: + status = False + return status, result + + 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 None + + def write_txt_file(self, file_path, value): + try: + with open(file_path, 'w') as fd: + fd.write(str(value)) + except IOError: + return False + return True + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/pcie.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/pcie.py new file mode 100644 index 0000000000..6935fcda9e --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/pcie.py @@ -0,0 +1,12 @@ +import os +import re + +try: + from sonic_platform_base.sonic_pcie.pcie_common import PcieUtil +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Pcie(PcieUtil): + + def __init__(self, platform_path): + PcieUtil.__init__(self, platform_path) diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/platform.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/platform.py new file mode 100644 index 0000000000..2f2c2a447f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/platform.py @@ -0,0 +1,21 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the platform information +# +############################################################################# + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + """Platform-specific Platform class""" + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/psu.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/psu.py new file mode 100644 index 0000000000..8787e6ddd1 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/psu.py @@ -0,0 +1,302 @@ +############################################################################# +# Edgecore +# +# Module contains an implementation of SONiC Platform Base API and +# provides the PSUs status which are available in the platform +# +############################################################################# + +import os.path + +try: + from sonic_platform_base.psu_base import PsuBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +I2C_PATH ="/sys/bus/i2c/devices/{0}-00{1}/" + +PSULED_FNODES= ["/sys/class/leds/as9647_32d_led::psu1/brightness", + "/sys/class/leds/as9647_32d_led::psu2/brightness"] + +PSU_NAME_LIST = ["PSU-1", "PSU-2"] +PSU_NUM_FAN = [1, 1] +PSU_HWMON_I2C_MAPPING = { + 0: { + "num": 3, + "addr": "59" + }, + 1: { + "num": 2, + "addr": "58" + }, +} + +PSU_CPLD_I2C_MAPPING = { + 0: { + "num": 3, + "addr": "51" + }, + 1: { + "num": 2, + "addr": "50" + }, +} + +class Psu(PsuBase): + """Platform-specific Psu class""" + + def __init__(self, psu_index=0): + PsuBase.__init__(self) + self.index = psu_index + self._api_helper = APIHelper() + + self.i2c_num = PSU_HWMON_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_HWMON_I2C_MAPPING[self.index]["addr"] + self.hwmon_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + + self.i2c_num = PSU_CPLD_I2C_MAPPING[self.index]["num"] + self.i2c_addr = PSU_CPLD_I2C_MAPPING[self.index]["addr"] + self.cpld_path = I2C_PATH.format(self.i2c_num, self.i2c_addr) + self.__initialize_fan() + self.PSULED_MODES = { + "0" : self.STATUS_LED_COLOR_OFF, + "1" : self.STATUS_LED_COLOR_GREEN, + "3" : self.STATUS_LED_COLOR_AMBER + } + + def __initialize_fan(self): + from sonic_platform.fan import Fan + for fan_index in range(0, PSU_NUM_FAN[self.index]): + fan = Fan(fan_index, 0, is_psu_fan=True, psu_index=self.index) + if fan.get_presence(): + self._fan_list.append(fan) + + def get_voltage(self): + """ + Retrieves current PSU voltage output + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + if self.get_status() == 0: + return None + vout_path = "{}{}".format(self.hwmon_path, 'psu_v_out') + vout_val=self._api_helper.read_txt_file(vout_path) + return float(vout_val)/ 1000 + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + if self.get_status() == 0: + return None + iout_path = "{}{}".format(self.hwmon_path, 'psu_i_out') + val=self._api_helper.read_txt_file(iout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_power(self): + """ + Retrieves current energy supplied by PSU + Returns: + A float number, the power in watts, e.g. 302.6 + """ + if self.get_status() == 0: + return None + pout_path = "{}{}".format(self.hwmon_path, 'psu_p_out') + val=self._api_helper.read_txt_file(pout_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def set_status_led(self, color): + """ + Sets the state of the PSU status LED + Args: + color: A string representing the color with which to set the PSU status LED + Note: Only support green, amber and off + Returns: + bool: True if status LED state is set successfully, False if not + """ + mode = None + for key, val in self.PSULED_MODES.items(): + if val == color: + mode = key + break + if mode is None: + return False + else: + return self._api_helper.write_txt_file(PSULED_FNODES[self.index], mode) + + 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 + """ + val = self._api_helper.read_txt_file(PSULED_FNODES[self.index]) + return self.PSULED_MODES[val] if val in self.PSULED_MODES else "UNKNOWN" + + def get_temperature(self): + """ + Retrieves current temperature reading from PSU + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temp_path = "{}{}".format(self.hwmon_path, 'psu_temp1_input') + val=self._api_helper.read_txt_file(temp_path) + if val is not None: + return float(val)/1000 + else: + return 0 + + def get_temperature_high_threshold(self): + """ + Retrieves the high threshold temperature of PSU + Returns: + A float number, the high threshold temperature of PSU in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return 50.0 + + def get_voltage_high_threshold(self): + """ + Retrieves the high threshold PSU voltage output + Returns: + A float number, the high threshold output voltage in volts, + e.g. 12.1 + """ + return 12.6 + + def get_voltage_low_threshold(self): + """ + Retrieves the low threshold PSU voltage output + Returns: + A float number, the low threshold output voltage in volts, + e.g. 12.1 + """ + return 11.4 + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return PSU_NAME_LIST[self.index] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + presence_path="{}{}".format(self.cpld_path, 'psu_present') + val=self._api_helper.read_txt_file(presence_path) + if val is not None: + return int(val, 10) == 1 + else: + return 0 + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + power_path="{}{}".format(self.cpld_path, 'psu_power_good') + val = self._api_helper.read_txt_file(power_path) + if val is not None: + if int(val, 10) == 1: + self.set_status_led(self.STATUS_LED_COLOR_GREEN) + return True + else: + self.set_status_led(self.STATUS_LED_COLOR_AMBER) + return False + else: + return False + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + model_path="{}{}".format(self.cpld_path, 'psu_model_name') + if not os.path.isfile(model_path): + return "Unknown" + + val = open(model_path, encoding='utf-8', errors='ignore').read() + if val is not None: + val = val.strip() + return val + else: + return "Unknown" + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + serial_path="{}{}".format(self.cpld_path, 'psu_serial_number') + if not os.path.isfile(serial_path): + return "Unknown" + + val = open(serial_path, encoding='utf-8', errors='ignore').read() + if val is not None: + val = val.strip() + return val + else: + return "Unknown" + + def is_replaceable(self): + """ + Retrieves whether device is replaceable + returns: + bool: True if it is replaceable + """ + return True + + 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_maximum_supplied_power(self): + """ + Retrieves maximum supplied power of PSU + Returns: + float: Power in watts + """ + return self.get_power() + + def get_revision(self): + """ + Retrieves the hardware revision of the device + + Returns: + string: Revision value of device + """ + return self.get_serial() + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent device + """ + return (self.index + 1) + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/sfp.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/sfp.py new file mode 100644 index 0000000000..f325dd509f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/sfp.py @@ -0,0 +1,330 @@ +############################################################################# +# Accton +# +# Sfp contains an implementation of SONiC Platform Base API and +# provides the sfp device status which are available in the platform +# +############################################################################# + +import os +import sys +import time +import struct +import subprocess +from ctypes import create_string_buffer + +try: + from .thermal import SfpThermal + from sonic_py_common import logger + from sonic_platform_base.sonic_xcvr.sfp_optoe_base import SfpOptoeBase + from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +logger = logger.Logger() +logger.set_min_log_priority_debug() +logger.log_debug("Load {} module".format(__name__)) + +QSFP_POWEROVERRIDE_OFFSET = 93 +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' + +SYSFS_RESET_DISABLE = 0 +SYSFS_RESET_ENABLE = 1 + +SYSFS_LPM_MODE_DISABLE = 0 +SYSFS_LPM_MODE_ENABLE = 1 + +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 + +SFP_TYPE = 'SFP' +OSFP_TYPE = 'OSFP' +QSFP_TYPE = 'QSFP' + +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later with SFF-8636 + '11', # QSFP28 or later with SFF-8636 + '1e', # QSFP+ or later with CMIS +] +OSFP_TYPE_CODE_LIST = [ + '19' # OSFP 8X Pluggable Transceiver +] + +class Sfp(SfpOptoeBase): + """Platform-specific Sfp class""" + + EEPROM_PATH = '/sys/bus/i2c/devices/{0}-0050/eeprom' + CPLD_I2C_PATH = "/sys/bus/i2c/devices/" + PLATFORM_ROOT_PATH = "/usr/share/sonic/device" + PMON_JSON_PATH = "/usr/share/sonic/platform" + PMON_HWSKU_PATH = '/usr/share/sonic/hwsku' + SFP_ERROR_DESCRIPTION_HIGH_VCC = "High VCC detected" + SFP_ERROR_DESCRIPTION_LOW_VCC = "Low VCC detected" + + # Port number + PORT_START = 1 + PORT_END = 32 + + _cpld_mapping = { + 0: "13-0061", + 1: "15-0062", + } + + _port_to_i2c_mapping = list(range(18, 50)) + _sfp_port = range(PORT_START, PORT_END + 1) + + + def __init__(self, sfp_index=0): + + SfpOptoeBase.__init__(self) + self._index = sfp_index + self._port_num = self._index + 1 + self._api_helper = APIHelper() + self.data = {'present': False} + + self.eeprom_path = self.EEPROM_PATH.format(Sfp._port_to_i2c_mapping[self._index]) + + if self._index <= 15: + cpld_index = 0 + else: + cpld_index = 1 + + self.reset_path = f"{Sfp.CPLD_I2C_PATH}{Sfp._cpld_mapping[cpld_index]}/module_reset_{self._port_num}" + self.present_path = f"{Sfp.CPLD_I2C_PATH}{Sfp._cpld_mapping[cpld_index]}/module_present_{self._port_num}" + self.lpmode_path = f"{Sfp.CPLD_I2C_PATH}{Sfp._cpld_mapping[cpld_index]}/module_lpmode_{self._port_num}" + + self._sfp_type = None + self._thermal_list.append(SfpThermal(self)) + + @property + def sfp_type(self): + if self._sfp_type is None: + self._sfp_type = self._detect_sfp_type() + + return self._sfp_type + + def _detect_sfp_type(self): + sfp_type_raw = self.read_eeprom(XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + sfp_type = SFP_TYPE + if sfp_type_raw: + sfp_type_code = [f'{x:02x}' for x in sfp_type_raw][0] + if sfp_type_code in QSFP_TYPE_CODE_LIST: + sfp_type = QSFP_TYPE + elif sfp_type_code in OSFP_TYPE_CODE_LIST: + sfp_type = OSFP_TYPE + return sfp_type + + def __is_host(self): + try: + result = subprocess.run( + ["docker", "info"], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + return result.returncode == 0 + except FileNotFoundError: + # 'docker' command is not found, assume not host (or minimal container) + return False + + def __get_path_to_port_config_file(self): + platform_path = "/".join([self.PLATFORM_ROOT_PATH, self._api_helper.platform]) + platform_json_path = platform_path if self.__is_host() else self.PMON_JSON_PATH + config_file_path = "/".join([platform_json_path, "platform.json"]) + return config_file_path + + + def get_eeprom_path(self): + return self.eeprom_path + + + def get_id(self): + return self._index + + + 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()) + name = sfputil_helper.logical[self._index] or "Unknown" + return name + + + def get_presence(self): + """ + Retrieves the presence of the device + Returns: + bool: True if device is present, False if not + """ + val = self._api_helper.read_txt_file(self.present_path) + + if val is not None: + return int(val, 10)==1 + else: + return False + + + def get_transceiver_change_event(self, timeout=2000): + """ + Checks if transceiver has been inserted/removed + Returns: + SFP_STATUS_INSERTED, SFP_STATUS_REMOVED or None + """ + present = self.get_presence() + if present != self.data['present']: + if present == True: + sfp_event = SFP_STATUS_INSERTED + logger.log_debug("get_transceiver_change_event: port {}: SFP_STATUS_INSERTED".format(self._port_num)) + else: + sfp_event = SFP_STATUS_REMOVED + logger.log_debug("get_transceiver_change_event: port {}: SFP_STATUS_REMOVED".format(self._port_num)) + else: + sfp_event = None + + self.data['present'] = present + return sfp_event + + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + Returns: + A Boolean, True if reset enabled, False if disabled + """ + val=self._api_helper.read_txt_file(self.reset_path) + if val is None: + return 0 + + return int(val, 10)==1 + + + def get_lpmode(self): + """ + Retrieves the lpmode (low power mode) status of this SFP + Returns: + A Boolean, True if lpmode is enabled, False if disabled + """ + if self._port_num > self.PORT_END: + # SFP doesn't support this feature + return False + else: + val = self._api_helper.read_txt_file(self.lpmode_path) + if val is not None: + return int(val, 10) == 1 + else: + return False + + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + Returns: + A boolean, True if successful, False if not + """ + # Check for invalid port_num + + if self._port_num > self.PORT_END: + return False # SFP doesn't support this feature + elif not self.get_presence(): + return False + + ret = self._api_helper.write_txt_file(self.reset_path, SYSFS_RESET_ENABLE) + if ret is not True: + return ret + + time.sleep(0.2) + ret = self._api_helper.write_txt_file(self.reset_path, SYSFS_RESET_DISABLE) + time.sleep(0.2) + + return ret + + + 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 + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if self._port_num > self.PORT_END: + return False # SFP doesn't support this feature + else: + if not self.get_presence(): + return False + + val = SYSFS_LPM_MODE_ENABLE + if lpmode == False: + val = SYSFS_LPM_MODE_DISABLE + return self._api_helper.write_txt_file(self.lpmode_path, val) + + + def get_transceiver_info(self): + transceiver_info_dict = SfpOptoeBase.get_transceiver_info(self) + if transceiver_info_dict is not None: + transceiver_info_dict['hardware_rev'] = 'N/A' + + return transceiver_info_dict + + + 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.get_presence() and not self.get_reset_status() + + def is_replaceable(self): + """ + Indicate whether this device is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_error_description(self): + """ + Get error description + + Args: + None + + Returns: + The error description + """ + if not self.get_presence(): + return self.SFP_STATUS_UNPLUGGED + + api = SfpOptoeBase.get_xcvr_api(self) + flags = api.get_module_level_flag() + case_temp = flags.get("case_temp_flags") + case_voltage = flags.get("voltage_flags") + if case_temp.get("case_temp_high_alarm_flag"): + error_description = self.SFP_ERROR_DESCRIPTION_HIGH_TEMP + elif case_temp.get("case_temp_high_warn_flag"): + error_description = self.SFP_ERROR_DESCRIPTION_HIGH_TEMP + elif case_voltage.get("voltage_high_alarm_flag"): + error_description = self.SFP_ERROR_DESCRIPTION_HIGH_VCC + elif case_voltage.get("voltage_high_warn_flag"): + error_description = self.SFP_ERROR_DESCRIPTION_HIGH_VCC + elif case_voltage.get("voltage_low_alarm_flag"): + error_description = self.SFP_ERROR_DESCRIPTION_LOW_VCC + elif case_voltage.get("voltage_low_warn_flag"): + error_description = self.SFP_ERROR_DESCRIPTION_LOW_VCC + else: + error_description = self.SFP_STATUS_OK + + return error_description + + def get_temperature(self): + bulkStatus = self.get_transceiver_bulk_status() + temp = bulkStatus["temperature"] if bulkStatus else 0.0 + if isinstance(temp, float): + temp = round(temp, 1) + return temp diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal.py new file mode 100644 index 0000000000..03508e2950 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal.py @@ -0,0 +1,378 @@ +############################################################################# +# Edgecore +# +# Thermal contains an implementation of SONiC Platform Base API and +# provides the thermal device status which are available in the platform +# +############################################################################# + +import os +import glob +import time +import threading + +try: + from sonic_platform_base.thermal_base import ThermalBase + from sonic_py_common.logger import Logger + from .thermal_device_data import DEVICE_DATA + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +logger = Logger() +# To enable messages of log_debug verbosity, uncomment the below line +# logger.set_min_log_priority_debug() + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + NUMBER_OF_THERMALS = 12 + CPU_TEMP_SENSORS_OFFSET = 11 + ASIC_TEMP_SENSORS_OFFSET = 8 + SYSFS_PATH = "/sys/bus/i2c/devices" + _db_thermals = None + _db_lock = threading.Lock() + + def __init__(self, thermal_index=0): + self._api_helper = APIHelper() + + self.index = thermal_index + # Add thermal name + self.THERMAL_NAME_LIST = [] + self.THERMAL_NAME_LIST.append("PCB VDD_Core") + self.THERMAL_NAME_LIST.append("PCB FP Hotspot") + self.THERMAL_NAME_LIST.append("PCB Top Front") + self.THERMAL_NAME_LIST.append("PCB Bottom Front") + self.THERMAL_NAME_LIST.append("PCB Bottom Rear") + self.THERMAL_NAME_LIST.append("PCB OCXO") + self.THERMAL_NAME_LIST.append("PCB ASIC") + self.THERMAL_NAME_LIST.append("PCB Top Rear") + self.THERMAL_NAME_LIST.append("ASIC Temp 1") + self.THERMAL_NAME_LIST.append("ASIC Temp 2") + self.THERMAL_NAME_LIST.append("ASIC Temp 3") + self.THERMAL_NAME_LIST.append("CPU Temp") + + if self.index < Thermal.ASIC_TEMP_SENSORS_OFFSET: + i2c_path = { + 0: "11-0048/hwmon/hwmon*/", + 1: "11-0049/hwmon/hwmon*/", + 2: "11-004a/hwmon/hwmon*/", + 3: "11-004b/hwmon/hwmon*/", + 4: "11-004c/hwmon/hwmon*/", + 5: "11-004d/hwmon/hwmon*/", + 6: "11-004e/hwmon/hwmon*/", + 7: "11-004f/hwmon/hwmon*/", + }.get(self.index, None) + + self.hwmon_path = "{}/{}".format(self.SYSFS_PATH, i2c_path) + + self.ss_index = 1 + + self.minimum_thermal = None + self.maximum_thermal = None + + def __read_txt_file_with_glob(self, file_path): + data = None + for filename in glob.glob(file_path): + try: + with open(filename, 'r') as fd: + data = fd.readline().rstrip() + break + except IOError as e: + pass + + return data + + def __get_round_temp(self, temp, divisor): + round_temp = None + try: + round_temp = round(float(temp) / divisor, 1) + except (ValueError, TypeError) as e: + logger.log_error("Failed to read temperature sensor {}: {}".format(self.get_name(), e)) + return round_temp + + def __get_pcb_temp(self): + temp_file = "temp{}_input".format(self.ss_index) + temp_file_path = os.path.join(self.hwmon_path, temp_file) + temp = self.__read_txt_file_with_glob(temp_file_path) + return self.__get_round_temp(temp, 1000) + + def __get_asic_temp(self): + temp = None + + if Thermal._db_thermals is None: + with Thermal._db_lock: + if Thermal._db_thermals is None: + try: + from swsscommon.swsscommon import SonicV2Connector + db = SonicV2Connector() + db.connect(db.STATE_DB) + Thermal._db_thermals = db + except Exception as e: + logger.log_error("Failed to connect to STATE_DB: {}".format(e)) + + if Thermal._db_thermals is not None: + try: + tbl = Thermal._db_thermals.get_all(Thermal._db_thermals.STATE_DB, 'ASIC_TEMPERATURE_INFO') + temp = tbl.get("temperature_{}".format(self.index - Thermal.ASIC_TEMP_SENSORS_OFFSET), None) + except Exception as e: + logger.log_error("Failed to get ASIC temperature from DB: {}".format(e)) + + return self.__get_round_temp(temp, 1) + + def __get_cpu_temp(self): + temp_file_path = "/sys/class/hwmon/hwmon2/temp1_input" + temp = self._api_helper.read_txt_file(temp_file_path) + return self.__get_round_temp(temp, 1000) + + 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 + """ + temp = None + try: + if self.index < Thermal.ASIC_TEMP_SENSORS_OFFSET: + temp = self.__get_pcb_temp() + elif self.index < Thermal.CPU_TEMP_SENSORS_OFFSET: + temp = self.__get_asic_temp() + elif self.index < Thermal.NUMBER_OF_THERMALS: + temp = self.__get_cpu_temp() + except Exception as e: + logger.log_error("Failed to get temperature for thermal index {}: {}".format(self.index, e)) + + return temp + + 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 + """ + threshold = None + if self.index >= 0 and self.index < Thermal.NUMBER_OF_THERMALS: + temp_list = DEVICE_DATA['thresholds'][self.index] + thresh_list = temp_list[len(temp_list) - 2].split(':') + threshold = float(thresh_list[1]) + return threshold + + def get_low_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the low threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 0.0 + """ + return 0.1 + + def get_low_critical_threshold(self): + """ + Retrieves the low critical threshold temperature of thermal + Returns: + A float number, the low critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return 0.1 + + def get_high_critical_threshold(self): + """ + Retrieves the high critical threshold temperature of thermal + + Returns: + A float number, the high critical threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + threshold = None + if self.index >= 0 and self.index < Thermal.NUMBER_OF_THERMALS: + temp_list = DEVICE_DATA['thresholds'][self.index] + thresh_list = temp_list[len(temp_list) - 1].split(':') + threshold = float(thresh_list[1]) + return threshold + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + return self.THERMAL_NAME_LIST[self.index] + + def get_model(self): + """ + Retrieves the model of the thermal device + Returns: + string: The model of the thermal device + """ + model = None + if self.index < Thermal.ASIC_TEMP_SENSORS_OFFSET: + model = "LM75BD" + elif self.index < Thermal.CPU_TEMP_SENSORS_OFFSET: + model = "Xsight ASIC" + elif self.index < Thermal.NUMBER_OF_THERMALS: + model = "Host CPU" + return model + + def get_serial(self): + """ + Retrieves the model of the thermal device + Returns: + string: The model of the thermal device + """ + return "N/A" + + def is_replaceable(self): + """ + Retrieves is the thermal device replaceable + Returns: + boolean: false + """ + return False + + def get_presence(self): + """ + Retrieves the presence of the Thermal + Returns: + bool: True if Thermal is present, False if not + """ + presence = False + if self.index < Thermal.ASIC_TEMP_SENSORS_OFFSET: + temp = self.__get_pcb_temp() + if temp is not None: + presence = True + else: + presence = True + return 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.get_presence() + + def get_minimum_recorded(self): + """ + Retrieves the minimum recorded temperature of thermal + Returns: + A float number, the minimum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + tmp = self.get_temperature() + if isinstance(tmp, float): + if self.minimum_thermal is None or tmp < self.minimum_thermal: + self.minimum_thermal = tmp + return self.minimum_thermal + + def get_maximum_recorded(self): + """ + Retrieves the maximum recorded temperature of thermal + Returns: + A float number, the maximum recorded temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + tmp = self.get_temperature() + if isinstance(tmp, float): + if self.maximum_thermal is None or tmp > self.maximum_thermal: + self.maximum_thermal = tmp + return self.maximum_thermal + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent device + """ + return (self.index + 1) + + +class SfpThermal(ThermalBase): + THRESH_DELAY = 1 # 1 second + + def __init__(self, sfp): + ThermalBase.__init__(self) + self._sfp = sfp + self._minimum = None + self._maximum = None + self._cachedThreshInfo = None + self._cachedThreshInfoTime = 0 + + def get_name(self): + return "{} {}".format(self._sfp.sfp_type, self._sfp.get_id() + 1) + + def get_presence(self): + return self._sfp.get_presence() + + def get_model(self): + return "N/A" + + def get_serial(self): + return "N/A" + + def get_status(self): + return self.get_temperature() is not None + + def get_position_in_parent(self): + return 1 + + def is_replaceable(self): + return False + + def get_temperature(self): + value = self._sfp.get_temperature() + if not isinstance(value, float): + return None + if self._minimum is None or self._minimum > value: + self._minimum = value + if self._maximum is None or self._maximum < value: + self._maximum = value + return value + + def _get_threshold_info(self): + currTime = time.time() + if currTime - self._cachedThreshInfoTime > self.THRESH_DELAY: + self._cachedThreshInfoTime = currTime + self._cachedThreshInfo = self._sfp.get_transceiver_threshold_info() + return self._cachedThreshInfo + + def get_low_threshold(self): + threshInfo = self._get_threshold_info() + if threshInfo: + lowThreshold = threshInfo.get("templowwarning") + if not threshInfo or lowThreshold == "N/A": + return None + return lowThreshold + + def get_low_critical_threshold(self): + threshInfo = self._get_threshold_info() + if threshInfo: + lowCritThreshold = threshInfo.get("templowalarm") + if not threshInfo or lowCritThreshold == "N/A": + return None + return lowCritThreshold + + def get_high_threshold(self): + threshInfo = self._get_threshold_info() + if threshInfo: + highThreshold = threshInfo.get("temphighwarning") + if not threshInfo or highThreshold == "N/A": + return None + return highThreshold + + def get_high_critical_threshold(self): + threshInfo = self._get_threshold_info() + if threshInfo: + highCritThreshold = threshInfo.get("temphighalarm") + if not threshInfo or highCritThreshold == "N/A": + return None + return highCritThreshold + + def get_minimum_recorded(self): + self.get_temperature() + return self._minimum + + def get_maximum_recorded(self): + self.get_temperature() + return self._maximum diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_actions.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_actions.py new file mode 100644 index 0000000000..3868349c7f --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_actions.py @@ -0,0 +1,234 @@ +from sonic_platform_base.sonic_thermal_control.thermal_action_base import ThermalPolicyActionBase +from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +from .helper import APIHelper +from .thermal import logger +import getpass +import time + +class FanAction(ThermalPolicyActionBase): + def get_fan_info(self, thermal_info_dict): + from .thermal_infos import FanInfo + fan_info_obj = None + if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): + fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME] + else: + logger.log_error("Failed to get fans information") + return fan_info_obj + +class ThermalAction(ThermalPolicyActionBase): + def get_thermal_info(self, thermal_info_dict): + from .thermal_infos import ThermalInfo + thermal_info_obj = None + if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): + thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] + else: + logger.log_error("Failed to get thermals information") + return thermal_info_obj + + +class SetFanSpeedAction(FanAction): + """ + Base thermal action class to set speed for fans + """ + # JSON field definition + JSON_FIELD_SPEED = 'speed' + + def __init__(self): + """ + Constructor of SetFanSpeedAction which actually do nothing. + """ + self.speed = None + + def load_from_json(self, json_obj): + """ + Construct SetFanSpeedAction via JSON. JSON example: + { + "type": "fan.all.set_speed" + "speed": "100" + } + :param json_obj: A JSON object representing a SetFanSpeedAction action. + :return: + """ + self.speed = 100 + if SetFanSpeedAction.JSON_FIELD_SPEED in json_obj: + speed = float(json_obj[SetFanSpeedAction.JSON_FIELD_SPEED]) + if speed >= 0 and speed <= 100: + self.speed = speed + else: + logger.log_error('{}: Invalid speed value {} in JSON policy file, value should be in range [0, 100]. ' \ + 'Forcing speed to 100%.'.format(self.__class__.__name__, speed)) + else: + logger.log_error('{}: Missing mandatory field `{}` in JSON policy file. Forcing speed to 100%.'. + format(self.__class__.__name__, SetFanSpeedAction.JSON_FIELD_SPEED)) + +@thermal_json_object('fan.all.set_speed') +class SetAllFanSpeedAction(SetFanSpeedAction): + """ + Action to set speed for all fans + """ + def execute(self, thermal_info_dict): + """ + Set speed for all fans + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + fan_info_obj = self.get_fan_info(thermal_info_dict) + if fan_info_obj: + logger.log_notice("Set all Fan\'s speed to {}%".format(self.speed)) + for fan in fan_info_obj.get_presence_fans(): + fan.set_speed(self.speed) + +@thermal_json_object('thermal_control.control') +class ControlThermalAlgoAction(ThermalPolicyActionBase): + """ + Action to control the thermal control algorithm + """ + # JSON field definition + JSON_FIELD_STATUS = 'status' + + def __init__(self): + self.status = True + + def load_from_json(self, json_obj): + """ + Construct ControlThermalAlgoAction via JSON. JSON example: + { + "type": "thermal_control.control" + "status": "true" + } + :param json_obj: A JSON object representing a ControlThermalAlgoAction action. + :return: + """ + self.status = False + if ControlThermalAlgoAction.JSON_FIELD_STATUS in json_obj: + status_str = json_obj[ControlThermalAlgoAction.JSON_FIELD_STATUS].lower() + if status_str in ['true', 'false']: + self.status = status_str + else: + logger.log_error('{}: Invalid `{}` field value ({}), value should be true or false. Forcing false.'. + format(self.__class__.__name__, ControlThermalAlgoAction.JSON_FIELD_STATUS, status_str)) + else: + logger.log_error('{}: Missing mandatory field `{}` in JSON policy file. Forcing false.'. + format(self.__class__.__name__, ControlThermalAlgoAction.JSON_FIELD_STATUS)) + + def execute(self, thermal_info_dict): + """ + Disable thermal control algorithm + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + from .thermal_infos import ChassisInfo + chassis_info_obj = None + if ChassisInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ChassisInfo.INFO_NAME], ChassisInfo): + chassis_info_obj = thermal_info_dict[ChassisInfo.INFO_NAME] + chassis = chassis_info_obj.get_chassis() + thermal_manager = chassis.get_thermal_manager() + if self.status: + thermal_manager.start_thermal_control_algorithm() + else: + thermal_manager.stop_thermal_control_algorithm() + +@thermal_json_object('thermal.warning.overheat') +class ThermalWarningAction(ThermalAction): + """ + Action for handling thermal warning overheat (chassis and XCVR). + Fan speed is forced to 100% by the fan.all.set_speed action in the policy. + """ + + def execute(self, thermal_info_dict): + """ + Log warning overheat for chassis and XCVR sensors. + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + for name, temp, threshold in thermal_info_obj.get_warning_overheat_data(): + logger.log_warning("Thermal warning overheat detected by '{}' sensor: temperature = {}, threshold = {}". + format(name, temp, threshold)) + + for name, temp, threshold in thermal_info_obj.get_xcvr_warning_overheat_data(): + logger.log_warning("XCVR warning overheat: '{}' temperature = {}, threshold = {}".format( + name, temp, threshold)) + +@thermal_json_object('thermal.critical.overheat') +class ThermalCriticalAction(ThermalAction): + """ + Action for handling thermal critical overheat. + Chassis critical: log + thermal shutdown (reboot). + XCVR critical: log per module (no reboot). + Fan speed is forced to 100% by the fan.all.set_speed action in the policy. + """ + def __init__(self): + super().__init__() + self.api_helper = APIHelper() + + def reboot_device(self): + from .chassis import HOST_REBOOT_CAUSE_PATH, REBOOT_CAUSE_FILE + + reboot_user = getpass.getuser() + reboot_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + reboot_cause_path = (HOST_REBOOT_CAUSE_PATH + REBOOT_CAUSE_FILE) + msg = "User issued 'Thermal Overload' command [User: {}, Time: {}]".format(reboot_user, reboot_time) + sts = self.api_helper.write_txt_file(reboot_cause_path, msg) + if not sts: + logger.log_error("Failed to write reboot cause to the file: {}".format(reboot_cause_path)) + + sts, res = self.api_helper.run_command("sync") + if not (sts and res == ''): + logger.log_error("Failed to run sync command") + time.sleep(3) + + sts, res = self.api_helper.run_command("/opt/xplt/utils/pwcycle_box.sh") + if not sts: + logger.log_error("Failed to reboot device: {}".format(res)) + + def execute(self, thermal_info_dict): + """ + Perform thermal critical overheat logic. + For chassis sensors: log and reboot. + For XCVR sensors: log per module (no reboot). + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + if thermal_info_obj.is_critical_overheat(): + for name, temp, threshold in thermal_info_obj.get_critical_overheat_data(): + logger.log_error("Thermal critical overheat detected by '{}' sensor: temperature = {}, threshold = {}". + format(name, temp, threshold)) + logger.log_error("Thermal critical overheat detected. Rebooting the device.") + self.reboot_device() + + for name, temp, threshold in thermal_info_obj.get_xcvr_critical_overheat_data(): + logger.log_error("XCVR critical overheat: '{}' temperature = {}, threshold = {}".format( + name, temp, threshold)) + +@thermal_json_object('update.cooling.level') +class ThermalCoolLevelUpdateAction(ThermalAction, FanAction): + """ + Action to adjust fan speed according to the current system cooling level. + """ + + def __init__(self): + from .thermal_device_data import DEVICE_DATA + + # Get the list of fan speeds, where each index corresponds to a specific + # cooling level index. + self.cool_lvl_map = DEVICE_DATA['fan_speed'] + + def execute(self, thermal_info_dict): + """ + Adjust the fan speed according to the current system cooling level. + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + fan_info_obj = self.get_fan_info(thermal_info_dict) + if thermal_info_obj and fan_info_obj: + cool_lvl_idx = thermal_info_obj.get_cooling_level_idx() + if cool_lvl_idx in range(len(self.cool_lvl_map)): + for fan in fan_info_obj.get_presence_fans(): + fan.set_speed(self.cool_lvl_map[cool_lvl_idx]) + else: + logger.log_error("Invalid cooling level index: {}".format(cool_lvl_idx)) diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_conditions.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_conditions.py new file mode 100644 index 0000000000..83df89c1c7 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_conditions.py @@ -0,0 +1,130 @@ +from sonic_platform_base.sonic_thermal_control.thermal_condition_base import ThermalPolicyConditionBase +from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +from .thermal import logger + +class FanCondition(ThermalPolicyConditionBase): + def get_fan_info(self, thermal_info_dict): + from .thermal_infos import FanInfo + fan_info_obj = None + if FanInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[FanInfo.INFO_NAME], FanInfo): + fan_info_obj = thermal_info_dict[FanInfo.INFO_NAME] + else: + logger.log_error("Failed to get fans information") + return fan_info_obj + +class ThermalCondition(ThermalPolicyConditionBase): + def get_thermal_info(self, thermal_info_dict): + from .thermal_infos import ThermalInfo + thermal_info_obj = None + if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): + thermal_info_obj = thermal_info_dict[ThermalInfo.INFO_NAME] + else: + logger.log_error("Failed to get thermals information") + return thermal_info_obj + + +@thermal_json_object('fan.any.absence') +class AnyFanAbsenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_absence_fans()) > 0 if fan_info_obj else False + + +@thermal_json_object('fan.all.presence') +class AllFanPresenceCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_absence_fans()) == 0 if fan_info_obj else False + + +@thermal_json_object('fan.any.fault') +class AnyFanFaultCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_fault_fans()) > 0 if fan_info_obj else False + + +@thermal_json_object('fan.all.good') +class AllFanGoodCondition(FanCondition): + def is_match(self, thermal_info_dict): + fan_info_obj = self.get_fan_info(thermal_info_dict) + return len(fan_info_obj.get_fault_fans()) == 0 if fan_info_obj else False + + +@thermal_json_object('thermal.any.warning') +class ThermalWarningCondition(ThermalCondition): + """ + A thermal condition class that checks and indicates whether there is a + thermal warning overheat (chassis or XCVR). + """ + def is_match(self, thermal_info_dict): + result = False + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + result = thermal_info_obj.is_warning_overheat() or thermal_info_obj.is_xcvr_warning_overheat() + return result + + +@thermal_json_object('thermal.any.critical') +class ThermalCriticalCondition(ThermalCondition): + """ + A thermal condition class that checks and indicates whether there is a + thermal critical overheat (chassis or XCVR). + """ + def is_match(self, thermal_info_dict): + result = False + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + result = thermal_info_obj.is_critical_overheat() or thermal_info_obj.is_xcvr_critical_overheat() + return result + + +@thermal_json_object('thermal.any.change') +class ThermalAnyChangeCondition(ThermalCondition, FanCondition): + """ + A thermal condition class that checks and indicates whether there is a + temperature change among the sensors participating in fan speed control logic, + or a fan status change. + """ + def is_match(self, thermal_info_dict): + result = False + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + fan_info_obj = self.get_fan_info(thermal_info_dict) + if thermal_info_obj and fan_info_obj: + tc_temperatures_changed = thermal_info_obj.is_tc_temperatures_changed() + fan_status_changed = fan_info_obj.is_status_changed() + if tc_temperatures_changed or fan_status_changed: + logger.log_info("Thermal status changed, temperatures: {}, fans: {}".format( + thermal_info_obj.get_temperatures(), fan_status_changed)) + result = True + return result + + +@thermal_json_object('thermal.faulty.sensor') +class ThermalFaultySensorCondition(ThermalCondition): + """ + A thermal condition class that checks and indicates whether a faulty temperature + sensor is detected. + """ + def is_match(self, thermal_info_dict): + result = False + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + thermal_list = thermal_info_obj.get_thermal_list() + faulty_sensor_idxs = thermal_info_obj.get_faulty_sensors() + temp_list = thermal_info_obj.get_temperatures() + + if thermal_info_obj.is_faulty_sensor_invalid_detected(): + for idx in faulty_sensor_idxs: + logger.log_error("Thermal faulty sensor detected due to an invalid sample on `{}` sensor: " + "value={}".format(thermal_list[idx].get_name(), temp_list[idx])) + result = True + elif thermal_info_obj.is_faulty_sensor_average_detected(): + avg_temp = thermal_info_obj.get_faulty_average() + avg_temp_list = [temp_list[idx] for idx in thermal_info_obj.AVG_SENSOR_IDX_LIST] + for idx in faulty_sensor_idxs: + logger.log_error("Thermal faulty sensor detected on `{}` sensor due to average deviation: " + "value={}, samples={}, average={}".format( + thermal_list[idx].get_name(), temp_list[idx], avg_temp_list, avg_temp)) + result = True + return result diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_device_data.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_device_data.py new file mode 100644 index 0000000000..d82e71641d --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_device_data.py @@ -0,0 +1,40 @@ +DEVICE_DATA = { + # Threshold definitions: + # The `thresholds` is a list of lists. + # - Each element in the outer list corresponds to a sensor (by index). + # - Each inner list contains threshold pairs for different cooling levels. + # There are five threshold pairs per sensor. Each threshold pair is a string + # containing two values separated by a colon. The first value represents + # the low threshold, and the second represents the high threshold. + # When any sensor exceeds its high threshold, the cooling level for that + # sensor is increased. When the temperature falls below the low threshold, + # the cooling level for that sensor is decreased. Based on this logic, + # the cooling level for each sensor can range from 0 to 5. + # + # Notes: + # - The index order of `thresholds` must align with the sensor instances + # defined in `thermal.py`. + # - A threshold value of 'NA' indicates that the sensor is non-recoverable. + # - Updated threshold pairs for `PCB Top Front` and `PCB Bottom Front` + # ensure that cooling level index 0 corresponds to room temperature, + # equivalent to 38% fan speed (RPM). + 'thresholds': [ + ["00:00", "00:00", "00:00", "65:70", "NA:80"], # 0: PCB VDD_Core + ["19:31", "37:48", "45:53", "56:59", "NA:64"], # 1: PCB FP Hotspot + ["15:24", "25:32", "34:40", "45:48", "NA:53"], # 2: PCB Top Front + ["15:25", "28:37", "36:43", "48:51", "NA:56"], # 3: PCB Bottom Front + ["00:00", "00:00", "00:00", "65:70", "NA:80"], # 4: PCB Bottom Rear + ["00:00", "00:00", "00:00", "65:70", "NA:80"], # 5: PCB OCXO + ["00:00", "00:00", "00:00", "65:70", "NA:80"], # 6: PCB ASIC + ["00:00", "00:00", "00:00", "65:70", "NA:80"], # 7: PCB Top Rear + ["40:51", "54:64", "62:69", "100:108", "NA:115"], # 8: ASIC Temp 1 + ["40:51", "54:64", "62:69", "100:108", "NA:115"], # 9: ASIC Temp 2 + ["40:51", "54:64", "62:69", "100:108", "NA:115"], # 10: ASIC Temp 3 + ["30:45", "48:60", "54:63", "63:66", "NA:71"] # 11: CPU Temp + ], + # List of fan speeds, where each index corresponds to a cooling level index + 'fan_speed': [ + "38", "60", "80", "100", "100", "100" # RPM percentage + ] +} + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_infos.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_infos.py new file mode 100644 index 0000000000..1991adf6c7 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_infos.py @@ -0,0 +1,557 @@ +from sonic_platform_base.sonic_thermal_control.thermal_info_base import ThermalPolicyInfoBase +from sonic_platform_base.sonic_thermal_control.thermal_json_object import thermal_json_object +from .thermal import logger +from enum import Enum + +@thermal_json_object('fan_info') +class FanInfo(ThermalPolicyInfoBase): + """ + Fan information needed by thermal policy + """ + + # Fan information name + INFO_NAME = 'fan_info' + + def __init__(self): + self._absence_fans = set() + self._presence_fans = set() + self._fault_fans = set() + self._status_changed = False + + def collect(self, chassis): + """ + Collect absence and presence fans. + :param chassis: The chassis object + :return: + """ + self._status_changed = False + for fan in chassis.get_all_fans(): + presence = fan.get_presence() + status = fan.get_status() + if presence and fan not in self._presence_fans: + self._presence_fans.add(fan) + self._status_changed = True + if fan in self._absence_fans: + self._absence_fans.remove(fan) + elif not presence and fan not in self._absence_fans: + self._absence_fans.add(fan) + self._status_changed = True + if fan in self._presence_fans: + self._presence_fans.remove(fan) + + if not status and fan not in self._fault_fans: + self._fault_fans.add(fan) + self._status_changed = True + elif status and fan in self._fault_fans: + self._fault_fans.remove(fan) + self._status_changed = True + + def get_absence_fans(self): + """ + Retrieves absence fans + :return: A set of absence fans + """ + return self._absence_fans + + def get_presence_fans(self): + """ + Retrieves presence fans + :return: A set of presence fans + """ + return self._presence_fans + + def get_fault_fans(self): + """ + Retrieves fault fans + :return: A set of fault fans + """ + return self._fault_fans + + def is_status_changed(self): + """ + Retrieves if the status of fan information changed + :return: True if status changed else False + """ + return self._status_changed + + +@thermal_json_object('psu_info') +class PsuInfo(ThermalPolicyInfoBase): + """ + PSU information needed by thermal policy + """ + INFO_NAME = 'psu_info' + + def __init__(self): + self._absence_psus = set() + self._presence_psus = set() + self._status_changed = False + + def collect(self, chassis): + """ + Collect absence and presence PSUs. + :param chassis: The chassis object + :return: + """ + self._status_changed = False + for psu in chassis.get_all_psus(): + if psu.get_presence() and psu.get_powergood_status() and psu not in self._presence_psus: + self._presence_psus.add(psu) + self._status_changed = True + if psu in self._absence_psus: + self._absence_psus.remove(psu) + elif (not psu.get_presence() or not psu.get_powergood_status()) and psu not in self._absence_psus: + self._absence_psus.add(psu) + self._status_changed = True + if psu in self._presence_psus: + self._presence_psus.remove(psu) + + def get_absence_psus(self): + """ + Retrieves presence PSUs + :return: A set of absence PSUs + """ + return self._absence_psus + + def get_presence_psus(self): + """ + Retrieves presence PSUs + :return: A set of presence fans + """ + return self._presence_psus + + def is_status_changed(self): + """ + Retrieves if the status of PSU information changed + :return: True if status changed else False + """ + return self._status_changed + + +@thermal_json_object('thermal_info') +class ThermalInfo(ThermalPolicyInfoBase): + """ + Thermal information needed by thermal policy + """ + from .thermal import Thermal + from .chassis import PORT_END + + # Thermal information name + INFO_NAME = 'thermal_info' + + class CoolingLevel(Enum): + LEVEL_0 = 0 + LEVEL_1 = 1 + LEVEL_2 = 2 + LEVEL_3 = 3 + LEVEL_4 = 4 + LEVEL_5 = 5 + + # Temperature deviation tolerance in degrees Celsius + THERMAL_FAULT_SENSOR_TOLERANCE = 15 + + NUM_CHASSIS_THERMALS = Thermal.NUMBER_OF_THERMALS + NUM_XCVR_THERMALS = PORT_END + NUM_THERMALS = NUM_CHASSIS_THERMALS + NUM_XCVR_THERMALS + + # Indices of `Thermal.py` instances corresponding to PCB temperature sensors. + PCB_SENSOR_IDX_LIST = [0, 1, 2, 3, 4, 5, 6, 7] + # Indices of `Thermal.py` instances corresponding to ASIC temperature sensors. + ASIC_SENSOR_IDX_LIST = [8, 9, 10] + # Indices of `Thermal.py` instances corresponding to CPU temperature sensors. + CPU_SENSOR_IDX_LIST = [11] + + # Indices of `Thermal.py` instances used for detecting faulty sensor by average. + AVG_SENSOR_IDX_LIST = [1, 2, 3] + # Indices of `Thermal.py` instances used for thermal control (fan speed control and overheat detection). + TC_SENSOR_IDX_LIST = AVG_SENSOR_IDX_LIST + ASIC_SENSOR_IDX_LIST + CPU_SENSOR_IDX_LIST + + # Indices of XCVR `Thermal.py` instances, starting after the PCB, ASIC, and CPU sensor indices. + # Note: This list is not used in this file, it is used for testing purposes. + XCVR_SENSOR_IDX_LIST = list(range(NUM_CHASSIS_THERMALS, NUM_THERMALS)) + + class HysteresisMonitor: + """ + A class per sensor to manage and update its hysteresis state + + Attributes: + thresholds: This is a list containing 5 string elements, where each + element follows this format: + "low hysteresis threshold : high hysteresis threshold" + For example: + thresholds = ["19:31", "37:48", "45:53", "56:59", "NA:64"] + parameter value + --------- ----- + low hysteresis threshold 1 19 + high hysteresis threshold 1 31 + low hysteresis threshold 2 37 + high hysteresis threshold 2 48 + low hysteresis threshold 3 45 + high hysteresis threshold 3 53 + low hysteresis threshold 4 56 + high hysteresis threshold 4 59 + low hysteresis threshold 5 NA + high hysteresis threshold 5 64 + """ + LOW_TH_IDX = 0 + HIGH_TH_IDX = 1 + + def __init__(self, thresholds): + self.thresholds = [] + for threshold in thresholds: + low = threshold.split(':')[self.LOW_TH_IDX] + if low != "NA": + low = int(low) + + high = threshold.split(':')[self.HIGH_TH_IDX] + if high != "NA": + high = int(high) + + self.thresholds.append([low, high]) + + self.cool_lvl_idx = 0 + + # Track the current hysteresis state of each instance (True = high hyst, False = low hyst) + self.hyst_state_list = [False] * len(thresholds) + + def get_cool_level(self): + return self.cool_lvl_idx + + def update(self, value): + """Update the hysteresis state based on the new input temperature value + + Args: + value: integer value of the input temperature used to update the hysteresis state + + Returns: + An integer representing the cool level index used to determine the actual fan speed + """ + cool_lvl_idx = 0 + for idx, threshold in enumerate(self.thresholds): + low = threshold[self.LOW_TH_IDX] + high = threshold[self.HIGH_TH_IDX] + + # If the sensor is in the low state and the value crosses the high threshold + if not self.hyst_state_list[idx] and isinstance(high, int) and value > high: + self.hyst_state_list[idx] = True + # If the sensor is in the high state and the value crosses below or equals the low threshold + elif self.hyst_state_list[idx] and isinstance(low, int) and value <= low: + self.hyst_state_list[idx] = False + + # Record the highest index crossed, which represents the cool level + if self.hyst_state_list[idx]: + cool_lvl_idx = idx + 1 + + self.cool_lvl_idx = cool_lvl_idx + return cool_lvl_idx + + def __init__(self): + from .thermal_device_data import DEVICE_DATA + + self._cool_lvl_idx = self.CoolingLevel.LEVEL_0.value + + self._thermal_list = None + self._temp_list = None + + self._tc_temps_changed = False + + self._faulty_sensor_average_detected = False + self._faulty_sensor_invalid_detected = False + self._faulty_sensors = [] + self._faulty_average = None + + self._warn_oh = False + self._warn_oh_data = [] + + self._crit_oh = False + self._crit_oh_data = [] + + self._xcvr_warn_oh = False + self._xcvr_warn_oh_data = [] + + self._xcvr_crit_oh = False + self._xcvr_crit_oh_data = [] + + # Create a list of HysteresisMonitor classes, one per sensor, to track + # the threshold state of each sensor. + self.hyst_monitor_list = [] + for idx in self.TC_SENSOR_IDX_LIST: + self.hyst_monitor_list.append(self.HysteresisMonitor(DEVICE_DATA['thresholds'][idx])) + + def collect(self, chassis): + """ + Collect thermal sensor temperature change status + :param chassis: The chassis object + :return: + """ + self._tc_temps_changed = False + + self._faulty_sensor_average_detected = False + self._faulty_sensor_invalid_detected = False + self._faulty_average = None + + self._warn_oh = False + self._warn_oh_data = [] + + self._crit_oh = False + self._crit_oh_data = [] + + # Collect all thermal class instances and temperature samples + self._thermal_list = chassis.get_all_thermals() + temp_list = [thermal.get_temperature() for thermal in self._thermal_list] + + # Check whether the temperature values used for cooling level calculation have changed + if self._temp_list is None: + self._tc_temps_changed = True + else: + for idx in self.TC_SENSOR_IDX_LIST: + if self._temp_list[idx] != temp_list[idx]: + self._tc_temps_changed = True + + # Detect thermal faulty sensor based on invalid-sample condition + if self._tc_temps_changed: + self._faulty_sensors = [] + for idx in self.TC_SENSOR_IDX_LIST: + if not isinstance(temp_list[idx], float): + self._faulty_sensor_invalid_detected = True + self._faulty_sensors.append(idx) + + if not self._faulty_sensor_invalid_detected and self._tc_temps_changed: + try: + # Determine the maximum cooling level index among all HysteresisMonitor instances + cool_lvl_idx = self.CoolingLevel.LEVEL_0.value + for idx, sensor_idx in enumerate(self.TC_SENSOR_IDX_LIST): + cool_lvl_idx = max(cool_lvl_idx, self.hyst_monitor_list[idx].update(temp_list[sensor_idx])) + + # Log and save the cooling level index + if cool_lvl_idx != self._cool_lvl_idx: + logger.log_notice("Cooling level index has changed from {} to {}".format( + self._cool_lvl_idx, cool_lvl_idx)) + self._cool_lvl_idx = cool_lvl_idx + + # Detect thermal warning/critical overheat + for idx, sensor_idx in enumerate(self.TC_SENSOR_IDX_LIST): + cool_level = self.hyst_monitor_list[idx].get_cool_level() + if cool_level == self.CoolingLevel.LEVEL_5.value: + thermal = self._thermal_list[sensor_idx] + self._crit_oh_data.append((thermal.get_name(), temp_list[sensor_idx], + thermal.get_high_critical_threshold())) + self._crit_oh = True + elif cool_level == self.CoolingLevel.LEVEL_4.value: + thermal = self._thermal_list[sensor_idx] + self._warn_oh_data.append((thermal.get_name(), temp_list[sensor_idx], + thermal.get_high_threshold())) + self._warn_oh = True + except Exception as e: + logger.log_error("Failure in cooling level index calculation: {}".format(str(e))) + + try: + # Detect thermal faulty sensor based on average-value condition + avg_temp_list = [temp_list[idx] for idx in self.AVG_SENSOR_IDX_LIST] + avg_temp = round(sum(avg_temp_list) / len(avg_temp_list), 1) + self._faulty_sensors = [] + for idx in self.AVG_SENSOR_IDX_LIST: + if abs(temp_list[idx] - avg_temp) > self.THERMAL_FAULT_SENSOR_TOLERANCE: + self._faulty_sensor_average_detected = True + self._faulty_sensors.append(idx) + self._faulty_average = avg_temp + except Exception as e: + logger.log_error("Failure in average temperature calculation: {}".format(str(e))) + + self._temp_list = temp_list + + # Evaluate XCVR temperatures against their per-module EEPROM thresholds. + # Each module is evaluated in its own try/except so that a transient + # failure on one port does not prevent evaluation of the remaining ports. + # The outer try/except guards against chassis-level failures (e.g. + # get_all_sfps() raising) so the collect() method always completes. + # + # Fail-safe: if any evaluation fails, the previous overheat state is + # retained (OR'd in) so that a read failure on a module that was + # previously overheating is not misinterpreted as recovery. + prev_xcvr_warn = self._xcvr_warn_oh + prev_xcvr_warn_data = self._xcvr_warn_oh_data[:] + prev_xcvr_crit = self._xcvr_crit_oh + prev_xcvr_crit_data = self._xcvr_crit_oh_data[:] + self._xcvr_warn_oh = False + self._xcvr_warn_oh_data = [] + self._xcvr_crit_oh = False + self._xcvr_crit_oh_data = [] + xcvr_eval_failed = False + try: + for sfp in chassis.get_all_sfps(): + try: + if not sfp.get_presence(): + continue + sfp_thermal = sfp.get_thermal(0) + if sfp_thermal is None: + continue + temp = sfp_thermal.get_temperature() + if not isinstance(temp, (int, float)): + continue + name = sfp_thermal.get_name() + warn_th = sfp_thermal.get_high_threshold() + crit_th = sfp_thermal.get_high_critical_threshold() + if isinstance(crit_th, (int, float)) and temp > crit_th: + self._xcvr_crit_oh = True + self._xcvr_crit_oh_data.append((name, temp, crit_th)) + if isinstance(warn_th, (int, float)) and temp > warn_th: + self._xcvr_warn_oh = True + self._xcvr_warn_oh_data.append((name, temp, warn_th)) + except Exception as e: + xcvr_eval_failed = True + logger.log_error("Failure in XCVR temperature evaluation: {}".format(str(e))) + except Exception as e: + xcvr_eval_failed = True + logger.log_error("Failure in XCVR temperature evaluation: {}".format(str(e))) + + if xcvr_eval_failed: + self._xcvr_warn_oh = self._xcvr_warn_oh or prev_xcvr_warn + self._xcvr_crit_oh = self._xcvr_crit_oh or prev_xcvr_crit + if not self._xcvr_warn_oh_data and prev_xcvr_warn: + self._xcvr_warn_oh_data = prev_xcvr_warn_data + if not self._xcvr_crit_oh_data and prev_xcvr_crit: + self._xcvr_crit_oh_data = prev_xcvr_crit_data + + # Signal state change when XCVR overheat state transitions (onset or + # recovery) so the fan-speed-control policy can recalculate. + if self._xcvr_warn_oh != prev_xcvr_warn or self._xcvr_crit_oh != prev_xcvr_crit: + self._tc_temps_changed = True + + def get_critical_overheat_data(self): + """ + Retrieves a list of (name, temp, threshold) tuples for chassis sensors + that caused the critical overheat. + """ + return self._crit_oh_data + + def is_critical_overheat(self): + """ + Get an indication if a critical overheat condition has occurred. + :return: True if a critical overheat was detected, otherwise False + """ + return self._crit_oh + + def get_warning_overheat_data(self): + """ + Retrieves a list of (name, temp, threshold) tuples for chassis sensors + that caused the warning overheat. + """ + return self._warn_oh_data + + def is_warning_overheat(self): + """ + Get an indication if a warning overheat condition has occurred. + :return: True if a warning overheat was detected, otherwise False + """ + return self._warn_oh + + def is_xcvr_warning_overheat(self): + """ + Get an indication if an XCVR warning overheat condition has occurred. + :return: True if an XCVR warning overheat was detected, otherwise False + """ + return self._xcvr_warn_oh + + def get_xcvr_warning_overheat_data(self): + """ + Retrieves a list of (name, temp, threshold) tuples for XCVR modules + that exceeded their warning threshold. + """ + return self._xcvr_warn_oh_data + + def is_xcvr_critical_overheat(self): + """ + Get an indication if an XCVR critical overheat condition has occurred. + :return: True if an XCVR critical overheat was detected, otherwise False + """ + return self._xcvr_crit_oh + + def get_xcvr_critical_overheat_data(self): + """ + Retrieves a list of (name, temp, threshold) tuples for XCVR modules + that exceeded their critical threshold. + """ + return self._xcvr_crit_oh_data + + def is_tc_temperatures_changed(self): + """ + Get an indication of whether thermal sensor samples have changed among + the sensors involved in the fan speed control logic. + :return: True if any temperatures have changed, otherwise False + """ + return self._tc_temps_changed + + def get_thermal_list(self): + """ + Retrieves a list of thermal. + :return: List of thermal class instances. + """ + return self._thermal_list + + def get_temperatures(self): + """ + Retrieves a list of all temperature samples. + :return: List of all temperature samples. + """ + return self._temp_list + + def get_cooling_level_idx(self): + """ + Retrieves the cooling level index. + :return: Integer of cooling level index. + """ + return self._cool_lvl_idx + + def is_faulty_sensor_invalid_detected(self): + """ + Get an indication if a faulty sensor has been detected based on invalid-sample condition. + :return: True if a faulty sensor is found, otherwise False + """ + return self._faulty_sensor_invalid_detected + + def is_faulty_sensor_average_detected(self): + """ + Get an indication if a faulty sensor has been detected based on average-value condition. + :return: True if a faulty sensor is found, otherwise False + """ + return self._faulty_sensor_average_detected + + def get_faulty_sensors(self): + """ + Retrieves a list of all faulty sensor indices. + :return: List of all faulty sensor indices. + """ + return self._faulty_sensors + + def get_faulty_average(self): + """ + Retrieves the average temperature of the faulty sensors. + :return: The average temperature of the faulty sensors. + """ + return self._faulty_average + +@thermal_json_object('chassis_info') +class ChassisInfo(ThermalPolicyInfoBase): + """ + Chassis information needed by thermal policy + """ + INFO_NAME = 'chassis_info' + + def __init__(self): + self._chassis = None + + def collect(self, chassis): + """ + Collect platform chassis. + :param chassis: The chassis object + :return: + """ + self._chassis = chassis + + def get_chassis(self): + """ + Retrieves platform chassis object + :return: A platform chassis object. + """ + return self._chassis diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_manager.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_manager.py new file mode 100644 index 0000000000..eaf601b532 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/thermal_manager.py @@ -0,0 +1,96 @@ +from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase +from .helper import APIHelper +from sonic_platform.thermal import logger +from .thermal_actions import * +from .thermal_conditions import * +from .thermal_infos import * + +CPLD_I2C_PATH = "/sys/bus/i2c/devices/10-0066/fan" +FAN_LED_MODE = CPLD_I2C_PATH + "_led_mode" + +TC_INTERVAL_SEC = 30 +WD_TIMEOUT = TC_INTERVAL_SEC * 2 + +class ThermalManager(ThermalManagerBase): + + # Override default thermal control interval + _interval = TC_INTERVAL_SEC + + @classmethod + def initialize(cls): + """ + Initialize thermal manager, including register thermal condition types and thermal action types + and any other vendor specific initialization. + :return: + """ + cls._api_helper = APIHelper() + + # Prevent the "Policy {} already exists" exception when reloading the JSON configuration + # file via thermalctld's call to `load` in `thermal_manager.py`` by deleting all existing policies. + # This was done to reload all thermal control configurations during instantiation + # of `ThermalControlDaemon` in each thermal control test run. + cls._policy_dict = {} + + cls._api_helper.write_txt_file(FAN_LED_MODE, 0) # Disable LED debug mode + + @classmethod + def init_thermal_algorithm(cls, chassis): + """ + Initialize thermal algorithm according to policy file. + :param chassis: The chassis object. + :return: + """ + cls._chassis = chassis + + # Enable fan watchdog and set its initial timeout to twice the thermal control interval + cls.fan_watchdog = chassis.get_fan_watchdog() + if cls.fan_watchdog: + cls.fan_watchdog.arm(WD_TIMEOUT) + else: + logger.log_error("Failed to get fan watchdog") + + # Align 'sensors' command thresholds with thermal control thresholds + from .thermal_device_data import DEVICE_DATA + from sonic_platform import thermal_infos + LOW_TH_IDX = 0 + HIGH_TH_IDX = 1 + for idx in thermal_infos.ThermalInfo.PCB_SENSOR_IDX_LIST: + thermal = chassis.get_thermal(idx) + threshs_list = DEVICE_DATA['thresholds'][idx] + thresh_list = threshs_list[len(threshs_list) - 2].split(':') + low_thresh = int(thresh_list[LOW_TH_IDX]) * 1000 + high_thresh = int(thresh_list[HIGH_TH_IDX]) * 1000 + cls._api_helper.write_txt_file(thermal.hwmon_path + "temp1_max", high_thresh) + cls._api_helper.write_txt_file(thermal.hwmon_path + "temp1_max_hyst", low_thresh) + + # Call the base implementation + super().init_thermal_algorithm(chassis) + + @classmethod + def run_policy(cls, chassis): + """ + Collect thermal information, run each policy, if one policy matches, execute the policy's action. + :param chassis: The chassis object. + :return: + """ + if cls.fan_watchdog: + cls.fan_watchdog.arm(WD_TIMEOUT) + + # Call the base implementation + super().run_policy(chassis) + + @classmethod + def deinitialize(cls): + """ + Destroy thermal manager, including any vendor specific cleanup. The default behavior of this function + is a no-op. + :return: + """ + if cls._chassis: + for fan in cls._chassis.get_all_fans(): + fan.set_speed(100) + + if cls.fan_watchdog: + cls.fan_watchdog.disarm() + + cls._api_helper.write_txt_file(FAN_LED_MODE, 1) # Enable LED debug mode diff --git a/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/watchdog.py b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/watchdog.py new file mode 100644 index 0000000000..6bb89737ed --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/sonic_platform/watchdog.py @@ -0,0 +1,200 @@ +""" +Module contains an implementation of SONiC Platform Base API and +provides access to hardware watchdog +""" + +import os +import fcntl +import array +import time +from sonic_platform_base.watchdog_base import WatchdogBase +from sonic_py_common import logger +from .helper import APIHelper + +""" ioctl constants """ +IO_READ = 0x80000000 +IO_SIZE_INT = 0x00040000 +IO_READ_WRITE = 0xC0000000 +IO_TYPE_WATCHDOG = ord('W') << 8 + +WDR_INT = IO_READ | IO_SIZE_INT | IO_TYPE_WATCHDOG +WDWR_INT = IO_READ_WRITE | IO_SIZE_INT | IO_TYPE_WATCHDOG + +""" Watchdog ioctl commands """ +WDIOC_SETOPTIONS = 4 | WDR_INT +WDIOC_KEEPALIVE = 5 | WDR_INT +WDIOC_SETTIMEOUT = 6 | WDWR_INT +WDIOC_GETTIMEOUT = 7 | WDR_INT +WDIOC_GETTIMELEFT = 10 | WDR_INT + +""" Watchdog status constants """ +WDIOS_DISABLECARD = 0x0001 +WDIOS_ENABLECARD = 0x0002 + +""" watchdog sysfs """ +WD_SYSFS_PATH = "/sys/class/watchdog/watchdog0/" + +WD_COMMON_ERROR = -1 + +sonic_logger = logger.Logger() + + +class WatchdogImplBase(WatchdogBase): + """ + Base class that implements common logic for interacting + with watchdog using ioctl commands + """ + + def __init__(self, wd_device_path): + """ + Open a watchdog handle + @param wd_device_path Path to watchdog device + """ + super(WatchdogImplBase, self).__init__() + + self.watchdog_path = wd_device_path + self._watchdog = None + self._api_helper = APIHelper() + self.timeout = self._gettimeout() + + @property + def watchdog(self): + if self._watchdog is None: + self._watchdog = self.open_handle() + return self._watchdog + + def open_handle(self): + return os.open(self.watchdog_path, os.O_WRONLY) + + def __del__(self): + """ + Close watchdog + """ + + if self._watchdog is not None: + os.close(self._watchdog) + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False + if not + """ + sonic_logger.log_info(" Debug disarm watchdog ") + + if self.is_armed(): + os.popen("systemctl stop watchdog-control.service") + time.sleep(2) + + try: + self._disablewatchdog() + self.timeout = 0 + except IOError: + return False + + return True + + def _disablewatchdog(self): + """ + Turn off the watchdog timer + """ + + req = array.array('h', [WDIOS_DISABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + 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): + """ + Get watchdog timeout + @return watchdog timeout + """ + + file_path = WD_SYSFS_PATH + 'timeout' + val = self._api_helper.read_txt_file(file_path) + return int(val) if val is not None else 0 + + def _gettimeleft(self): + """ + Get time left before watchdog timer expires + @return time left in seconds + """ + + file_path = WD_SYSFS_PATH + 'timeleft' + val = self._api_helper.read_txt_file(file_path) + return int(val) if val is not None else 0 + + + def arm(self, seconds): + """ + Implements arm WatchdogBase API + """ + sonic_logger.log_info(" Debug arm watchdog4 ") + ret = WD_COMMON_ERROR + if seconds < 0: + return ret + if seconds > 340: + return ret + + # Stop the watchdog service to gain access of watchdog file pointer + if self.is_armed(): + os.popen("systemctl stop watchdog-control.service") + time.sleep(2) + + try: + if self.timeout != seconds: + self.timeout = self._settimeout(seconds) + if self.is_armed(): + self._keepalive() + else: + self._enablewatchdog() + ret = self.timeout + except IOError: + pass + + return ret + + def _enablewatchdog(self): + """ + Turn on the watchdog timer + """ + + req = array.array('h', [WDIOS_ENABLECARD]) + fcntl.ioctl(self.watchdog, WDIOC_SETOPTIONS, req, False) + + def _keepalive(self): + """ + Keep alive watchdog timer + """ + + fcntl.ioctl(self.watchdog, WDIOC_KEEPALIVE) + + def is_armed(self): + """ + Implements is_armed WatchdogBase API + """ + + file_path = WD_SYSFS_PATH + 'state' + return self._api_helper.read_txt_file(file_path) == 'active' + + def get_remaining_time(self): + """ + Implements get_remaining_time WatchdogBase API + """ + if self.is_armed(): + return self._gettimeleft() + else: + return -1 + diff --git a/device/accton/x86_64-accton_as9647_32d-r0/system_health_monitoring_config.json b/device/accton/x86_64-accton_as9647_32d-r0/system_health_monitoring_config.json new file mode 100644 index 0000000000..38ba88716a --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/system_health_monitoring_config.json @@ -0,0 +1,11 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": ["psu.temperature", "asic"], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "STATUS_LED_COLOR_AMBER", + "normal": "STATUS_LED_COLOR_GREEN", + "booting": "STATUS_LED_COLOR_GREEN_BLINK" + } +} diff --git a/device/accton/x86_64-accton_as9647_32d-r0/thermal_policy.json b/device/accton/x86_64-accton_as9647_32d-r0/thermal_policy.json new file mode 100644 index 0000000000..60d3710b65 --- /dev/null +++ b/device/accton/x86_64-accton_as9647_32d-r0/thermal_policy.json @@ -0,0 +1,137 @@ +{ + "thermal_control_algorithm": { + "run_at_boot_up": "true", + "fan_speed_when_suspend": "50" + }, + "info_types": [ + { + "type": "fan_info" + }, + { + "type": "psu_info" + }, + { + "type": "thermal_info" + }, + { + "type": "chassis_info" + } + ], + "policies": [ + { + "name": "fan speed control", + "conditions": [ + { + "type": "thermal.any.change" + } + ], + "actions": [ + { + "type": "update.cooling.level" + } + ] + }, + { + "name": "thermal warning overheat", + "conditions": [ + { + "type": "thermal.any.warning" + } + ], + "actions": [ + { + "type": "fan.all.set_speed", + "speed": "100" + }, + { + "type": "thermal.warning.overheat" + } + ] + }, + { + "name": "thermal critical overheat", + "conditions": [ + { + "type": "thermal.any.critical" + } + ], + "actions": [ + { + "type": "fan.all.set_speed", + "speed": "100" + }, + { + "type": "thermal.critical.overheat" + } + ] + }, + { + "name": "any fan absence", + "conditions": [ + { + "type": "fan.any.absence" + } + ], + "actions": [ + { + "type": "thermal_control.control", + "status": "false" + }, + { + "type": "fan.all.set_speed", + "speed": "100" + } + ] + }, + { + "name": "any fan broken", + "conditions": [ + { + "type": "fan.any.fault" + } + ], + "actions": [ + { + "type": "thermal_control.control", + "status": "false" + }, + { + "type": "fan.all.set_speed", + "speed": "100" + } + ] + }, + { + "name": "thermal faulty sensor", + "conditions": [ + { + "type": "thermal.faulty.sensor" + } + ], + "actions": [ + { + "type": "fan.all.set_speed", + "speed": "100" + } + ] + }, + { + "name": "all fans are present and good", + "conditions": [ + { + "type": "fan.all.presence" + }, + { + "type": "fan.all.good" + } + ], + "actions": [ + { + "type": "thermal_control.control", + "status": "true" + } + ] + } + ] +} + diff --git a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/chassis.py b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/chassis.py index 950b2ec596..b8e6fc2732 100644 --- a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/chassis.py +++ b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/chassis.py @@ -91,14 +91,6 @@ def __initialize_components(self): def __is_host(self): return os.system(HOST_CHK_CMD) == 0 - def __read_txt_file(self, file_path): - try: - with open(file_path, 'r') as fd: - return fd.read().strip() - except IOError: - pass - return None - def get_name(self): """ Retrieves the name of the device diff --git a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/component.py b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/component.py index 2a479a36e4..72972d7aa1 100644 --- a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/component.py +++ b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/component.py @@ -48,22 +48,6 @@ def __init__(self, component_index=0): self.index = component_index self.name = self.get_name() - def __run_command(self, command): - # Run bash command and print output to stdout - try: - process = subprocess.Popen( - shlex.split(command), stdout=subprocess.PIPE) - while True: - output = process.stdout.readline() - if output == '' and process.poll() is not None: - break - rc = process.poll() - if rc != 0: - return False - except Exception: - return False - return True - def __get_bios_version(self): # Retrieves the BIOS firmware version try: diff --git a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/eeprom.py b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/eeprom.py index 1b78ba83cd..06d73a08b7 100644 --- a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/eeprom.py +++ b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/eeprom.py @@ -2,10 +2,7 @@ import os import sys import re - if sys.version_info[0] >= 3: - from io import StringIO - else: - from cStringIO import StringIO + from io import StringIO from sonic_platform_base.sonic_eeprom import eeprom_tlvinfo except ImportError as e: diff --git a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/helper.py b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/helper.py index bfde50b4af..52c91fba20 100644 --- a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/helper.py +++ b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/helper.py @@ -1,8 +1,6 @@ import os import shlex -import struct import subprocess -from mmap import * from sonic_py_common import device_info HOST_CHK_CMD = "docker > /dev/null 2>&1" @@ -17,18 +15,8 @@ def __init__(self): def is_host(self): return os.system(HOST_CHK_CMD) == 0 - def pci_get_value(self, resource, offset): - status = True - result = "" - try: - fd = os.open(resource, os.O_RDWR) - mm = mmap(fd, 0) - mm.seek(int(offset)) - read_data_stream = mm.read(4) - result = struct.unpack('I', read_data_stream) - except Exception: - status = False - return status, result + def is_sonic(self): + return os.path.exists("/etc/sonic/config_db.json") def run_command(self, cmd): status = True @@ -47,14 +35,6 @@ def run_command(self, cmd): status = False return status, result - def run_interactive_command(self, cmd): - try: - args = shlex.split(cmd) - subprocess.run(args, check=True) - except Exception: - return False - return True - def read_txt_file(self, file_path): try: with open(file_path, 'r') as fd: diff --git a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/utils.py b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/utils.py deleted file mode 100644 index 6e500a0e33..0000000000 --- a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/utils.py +++ /dev/null @@ -1,40 +0,0 @@ -from sonic_py_common import device_info -from sonic_py_common.logger import Logger - -logger = Logger() - - -def fread(file_path, target_type, default='', raise_exception=False, log_func=logger.log_error): - """ - Read content from file and convert to target type - """ - try: - with open(file_path, 'r') as f: - value = f.read() - if value is None: - raise ValueError('File content of {} is None'.format(file_path)) - else: - value = target_type(value.strip()) - except (ValueError, IOError) as e: - if log_func: - log_func('Failed to read from file {} - {}'.format(file_path, repr(e))) - if not raise_exception: - value = default - else: - raise e - - return value - - -def fread_str(file_path, default='', raise_exception=False, log_func=logger.log_error): - """ - Read string content from file - """ - return fread(file_path=file_path, target_type=str, default=default, raise_exception=raise_exception, log_func=log_func) - - -def fread_int(file_path, default=0, raise_exception=False, log_func=logger.log_error): - """ - Read content from file and cast it to integer - """ - return fread(file_path=file_path, target_type=int, default=default, raise_exception=raise_exception, log_func=log_func) diff --git a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/watchdog.py b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/watchdog.py index 58a1d0749e..8303d3bac8 100644 --- a/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/watchdog.py +++ b/device/accton/x86_64-accton_es9618xx-r0/sonic_platform/watchdog.py @@ -11,7 +11,7 @@ import time from sonic_platform_base.watchdog_base import WatchdogBase from sonic_py_common import logger -from . import utils +from .helper import APIHelper """ ioctl constants """ IO_READ = 0x80000000 @@ -56,6 +56,7 @@ def __init__(self, wd_device_path): self.watchdog_path = wd_device_path self._watchdog = None + self._api_helper = APIHelper() self.timeout = self._gettimeout() @property @@ -124,7 +125,8 @@ def _gettimeout(self): """ file_path = WD_SYSFS_PATH + 'timeout' - return utils.fread_int(file_path) + val = self._api_helper.read_txt_file(file_path) + return int(val) if val is not None else 0 def _gettimeleft(self): """ @@ -133,7 +135,8 @@ def _gettimeleft(self): """ file_path = WD_SYSFS_PATH + 'timeleft' - return utils.fread_int(file_path) + val = self._api_helper.read_txt_file(file_path) + return int(val) if val is not None else 0 def arm(self, seconds): @@ -186,7 +189,7 @@ def is_armed(self): """ file_path = WD_SYSFS_PATH + 'state' - return utils.fread_str(file_path) == 'active' + return self._api_helper.read_txt_file(file_path) == 'active' def get_remaining_time(self): """ diff --git a/platform/xsight/files/xlx/start.sh b/platform/xsight/files/xlx/start.sh index 7b712b1998..5a60e887d6 100755 --- a/platform/xsight/files/xlx/start.sh +++ b/platform/xsight/files/xlx/start.sh @@ -47,7 +47,7 @@ fname=$(basename $0) # sonic systemd-udevd[380]: eth1: Failed to rename network interface 3 from 'eth1' to 'eth0': File exists # sonic kernel: ice 0000:f4:00.0 eth10g0: renamed from eth0 # As a workaround, we reload the igb driver when the eth0 was busy during the igb probe. -if [[ ${ONIE_MACHINE,,} == *"es9618"* ]]; then +if [[ ${ONIE_MACHINE,,} == *"es9618"* || ${ONIE_MACHINE,,} == *"as9647"* ]]; then out=$(ip a l eth0 | grep "UP") res=$? echo "$fname: eth0 link UP check result=$res, output=$out" | tee /dev/kmsg @@ -123,7 +123,11 @@ if [[ ${ONIE_MACHINE,,} != *"kvm"* ]]; then XPLT_SWITCH_CHIP_RESET=$XPLT_UTL/es9632x_reset_x1.sh elif [[ "${XSIGHT_DEVICE}" == "X2" ]]; then sleep 12 - XPLT_SWITCH_CHIP_RESET=$XPLT_UTL/es9618x_reset_x2.sh + if [[ ${ONIE_MACHINE,,} == *"es9618"* ]]; then + XPLT_SWITCH_CHIP_RESET=$XPLT_UTL/es9618x_reset_x2.sh + else + XPLT_SWITCH_CHIP_RESET=$XPLT_UTL/reset_x2.sh + fi fi # Reset switch chip and PCI bus diff --git a/platform/xsight/one-image.mk b/platform/xsight/one-image.mk index 3c0476b7de..b1da1baa73 100644 --- a/platform/xsight/one-image.mk +++ b/platform/xsight/one-image.mk @@ -5,7 +5,9 @@ $(SONIC_ONE_IMAGE)_MACHINE = xsight $(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie $(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) $(XPCI) $(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(ACCTON_ES9618XX_PLATFORM_MODULE) \ - $(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE) + $(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE) \ + $(ACCTON_AS9647_32D_PLATFORM_MODULE) \ + $(ACCTON_AS9647_32D_XPLT_PLATFORM_MODULE) ifeq ($(INSTALL_DEBUG_TOOLS),y) $(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) diff --git a/platform/xsight/platform-modules-accton.mk b/platform/xsight/platform-modules-accton.mk index 0d47a50833..772a644af4 100755 --- a/platform/xsight/platform-modules-accton.mk +++ b/platform/xsight/platform-modules-accton.mk @@ -1,7 +1,9 @@ # Accton Platform modules ACCTON_ES9618XX_PLATFORM_MODULE_VERSION = 1.1 +ACCTON_AS9647_32D_PLATFORM_MODULE_VERSION = 1.1 export ACCTON_ES9618XX_PLATFORM_MODULE_VERSION +export ACCTON_AS9647_32D_PLATFORM_MODULE_VERSION ACCTON_ES9618XX_PLATFORM_MODULE = sonic-platform-accton-es9618xx_$(ACCTON_ES9618XX_PLATFORM_MODULE_VERSION)_amd64.deb $(ACCTON_ES9618XX_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-accton @@ -10,3 +12,7 @@ $(ACCTON_ES9618XX_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_C SONIC_DPKG_DEBS += $(ACCTON_ES9618XX_PLATFORM_MODULE) +ACCTON_AS9647_32D_PLATFORM_MODULE = sonic-platform-accton-as9647-32d_$(ACCTON_AS9647_32D_PLATFORM_MODULE_VERSION)_amd64.deb +$(ACCTON_AS9647_32D_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9647_32d-r0 +$(eval $(call add_extra_package,$(ACCTON_ES9618XX_PLATFORM_MODULE),$(ACCTON_AS9647_32D_PLATFORM_MODULE))) + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/classes/__init__.py b/platform/xsight/sonic-platform-modules-accton/as9647-32d/classes/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g0.link b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g0.link new file mode 100644 index 0000000000..01b9c61cba --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g0.link @@ -0,0 +1,7 @@ +[Match] +Type=ether +Path=pci-0000:f4:00.0 + +[Link] +Name=eth10g0 +MACAddressPolicy=persistent diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g1.link b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g1.link new file mode 100644 index 0000000000..f037401422 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g1.link @@ -0,0 +1,7 @@ +[Match] +Type=ether +Path=pci-0000:f4:00.1 + +[Link] +Name=eth10g1 +MACAddressPolicy=persistent diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g2.link b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g2.link new file mode 100644 index 0000000000..f67815c83b --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g2.link @@ -0,0 +1,7 @@ +[Match] +Type=ether +Path=pci-0000:f4:00.2 + +[Link] +Name=eth10g2 +MACAddressPolicy=persistent diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g3.link b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g3.link new file mode 100644 index 0000000000..25538c9aae --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth10g3.link @@ -0,0 +1,7 @@ +[Match] +Type=ether +Path=pci-0000:f4:00.3 + +[Link] +Name=eth10g3 +MACAddressPolicy=persistent diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth1g0.link b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth1g0.link new file mode 100644 index 0000000000..5b0a475376 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth1g0.link @@ -0,0 +1,8 @@ +[Match] +Type=ether +Path=pci-0000:03:00.0 +Property=ID_MODEL_ID=0x1533 + +[Link] +Name=eth0 +MACAddressPolicy=persistent diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth1g1.link b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth1g1.link new file mode 100644 index 0000000000..ac9714574a --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/files/link/70-xsight-eth1g1.link @@ -0,0 +1,8 @@ +[Match] +Type=ether +Path=pci-0000:04:00.0 +Property=ID_MODEL_ID=0x1533 + +[Link] +Name=eth1 +MACAddressPolicy=persistent diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/Makefile b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/Makefile new file mode 100644 index 0000000000..514e07bf9c --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/Makefile @@ -0,0 +1,17 @@ +ifneq ($(KERNELRELEASE),) +obj-m += x86-64-as9647-32d-cpld.o \ + x86-64-as9647-32d-fan.o x86-64-as9647-32d-leds.o \ + x86-64-as9647-32d-psu.o dps850.o +else +ifeq (,$(KERNEL_SRC)) +$(error KERNEL_SRC is not defined) +else +KERNELDIR:=$(KERNEL_SRC) +endif +PWD:=$(shell pwd) +default: + $(MAKE) -C $(KERNELDIR) M=$(PWD) modules +clean: + rm -rf *.o *.mod.o *.mod.o *.ko .*cmd .tmp_versions Module.markers Module.symvers modules.order +endif + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/dps850.c b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/dps850.c new file mode 100644 index 0000000000..ff22dee2d2 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/dps850.c @@ -0,0 +1,515 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * An hwmon driver for the Delta DPS-850AB-4 Power Module + * + * Copyright (C) 2017 Accton Technology Corporation. + * Brandon Chuang + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +enum chips { + DPS850 +}; + +/* Each client has this additional data + */ +struct dps850_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 chip; /* chip id */ + u8 vout_mode; /* Register value */ + u16 v_in; /* Register value */ + u16 v_out; /* Register value */ + u16 i_in; /* Register value */ + u16 i_out; /* Register value */ + u16 p_in; /* Register value */ + u16 p_out; /* Register value */ + u16 temp_input[3]; /* Register value */ + u16 fan_speed; /* Register value */ + u8 mfr_model[16]; /* Register value */ + u8 mfr_serial[16]; /* Register value */ +}; + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf); +static struct dps850_data *dps850_update_device(struct device *dev); +static int dps850_write_word(struct i2c_client *client, u8 reg, u16 value); + +enum dps850_sysfs_attributes { + PSU_V_IN, + PSU_V_OUT, + PSU_I_IN, + PSU_I_OUT, + PSU_P_IN, + PSU_P_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_FAN1_SPEED, + PSU_MFR_MODEL, + PSU_MFR_SERIAL +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_v_in, S_IRUGO, show_linear, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(psu_v_out,S_IRUGO, show_vout_by_mode,NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(psu_i_in, S_IRUGO, show_linear, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(psu_i_out,S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(psu_p_in, S_IRUGO, show_linear, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(psu_p_out,S_IRUGO, show_linear, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(psu_temp1_input, S_IRUGO, show_linear, NULL, PSU_TEMP1_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp2_input, S_IRUGO, show_linear, NULL, PSU_TEMP2_INPUT); +static SENSOR_DEVICE_ATTR(psu_temp3_input, S_IRUGO, show_linear, NULL, PSU_TEMP3_INPUT); +static SENSOR_DEVICE_ATTR(psu_fan1_speed_rpm, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); +static SENSOR_DEVICE_ATTR(psu_mfr_model, S_IRUGO, show_ascii, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(psu_mfr_serial, S_IRUGO, show_ascii, NULL, PSU_MFR_SERIAL); + +static struct attribute *dps850_attributes[] = { + &sensor_dev_attr_psu_v_out.dev_attr.attr, + &sensor_dev_attr_psu_i_out.dev_attr.attr, + &sensor_dev_attr_psu_p_out.dev_attr.attr, + &sensor_dev_attr_psu_v_in.dev_attr.attr, + &sensor_dev_attr_psu_i_in.dev_attr.attr, + &sensor_dev_attr_psu_p_in.dev_attr.attr, + &sensor_dev_attr_psu_temp1_input.dev_attr.attr, + &sensor_dev_attr_psu_temp2_input.dev_attr.attr, + &sensor_dev_attr_psu_temp3_input.dev_attr.attr, + &sensor_dev_attr_psu_fan1_speed_rpm.dev_attr.attr, + &sensor_dev_attr_psu_mfr_model.dev_attr.attr, + &sensor_dev_attr_psu_mfr_serial.dev_attr.attr, + NULL +}; + +static int two_complement_to_int(u16 data, u8 valid_bit, int mask) +{ + u16 valid_data = data & mask; + bool is_negative = valid_data >> (valid_bit - 1); + + return is_negative ? (-(((~valid_data) & mask) + 1)) : valid_data; +} + +static ssize_t show_linear(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct dps850_data *data = dps850_update_device(dev); + + u16 value = 0; + int exponent, mantissa; + int multiplier = 1000; + + if (!data->valid) { + return 0; + } + + switch (attr->index) { + case PSU_V_IN: + value = data->v_in; + break; + case PSU_I_IN: + value = data->i_in; + break; + case PSU_I_OUT: + value = data->i_out; + break; + case PSU_P_IN: + value = data->p_in; + break; + case PSU_P_OUT: + value = data->p_out; + break; + case PSU_TEMP1_INPUT: + case PSU_TEMP2_INPUT: + case PSU_TEMP3_INPUT: + value = data->temp_input[attr->index-PSU_TEMP1_INPUT]; + break; + case PSU_FAN1_SPEED: + value = data->fan_speed; + multiplier = 1; + break; + } + + exponent = two_complement_to_int(value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(value & 0x7ff, 11, 0x7ff); + + return (exponent >= 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static ssize_t show_ascii(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct dps850_data *data = dps850_update_device(dev); + u8 *ptr = NULL; + + if (!data->valid) { + return 0; + } + + switch (attr->index) { + case PSU_MFR_MODEL: /* psu_mfr_model */ + ptr = data->mfr_model + 1; /* The first byte is the length of string. */ + break; + case PSU_MFR_SERIAL: /* psu_mfr_serial */ + ptr = data->mfr_serial + 1; /* The first byte is the length of string. */ + break; + default: + return 0; + } + + return sprintf(buf, "%s\n", ptr); +} + +static ssize_t show_vout_by_mode(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct dps850_data *data = dps850_update_device(dev); + int exponent, mantissa; + int multiplier = 1000; + + if (!data->valid) { + return 0; + } + + exponent = two_complement_to_int(data->vout_mode, 5, 0x1f); + mantissa = data->v_out; + + return (exponent > 0) ? sprintf(buf, "%d\n", (mantissa << exponent) * multiplier) : + sprintf(buf, "%d\n", (mantissa * multiplier) / (1 << -exponent)); +} + +static const struct attribute_group dps850_group = { + .attrs = dps850_attributes, +}; + +static int dps850_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct dps850_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct dps850_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->chip = dev_id->driver_data; + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &dps850_group); + if (status) { + goto exit_free; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,9,0) + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, "dps850", + NULL, NULL, NULL); +#else + data->hwmon_dev = hwmon_device_register(&client->dev); +#endif + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &dps850_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int dps850_remove(struct i2c_client *client) +{ + struct dps850_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &dps850_group); + kfree(data); + + return 0; +} + +static const struct i2c_device_id dps850_id[] = { + { "dps850", DPS850 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, dps850_id); + +static struct i2c_driver dps850_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "dps850", + }, + .probe = dps850_probe, + .remove = dps850_remove, + .id_table = dps850_id, + .address_list = normal_i2c, +}; + +static int dps850_read_byte(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int dps850_read_word(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_word_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int dps850_write_word(struct i2c_client *client, u8 reg, u16 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_word_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int dps850_read_block(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_i2c_block_data(client, command, data_len, data); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +struct reg_data_byte { + u8 reg; + u8 *value; +}; + +struct reg_data_word { + u8 reg; + u16 *value; +}; + +static struct dps850_data *dps850_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct dps850_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int i, status, length; + u8 command, buf; + struct reg_data_byte regs_byte[] = { {0x20, &data->vout_mode}}; + struct reg_data_word regs_word[] = { {0x88, &data->v_in}, + {0x8b, &data->v_out}, + {0x89, &data->i_in}, + {0x8c, &data->i_out}, + {0x96, &data->p_out}, + {0x97, &data->p_in}, + {0x8d, &(data->temp_input[0])}, + {0x8e, &(data->temp_input[1])}, + {0x8f, &(data->temp_input[2])}, + {0x90, &data->fan_speed}}; + + dev_dbg(&client->dev, "Starting dps850 update\n"); + data->valid = 0; + + /* Read byte data */ + for (i = 0; i < ARRAY_SIZE(regs_byte); i++) { + status = dps850_read_byte(client, regs_byte[i].reg); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_byte[i].reg, status); + goto exit; + } + else { + *(regs_byte[i].value) = status; + } + } + + /* Read word data */ + for (i = 0; i < ARRAY_SIZE(regs_word); i++) { + status = dps850_read_word(client, regs_word[i].reg); + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", + regs_word[i].reg, status); + goto exit; + } + else { + *(regs_word[i].value) = status; + } + } + + /* Read mfr_model */ + command = 0x9a; + length = 1; + memset(data->mfr_model, 0, sizeof(data->mfr_model)); + + /* Read first byte to determine the length of data */ + status = dps850_read_block(client, command, &buf, length); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + status = dps850_read_block(client, command, data->mfr_model, buf+1); + data->mfr_model[buf+1] = '\0'; + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + /* Read mfr_serial */ + command = 0x9e; + length = 1; + memset(data->mfr_serial, 0, sizeof(data->mfr_serial)); + + /* Read first byte to determine the length of data */ + status = dps850_read_block(client, command, &buf, length); + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + status = dps850_read_block(client, command, data->mfr_serial, buf+1); + data->mfr_serial[buf+1] = '\0'; + + if (status < 0) { + dev_dbg(&client->dev, "reg %d, err %d\n", command, status); + goto exit; + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + mutex_unlock(&data->update_lock); + + return data; +} + +static int __init dps850_init(void) +{ + return i2c_add_driver(&dps850_driver); +} + +static void __exit dps850_exit(void) +{ + i2c_del_driver(&dps850_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("DELTA DPS-850AB driver"); +MODULE_LICENSE("GPL"); + +module_init(dps850_init); +module_exit(dps850_exit); + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-cpld.c b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-cpld.c new file mode 100644 index 0000000000..7d910ae28a --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-cpld.c @@ -0,0 +1,887 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2025 Accton Technology Corporation. + * Phani Karanam + * + * This module supports the accton cpld that hold the channel select + * mechanism for other i2c slave devices, such as SFP. + * This includes the: + * Accton as9647_32d CPLD1/CPLD2/CPLD3 + * + * Based on: + * es9632xx-cpld.c from Brandon Chuang + * Copyright (C) 2016 Accton Technology Corporation. + * + * Based on: + * pca954x.c from Kumar Gala + * Copyright (C) 2006 + * + * Based on: + * pca954x.c from Ken Harrenstien + * Copyright (C) 2004 Google, Inc. (Ken Harrenstien) + * + * Based on: + * i2c-virtual_cb.c from Brian Kuschak + * and + * pca9540.c from Jean Delvare . + * + * This file is licensed under the terms of the GNU General Public + * License version 2. This program is licensed "as is" without any + * warranty of any kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define I2C_RW_RETRY_COUNT 10 +#define I2C_RW_RETRY_INTERVAL 60 /* ms */ + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +enum cpld_type { + as9647_32d_cpld1, + as9647_32d_cpld2, + as9647_32d_cpld3, +}; + +struct as9647_32d_cpld_data { + enum cpld_type type; + struct device *hwmon_dev; + struct mutex update_lock; +}; + +static const struct i2c_device_id as9647_32d_cpld_id[] = { + { "as9647_32d_cpld1", as9647_32d_cpld1 }, + { "as9647_32d_cpld2", as9647_32d_cpld2 }, + { "as9647_32d_cpld3", as9647_32d_cpld3 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, as9647_32d_cpld_id); + +#define TRANSCEIVER_PRESENT_ATTR_ID(index) MODULE_PRESENT_##index +#define TRANSCEIVER_RESET_ATTR_ID(index) MODULE_RESET_##index +#define TRANSCEIVER_LPMODE_ATTR_ID(index) MODULE_LPMODE_##index + +enum as9647_32d_cpld_sysfs_attributes { + BOARD_ID, + CPLD_VERSION, + ACCESS, + MODULE_PRESENT_ALL, + MODULE_RXLOS_ALL, + /* transceiver attributes */ + TRANSCEIVER_PRESENT_ATTR_ID(1), + TRANSCEIVER_PRESENT_ATTR_ID(2), + TRANSCEIVER_PRESENT_ATTR_ID(3), + TRANSCEIVER_PRESENT_ATTR_ID(4), + TRANSCEIVER_PRESENT_ATTR_ID(5), + TRANSCEIVER_PRESENT_ATTR_ID(6), + TRANSCEIVER_PRESENT_ATTR_ID(7), + TRANSCEIVER_PRESENT_ATTR_ID(8), + TRANSCEIVER_PRESENT_ATTR_ID(9), + TRANSCEIVER_PRESENT_ATTR_ID(10), + TRANSCEIVER_PRESENT_ATTR_ID(11), + TRANSCEIVER_PRESENT_ATTR_ID(12), + TRANSCEIVER_PRESENT_ATTR_ID(13), + TRANSCEIVER_PRESENT_ATTR_ID(14), + TRANSCEIVER_PRESENT_ATTR_ID(15), + TRANSCEIVER_PRESENT_ATTR_ID(16), + TRANSCEIVER_PRESENT_ATTR_ID(17), + TRANSCEIVER_PRESENT_ATTR_ID(18), + TRANSCEIVER_PRESENT_ATTR_ID(19), + TRANSCEIVER_PRESENT_ATTR_ID(20), + TRANSCEIVER_PRESENT_ATTR_ID(21), + TRANSCEIVER_PRESENT_ATTR_ID(22), + TRANSCEIVER_PRESENT_ATTR_ID(23), + TRANSCEIVER_PRESENT_ATTR_ID(24), + TRANSCEIVER_PRESENT_ATTR_ID(25), + TRANSCEIVER_PRESENT_ATTR_ID(26), + TRANSCEIVER_PRESENT_ATTR_ID(27), + TRANSCEIVER_PRESENT_ATTR_ID(28), + TRANSCEIVER_PRESENT_ATTR_ID(29), + TRANSCEIVER_PRESENT_ATTR_ID(30), + TRANSCEIVER_PRESENT_ATTR_ID(31), + TRANSCEIVER_PRESENT_ATTR_ID(32), + TRANSCEIVER_RESET_ATTR_ID(1), + TRANSCEIVER_RESET_ATTR_ID(2), + TRANSCEIVER_RESET_ATTR_ID(3), + TRANSCEIVER_RESET_ATTR_ID(4), + TRANSCEIVER_RESET_ATTR_ID(5), + TRANSCEIVER_RESET_ATTR_ID(6), + TRANSCEIVER_RESET_ATTR_ID(7), + TRANSCEIVER_RESET_ATTR_ID(8), + TRANSCEIVER_RESET_ATTR_ID(9), + TRANSCEIVER_RESET_ATTR_ID(10), + TRANSCEIVER_RESET_ATTR_ID(11), + TRANSCEIVER_RESET_ATTR_ID(12), + TRANSCEIVER_RESET_ATTR_ID(13), + TRANSCEIVER_RESET_ATTR_ID(14), + TRANSCEIVER_RESET_ATTR_ID(15), + TRANSCEIVER_RESET_ATTR_ID(16), + TRANSCEIVER_RESET_ATTR_ID(17), + TRANSCEIVER_RESET_ATTR_ID(18), + TRANSCEIVER_RESET_ATTR_ID(19), + TRANSCEIVER_RESET_ATTR_ID(20), + TRANSCEIVER_RESET_ATTR_ID(21), + TRANSCEIVER_RESET_ATTR_ID(22), + TRANSCEIVER_RESET_ATTR_ID(23), + TRANSCEIVER_RESET_ATTR_ID(24), + TRANSCEIVER_RESET_ATTR_ID(25), + TRANSCEIVER_RESET_ATTR_ID(26), + TRANSCEIVER_RESET_ATTR_ID(27), + TRANSCEIVER_RESET_ATTR_ID(28), + TRANSCEIVER_RESET_ATTR_ID(29), + TRANSCEIVER_RESET_ATTR_ID(30), + TRANSCEIVER_RESET_ATTR_ID(31), + TRANSCEIVER_RESET_ATTR_ID(32), + TRANSCEIVER_LPMODE_ATTR_ID(1), + TRANSCEIVER_LPMODE_ATTR_ID(2), + TRANSCEIVER_LPMODE_ATTR_ID(3), + TRANSCEIVER_LPMODE_ATTR_ID(4), + TRANSCEIVER_LPMODE_ATTR_ID(5), + TRANSCEIVER_LPMODE_ATTR_ID(6), + TRANSCEIVER_LPMODE_ATTR_ID(7), + TRANSCEIVER_LPMODE_ATTR_ID(8), + TRANSCEIVER_LPMODE_ATTR_ID(9), + TRANSCEIVER_LPMODE_ATTR_ID(10), + TRANSCEIVER_LPMODE_ATTR_ID(11), + TRANSCEIVER_LPMODE_ATTR_ID(12), + TRANSCEIVER_LPMODE_ATTR_ID(13), + TRANSCEIVER_LPMODE_ATTR_ID(14), + TRANSCEIVER_LPMODE_ATTR_ID(15), + TRANSCEIVER_LPMODE_ATTR_ID(16), + TRANSCEIVER_LPMODE_ATTR_ID(17), + TRANSCEIVER_LPMODE_ATTR_ID(18), + TRANSCEIVER_LPMODE_ATTR_ID(19), + TRANSCEIVER_LPMODE_ATTR_ID(20), + TRANSCEIVER_LPMODE_ATTR_ID(21), + TRANSCEIVER_LPMODE_ATTR_ID(22), + TRANSCEIVER_LPMODE_ATTR_ID(23), + TRANSCEIVER_LPMODE_ATTR_ID(24), + TRANSCEIVER_LPMODE_ATTR_ID(25), + TRANSCEIVER_LPMODE_ATTR_ID(26), + TRANSCEIVER_LPMODE_ATTR_ID(27), + TRANSCEIVER_LPMODE_ATTR_ID(28), + TRANSCEIVER_LPMODE_ATTR_ID(29), + TRANSCEIVER_LPMODE_ATTR_ID(30), + TRANSCEIVER_LPMODE_ATTR_ID(31), + TRANSCEIVER_LPMODE_ATTR_ID(32) +}; + +/* sysfs attributes for hwmon + */ +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +static ssize_t show_board_id(struct device *dev, struct device_attribute *da, + char *buf); +static int as9647_32d_cpld_read_internal(struct i2c_client *client, u8 reg); +static int as9647_32d_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value); + +/* transceiver attributes */ +#define DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(index) \ + static SENSOR_DEVICE_ATTR(module_present_##index, S_IRUGO, show_status, NULL, MODULE_PRESENT_##index); \ + static SENSOR_DEVICE_ATTR(module_reset_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_RESET_##index); \ + static SENSOR_DEVICE_ATTR(module_lpmode_##index, S_IRUGO | S_IWUSR, show_status, set_control, MODULE_LPMODE_##index) + +#define DECLARE_TRANSCEIVER_PRESENT_ATTR(index) &sensor_dev_attr_module_present_##index.dev_attr.attr +#define DECLARE_TRANSCEIVER_RESET_ATTR(index) &sensor_dev_attr_module_reset_##index.dev_attr.attr +#define DECLARE_TRANSCEIVER_LPMODE_ATTR(index) &sensor_dev_attr_module_lpmode_##index.dev_attr.attr + +static SENSOR_DEVICE_ATTR(board_id, S_IRUGO, show_board_id, NULL, BOARD_ID); +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(access, S_IWUSR, NULL, access, ACCESS); + +/* transceiver attributes */ +static SENSOR_DEVICE_ATTR(module_present_all, S_IRUGO, show_present_all, NULL, MODULE_PRESENT_ALL); + +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(1); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(2); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(3); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(4); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(5); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(6); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(7); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(8); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(9); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(10); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(11); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(12); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(13); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(14); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(15); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(16); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(17); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(18); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(19); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(20); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(21); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(22); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(23); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(24); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(25); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(26); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(27); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(28); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(29); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(30); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(31); +DECLARE_TRANSCEIVER_SENSOR_DEVICE_ATTR(32); + +static struct attribute *as9647_32d_cpld1_attributes[] = { + &sensor_dev_attr_board_id.dev_attr.attr, + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + NULL +}; + +static const struct attribute_group as9647_32d_cpld1_group = { + .attrs = as9647_32d_cpld1_attributes, +}; + +static struct attribute *as9647_32d_cpld2_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(1), + DECLARE_TRANSCEIVER_PRESENT_ATTR(2), + DECLARE_TRANSCEIVER_PRESENT_ATTR(3), + DECLARE_TRANSCEIVER_PRESENT_ATTR(4), + DECLARE_TRANSCEIVER_PRESENT_ATTR(5), + DECLARE_TRANSCEIVER_PRESENT_ATTR(6), + DECLARE_TRANSCEIVER_PRESENT_ATTR(7), + DECLARE_TRANSCEIVER_PRESENT_ATTR(8), + DECLARE_TRANSCEIVER_PRESENT_ATTR(9), + DECLARE_TRANSCEIVER_PRESENT_ATTR(10), + DECLARE_TRANSCEIVER_PRESENT_ATTR(11), + DECLARE_TRANSCEIVER_PRESENT_ATTR(12), + DECLARE_TRANSCEIVER_PRESENT_ATTR(13), + DECLARE_TRANSCEIVER_PRESENT_ATTR(14), + DECLARE_TRANSCEIVER_PRESENT_ATTR(15), + DECLARE_TRANSCEIVER_PRESENT_ATTR(16), + DECLARE_TRANSCEIVER_RESET_ATTR(1), + DECLARE_TRANSCEIVER_RESET_ATTR(2), + DECLARE_TRANSCEIVER_RESET_ATTR(3), + DECLARE_TRANSCEIVER_RESET_ATTR(4), + DECLARE_TRANSCEIVER_RESET_ATTR(5), + DECLARE_TRANSCEIVER_RESET_ATTR(6), + DECLARE_TRANSCEIVER_RESET_ATTR(7), + DECLARE_TRANSCEIVER_RESET_ATTR(8), + DECLARE_TRANSCEIVER_RESET_ATTR(9), + DECLARE_TRANSCEIVER_RESET_ATTR(10), + DECLARE_TRANSCEIVER_RESET_ATTR(11), + DECLARE_TRANSCEIVER_RESET_ATTR(12), + DECLARE_TRANSCEIVER_RESET_ATTR(13), + DECLARE_TRANSCEIVER_RESET_ATTR(14), + DECLARE_TRANSCEIVER_RESET_ATTR(15), + DECLARE_TRANSCEIVER_RESET_ATTR(16), + DECLARE_TRANSCEIVER_LPMODE_ATTR(1), + DECLARE_TRANSCEIVER_LPMODE_ATTR(2), + DECLARE_TRANSCEIVER_LPMODE_ATTR(3), + DECLARE_TRANSCEIVER_LPMODE_ATTR(4), + DECLARE_TRANSCEIVER_LPMODE_ATTR(5), + DECLARE_TRANSCEIVER_LPMODE_ATTR(6), + DECLARE_TRANSCEIVER_LPMODE_ATTR(7), + DECLARE_TRANSCEIVER_LPMODE_ATTR(8), + DECLARE_TRANSCEIVER_LPMODE_ATTR(9), + DECLARE_TRANSCEIVER_LPMODE_ATTR(10), + DECLARE_TRANSCEIVER_LPMODE_ATTR(11), + DECLARE_TRANSCEIVER_LPMODE_ATTR(12), + DECLARE_TRANSCEIVER_LPMODE_ATTR(13), + DECLARE_TRANSCEIVER_LPMODE_ATTR(14), + DECLARE_TRANSCEIVER_LPMODE_ATTR(15), + DECLARE_TRANSCEIVER_LPMODE_ATTR(16), + NULL +}; + +static const struct attribute_group as9647_32d_cpld2_group = { + .attrs = as9647_32d_cpld2_attributes, +}; + + +static struct attribute *as9647_32d_cpld3_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + &sensor_dev_attr_access.dev_attr.attr, + /* transceiver attributes */ + &sensor_dev_attr_module_present_all.dev_attr.attr, + DECLARE_TRANSCEIVER_PRESENT_ATTR(17), + DECLARE_TRANSCEIVER_PRESENT_ATTR(18), + DECLARE_TRANSCEIVER_PRESENT_ATTR(19), + DECLARE_TRANSCEIVER_PRESENT_ATTR(20), + DECLARE_TRANSCEIVER_PRESENT_ATTR(21), + DECLARE_TRANSCEIVER_PRESENT_ATTR(22), + DECLARE_TRANSCEIVER_PRESENT_ATTR(23), + DECLARE_TRANSCEIVER_PRESENT_ATTR(24), + DECLARE_TRANSCEIVER_PRESENT_ATTR(25), + DECLARE_TRANSCEIVER_PRESENT_ATTR(26), + DECLARE_TRANSCEIVER_PRESENT_ATTR(27), + DECLARE_TRANSCEIVER_PRESENT_ATTR(28), + DECLARE_TRANSCEIVER_PRESENT_ATTR(29), + DECLARE_TRANSCEIVER_PRESENT_ATTR(30), + DECLARE_TRANSCEIVER_PRESENT_ATTR(31), + DECLARE_TRANSCEIVER_PRESENT_ATTR(32), + DECLARE_TRANSCEIVER_RESET_ATTR(17), + DECLARE_TRANSCEIVER_RESET_ATTR(18), + DECLARE_TRANSCEIVER_RESET_ATTR(19), + DECLARE_TRANSCEIVER_RESET_ATTR(20), + DECLARE_TRANSCEIVER_RESET_ATTR(21), + DECLARE_TRANSCEIVER_RESET_ATTR(22), + DECLARE_TRANSCEIVER_RESET_ATTR(23), + DECLARE_TRANSCEIVER_RESET_ATTR(24), + DECLARE_TRANSCEIVER_RESET_ATTR(25), + DECLARE_TRANSCEIVER_RESET_ATTR(26), + DECLARE_TRANSCEIVER_RESET_ATTR(27), + DECLARE_TRANSCEIVER_RESET_ATTR(28), + DECLARE_TRANSCEIVER_RESET_ATTR(29), + DECLARE_TRANSCEIVER_RESET_ATTR(30), + DECLARE_TRANSCEIVER_RESET_ATTR(31), + DECLARE_TRANSCEIVER_RESET_ATTR(32), + DECLARE_TRANSCEIVER_LPMODE_ATTR(17), + DECLARE_TRANSCEIVER_LPMODE_ATTR(18), + DECLARE_TRANSCEIVER_LPMODE_ATTR(19), + DECLARE_TRANSCEIVER_LPMODE_ATTR(20), + DECLARE_TRANSCEIVER_LPMODE_ATTR(21), + DECLARE_TRANSCEIVER_LPMODE_ATTR(22), + DECLARE_TRANSCEIVER_LPMODE_ATTR(23), + DECLARE_TRANSCEIVER_LPMODE_ATTR(24), + DECLARE_TRANSCEIVER_LPMODE_ATTR(25), + DECLARE_TRANSCEIVER_LPMODE_ATTR(26), + DECLARE_TRANSCEIVER_LPMODE_ATTR(27), + DECLARE_TRANSCEIVER_LPMODE_ATTR(28), + DECLARE_TRANSCEIVER_LPMODE_ATTR(29), + DECLARE_TRANSCEIVER_LPMODE_ATTR(30), + DECLARE_TRANSCEIVER_LPMODE_ATTR(31), + DECLARE_TRANSCEIVER_LPMODE_ATTR(32), + NULL +}; + +static const struct attribute_group as9647_32d_cpld3_group = { + .attrs = as9647_32d_cpld3_attributes, +}; + + +static ssize_t show_present_all(struct device *dev, struct device_attribute *da, + char *buf) +{ + int i, status; + u8 values[2] = {0}; + u8 regs_cpld2[] = {0x14, 0x15}; + u8 *regs[] = {NULL, regs_cpld2, NULL}; + u8 size[] = {0, ARRAY_SIZE(regs_cpld2), 0}; + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_cpld_data *data = i2c_get_clientdata(client); + + mutex_lock(&data->update_lock); + + for (i = 0; i < size[data->type]; i++) { + status = as9647_32d_cpld_read_internal(client, regs[data->type][i]); + if (status < 0) { + goto exit; + } + + values[i] = ~(u8)status; + } + + mutex_unlock(&data->update_lock); + + /* Return values in order */ + return sprintf(buf, "%.2x %.2x\n", values[0], values[1]); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_cpld_data *data = i2c_get_clientdata(client); + int status = 0; + u8 reg = 0, mask = 0, invert = 1; + + switch (attr->index) { + case MODULE_PRESENT_1 ... MODULE_PRESENT_8: + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_PRESENT_1); + break; + case MODULE_PRESENT_9 ... MODULE_PRESENT_16: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_PRESENT_9); + break; + case MODULE_PRESENT_17 ... MODULE_PRESENT_24: + reg = 0x14; + mask = 0x1 << (attr->index - MODULE_PRESENT_17); + break; + case MODULE_PRESENT_25 ... MODULE_PRESENT_32: + reg = 0x15; + mask = 0x1 << (attr->index - MODULE_PRESENT_25); + break; + case MODULE_RESET_1 ... MODULE_RESET_8: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_RESET_1); + break; + case MODULE_RESET_9 ... MODULE_RESET_16: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_RESET_9); + break; + case MODULE_RESET_17 ... MODULE_RESET_24: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_RESET_17); + break; + case MODULE_RESET_25 ... MODULE_RESET_32: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_RESET_25); + break; + case MODULE_LPMODE_1 ... MODULE_LPMODE_8: + reg = 0x64; + mask = 0x1 << (attr->index - MODULE_LPMODE_1); + invert = 0; + break; + case MODULE_LPMODE_9 ... MODULE_LPMODE_16: + reg = 0x65; + mask = 0x1 << (attr->index - MODULE_LPMODE_9); + invert = 0; + break; + case MODULE_LPMODE_17 ... MODULE_LPMODE_24: + reg = 0x64; + mask = 0x1 << (attr->index - MODULE_LPMODE_17); + invert = 0; + break; + case MODULE_LPMODE_25 ... MODULE_LPMODE_32: + reg = 0x65; + mask = 0x1 << (attr->index - MODULE_LPMODE_25); + invert = 0; + break; + default: + return 0; + } + + mutex_lock(&data->update_lock); + status = as9647_32d_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + + return sprintf(buf, "%d\n", invert ? !(status & mask) : !!(status & mask)); + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t set_control(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_cpld_data *data = i2c_get_clientdata(client); + long value; + int status; + u8 reg = 0, mask = 0; + + status = kstrtol(buf, 10, &value); + if (status) { + return status; + } + + switch (attr->index) { + case MODULE_RESET_1 ... MODULE_RESET_8: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_RESET_1); + break; + case MODULE_RESET_9 ... MODULE_RESET_16: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_RESET_9); + break; + case MODULE_RESET_17 ... MODULE_RESET_24: + reg = 0x60; + mask = 0x1 << (attr->index - MODULE_RESET_17); + break; + case MODULE_RESET_25 ... MODULE_RESET_32: + reg = 0x61; + mask = 0x1 << (attr->index - MODULE_RESET_25); + break; + case MODULE_LPMODE_1 ... MODULE_LPMODE_8: + reg = 0x64; + mask = 0x1 << (attr->index - MODULE_LPMODE_1); + break; + case MODULE_LPMODE_9 ... MODULE_LPMODE_16: + reg = 0x65; + mask = 0x1 << (attr->index - MODULE_LPMODE_9); + break; + case MODULE_LPMODE_17 ... MODULE_LPMODE_24: + reg = 0x64; + mask = 0x1 << (attr->index - MODULE_LPMODE_17); + break; + case MODULE_LPMODE_25 ... MODULE_LPMODE_32: + reg = 0x65; + mask = 0x1 << (attr->index - MODULE_LPMODE_25); + break; + default: + return 0; + } + + /* Read current status */ + mutex_lock(&data->update_lock); + status = as9647_32d_cpld_read_internal(client, reg); + if (unlikely(status < 0)) { + goto exit; + } + + /* Update reset status. Since reset is active low, revert it */ + if ((attr->index >= MODULE_RESET_1 && attr->index <= MODULE_RESET_32)) { + value = !value; + } + + if (value) { + status |= mask; + } + else { + status &= ~mask; + } + + status = as9647_32d_cpld_write_internal(client, reg, status); + if (unlikely(status < 0)) { + goto exit; + } + + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static ssize_t access(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int status; + u32 addr, val; + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_cpld_data *data = i2c_get_clientdata(client); + + if (sscanf(buf, "0x%x 0x%x", &addr, &val) != 2) { + return -EINVAL; + } + + if (addr > 0xFF || val > 0xFF) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + status = as9647_32d_cpld_write_internal(client, addr, val); + if (unlikely(status < 0)) { + goto exit; + } + mutex_unlock(&data->update_lock); + return count; + +exit: + mutex_unlock(&data->update_lock); + return status; +} + +static void as9647_32d_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + dev_dbg(&client->dev, "Can't allocate cpld_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &cpld_client_list); + mutex_unlock(&list_lock); +} + +static void as9647_32d_cpld_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(cpld_node); + } + + mutex_unlock(&list_lock); +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int ver = 0; + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_cpld_data *data = i2c_get_clientdata(client); + + ver = i2c_smbus_read_byte_data(client, 0x1); + + if (ver < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, ver); + return ver; + } + + if (data->type == as9647_32d_cpld1) { + int subver = i2c_smbus_read_byte_data(client, 0x2); + + if (subver < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x2) err %d\n", client->addr, subver); + return subver; + } + return sprintf(buf, "%d.%d\n", ver, subver); + } + + return sprintf(buf, "%d\n", ver); +} + +static ssize_t show_board_id(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x0); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x0) err %d\n", client->addr, val); + return val; + } + + return sprintf(buf, "%d\n", (val >> 3) & 0x7); +} + +/* + * I2C init/probing/exit functions + */ +static int as9647_32d_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent); + struct as9647_32d_cpld_data *data; + int ret = -ENODEV; + const struct attribute_group *group = NULL; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) + goto exit; + + data = kzalloc(sizeof(struct as9647_32d_cpld_data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + mutex_init(&data->update_lock); + data->type = id->driver_data; + + /* Register sysfs hooks */ + switch (data->type) { + case as9647_32d_cpld1: + group = &as9647_32d_cpld1_group; + break; + case as9647_32d_cpld2: + group = &as9647_32d_cpld2_group; + break; + case as9647_32d_cpld3: + group = &as9647_32d_cpld3_group; + break; + default: + break; + } + + if (group) { + ret = sysfs_create_group(&client->dev.kobj, group); + if (ret) { + goto exit_free; + } + } + + as9647_32d_cpld_add_client(client); + return 0; + +exit_free: + kfree(data); +exit: + return ret; +} + +static int as9647_32d_cpld_remove(struct i2c_client *client) +{ + struct as9647_32d_cpld_data *data = i2c_get_clientdata(client); + const struct attribute_group *group = NULL; + + as9647_32d_cpld_remove_client(client); + + /* Remove sysfs hooks */ + switch (data->type) { + case as9647_32d_cpld1: + group = &as9647_32d_cpld1_group; + break; + case as9647_32d_cpld2: + group = &as9647_32d_cpld2_group; + break; + case as9647_32d_cpld3: + group = &as9647_32d_cpld3_group; + break; + default: + break; + } + + if (group) { + sysfs_remove_group(&client->dev.kobj, group); + } + + kfree(data); + + return 0; +} + +static int as9647_32d_cpld_read_internal(struct i2c_client *client, u8 reg) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_read_byte_data(client, reg); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +static int as9647_32d_cpld_write_internal(struct i2c_client *client, u8 reg, u8 value) +{ + int status = 0, retry = I2C_RW_RETRY_COUNT; + + while (retry) { + status = i2c_smbus_write_byte_data(client, reg, value); + if (unlikely(status < 0)) { + msleep(I2C_RW_RETRY_INTERVAL); + retry--; + continue; + } + + break; + } + + return status; +} + +int as9647_32d_cpld_read(unsigned short cpld_addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as9647_32d_cpld_read_internal(cpld_node->client, reg); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as9647_32d_cpld_read); + +int as9647_32d_cpld_write(unsigned short cpld_addr, u8 reg, u8 value) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &cpld_client_list) + { + cpld_node = list_entry(list_node, struct cpld_client_node, list); + + if (cpld_node->client->addr == cpld_addr) { + ret = as9647_32d_cpld_write_internal(cpld_node->client, reg, value); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(as9647_32d_cpld_write); + +static struct i2c_driver as9647_32d_cpld_driver = { + .driver = { + .name = "as9647_32d_cpld", + .owner = THIS_MODULE, + }, + .probe = as9647_32d_cpld_probe, + .remove = as9647_32d_cpld_remove, + .id_table = as9647_32d_cpld_id, +}; + +static int __init as9647_32d_cpld_init(void) +{ + mutex_init(&list_lock); + return i2c_add_driver(&as9647_32d_cpld_driver); +} + +static void __exit as9647_32d_cpld_exit(void) +{ + i2c_del_driver(&as9647_32d_cpld_driver); +} + +MODULE_AUTHOR("Brandon Chuang "); +MODULE_DESCRIPTION("Accton as9647_32d CPLD driver"); +MODULE_LICENSE("GPL"); + +module_init(as9647_32d_cpld_init); +module_exit(as9647_32d_cpld_exit); diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-fan.c b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-fan.c new file mode 100644 index 0000000000..9fd01c3ba4 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-fan.c @@ -0,0 +1,680 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A hwmon driver for the Accton as9647_32d fan + * + * Copyright (C) 2024 Accton Technology Corporation. + * Copyright (C) 2025 XsightLabs Ltd. + * + * Based on: + * es9632xx-fan.c from Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9647_32d_fan" +#define MAX_FAN_SPEED_RPM 31000 + +static struct as9647_32d_fan_data *as9647_32d_fan_update_device(struct device *dev); +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_fan_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t set_fan_led_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count); +static ssize_t show_version(struct device *dev, struct device_attribute *da, + char *buf); +extern int as9647_32d_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as9647_32d_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +/* fan related data, the index should match sysfs_fan_attributes + */ +static const u8 fan_reg[] = { + 0x0F, /* fan 1-6 present status */ + 0x10, /* fan 1-6 direction(0:F2B 1:B2F) */ + 0x11, /* fan PWM(for all fan) */ + 0x12, /* front fan 1 speed(rpm) */ + 0x13, /* front fan 2 speed(rpm) */ + 0x14, /* front fan 3 speed(rpm) */ + 0x15, /* front fan 4 speed(rpm) */ + 0x16, /* front fan 5 speed(rpm) */ + 0x17, /* front fan 6 speed(rpm) */ + 0x1C, /* LED display 1 (fan 1-4) */ + 0x1D, /* LED display 2 (fan 5-6) */ + 0x22, /* rear fan 1 speed(rpm) */ + 0x23, /* rear fan 2 speed(rpm) */ + 0x24, /* rear fan 3 speed(rpm) */ + 0x25, /* rear fan 4 speed(rpm) */ + 0x26, /* rear fan 5 speed(rpm) */ + 0x27, /* rear fan 6 speed(rpm) */ + 0x42, /* LED debug mode */ + +}; + +/* fan data */ +struct as9647_32d_fan_data { + struct platform_device *pdev; + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[ARRAY_SIZE(fan_reg)]; /* Register value */ +}; + +enum fan_id { + FAN1_ID, + FAN2_ID, + FAN3_ID, + FAN4_ID, + FAN5_ID, + FAN6_ID +}; + +enum sysfs_fan_attributes { + FAN_PRESENT_REG, + FAN_DIRECTION_REG, + FAN_DUTY_CYCLE_PERCENTAGE, /* Only one CPLD register to control duty cycle for all fans */ + FAN1_FRONT_SPEED_RPM, + FAN2_FRONT_SPEED_RPM, + FAN3_FRONT_SPEED_RPM, + FAN4_FRONT_SPEED_RPM, + FAN5_FRONT_SPEED_RPM, + FAN6_FRONT_SPEED_RPM, + FAN_LED_DISPLAY1, + FAN_LED_DISPLAY2, + FAN1_REAR_SPEED_RPM, + FAN2_REAR_SPEED_RPM, + FAN3_REAR_SPEED_RPM, + FAN4_REAR_SPEED_RPM, + FAN5_REAR_SPEED_RPM, + FAN6_REAR_SPEED_RPM, + FAN_LED_MODE, + FAN1_DIRECTION, + FAN2_DIRECTION, + FAN3_DIRECTION, + FAN4_DIRECTION, + FAN5_DIRECTION, + FAN6_DIRECTION, + FAN1_PRESENT, + FAN2_PRESENT, + FAN3_PRESENT, + FAN4_PRESENT, + FAN5_PRESENT, + FAN6_PRESENT, + FAN1_FAULT, + FAN2_FAULT, + FAN3_FAULT, + FAN4_FAULT, + FAN5_FAULT, + FAN6_FAULT, + FAN1_LED, + FAN2_LED, + FAN3_LED, + FAN4_LED, + FAN5_LED, + FAN6_LED, + FAN_MAX_RPM, + CPLD_VERSION +}; + +enum led_color { + LED_COLOR_UNKNOWN, + LED_COLOR_RED, + LED_COLOR_GREEN, + LED_COLOR_OFF +}; + +enum led_mode { + LED_MODE_NORMAL, + LED_MODE_DEBUG, + LED_MODE_UNKNOWN +}; + +/* Define attributes + */ +#define DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT);\ + static SENSOR_DEVICE_ATTR(fan##index2##_fault, S_IRUGO, fan_show_value, NULL, FAN##index##_FAULT) +#define DECLARE_FAN_FAULT_ATTR(index, index2) &sensor_dev_attr_fan##index##_fault.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_fault.dev_attr.attr +#define DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_direction, S_IRUGO, fan_show_value, NULL, FAN##index##_DIRECTION) +#define DECLARE_FAN_DIRECTION_ATTR(index) &sensor_dev_attr_fan##index##_direction.dev_attr.attr + +#define DECLARE_FAN_LED_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_led, S_IWUSR | S_IRUGO, fan_show_value, set_fan_led, FAN##index##_LED) +#define DECLARE_FAN_LED_ATTR(index) &sensor_dev_attr_fan##index##_led.dev_attr.attr + +#define DECLARE_FAN_LED_MODE_SENSOR_DEV_ATTR() \ + static SENSOR_DEVICE_ATTR(fan_led_mode, S_IWUSR | S_IRUGO, fan_show_value, set_fan_led_mode, FAN_LED_MODE) +#define DECLARE_FAN_LED_MODE_ATTR() &sensor_dev_attr_fan_led_mode.dev_attr.attr + +#define DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_duty_cycle_percentage, S_IWUSR | S_IRUGO, fan_show_value, set_duty_cycle, FAN##index##_DUTY_CYCLE_PERCENTAGE) +#define DECLARE_FAN_DUTY_CYCLE_ATTR(index) &sensor_dev_attr_fan##index##_duty_cycle_percentage.dev_attr.attr + +#define DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(index) \ + static SENSOR_DEVICE_ATTR(fan##index##_present, S_IRUGO, fan_show_value, NULL, FAN##index##_PRESENT) +#define DECLARE_FAN_PRESENT_ATTR(index) &sensor_dev_attr_fan##index##_present.dev_attr.attr + +#define DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(index, index2) \ + static SENSOR_DEVICE_ATTR(fan##index##_front_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_rear_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_FRONT_SPEED_RPM);\ + static SENSOR_DEVICE_ATTR(fan##index2##_input, S_IRUGO, fan_show_value, NULL, FAN##index##_REAR_SPEED_RPM) +#define DECLARE_FAN_SPEED_RPM_ATTR(index, index2) &sensor_dev_attr_fan##index##_front_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_rear_speed_rpm.dev_attr.attr, \ + &sensor_dev_attr_fan##index##_input.dev_attr.attr, \ + &sensor_dev_attr_fan##index2##_input.dev_attr.attr + +static SENSOR_DEVICE_ATTR(version, S_IRUGO, show_version, NULL, CPLD_VERSION); +static SENSOR_DEVICE_ATTR(fan_max_speed_rpm, S_IRUGO, fan_show_value, NULL, FAN_MAX_RPM); +#define DECLARE_FAN_MAX_RPM_ATTR(index) &sensor_dev_attr_fan_max_speed_rpm.dev_attr.attr + + +/* 6 fan fault attributes in this platform */ +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(1, 11); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(2, 12); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(3, 13); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(4, 14); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(5, 15); +DECLARE_FAN_FAULT_SENSOR_DEV_ATTR(6, 16); +/* 6 fan speed(rpm) attributes in this platform */ +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(1, 11); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(2, 12); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(3, 13); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(4, 14); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(5, 15); +DECLARE_FAN_SPEED_RPM_SENSOR_DEV_ATTR(6, 16); + +/* 6 fan present attributes in this platform */ +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(1); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(2); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(3); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(4); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(5); +DECLARE_FAN_PRESENT_SENSOR_DEV_ATTR(6); + +/* 6 fan direction attribute in this platform */ +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(1); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(2); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(3); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(4); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(5); +DECLARE_FAN_DIRECTION_SENSOR_DEV_ATTR(6); + +/* 6 fan led attribute in this platform */ +DECLARE_FAN_LED_SENSOR_DEV_ATTR(1); +DECLARE_FAN_LED_SENSOR_DEV_ATTR(2); +DECLARE_FAN_LED_SENSOR_DEV_ATTR(3); +DECLARE_FAN_LED_SENSOR_DEV_ATTR(4); +DECLARE_FAN_LED_SENSOR_DEV_ATTR(5); +DECLARE_FAN_LED_SENSOR_DEV_ATTR(6); + +/* 1 fan duty cycle attribute in this platform */ +DECLARE_FAN_DUTY_CYCLE_SENSOR_DEV_ATTR(); + +/* LED debug mode attribute */ +DECLARE_FAN_LED_MODE_SENSOR_DEV_ATTR(); + +static struct attribute *as9647_32d_fan_attributes[] = { + &sensor_dev_attr_version.dev_attr.attr, + /* fan related attributes */ + DECLARE_FAN_FAULT_ATTR(1, 11), + DECLARE_FAN_FAULT_ATTR(2, 12), + DECLARE_FAN_FAULT_ATTR(3, 13), + DECLARE_FAN_FAULT_ATTR(4, 14), + DECLARE_FAN_FAULT_ATTR(5, 15), + DECLARE_FAN_FAULT_ATTR(6, 16), + DECLARE_FAN_SPEED_RPM_ATTR(1, 11), + DECLARE_FAN_SPEED_RPM_ATTR(2, 12), + DECLARE_FAN_SPEED_RPM_ATTR(3, 13), + DECLARE_FAN_SPEED_RPM_ATTR(4, 14), + DECLARE_FAN_SPEED_RPM_ATTR(5, 15), + DECLARE_FAN_SPEED_RPM_ATTR(6, 16), + DECLARE_FAN_PRESENT_ATTR(1), + DECLARE_FAN_PRESENT_ATTR(2), + DECLARE_FAN_PRESENT_ATTR(3), + DECLARE_FAN_PRESENT_ATTR(4), + DECLARE_FAN_PRESENT_ATTR(5), + DECLARE_FAN_PRESENT_ATTR(6), + DECLARE_FAN_DIRECTION_ATTR(1), + DECLARE_FAN_DIRECTION_ATTR(2), + DECLARE_FAN_DIRECTION_ATTR(3), + DECLARE_FAN_DIRECTION_ATTR(4), + DECLARE_FAN_DIRECTION_ATTR(5), + DECLARE_FAN_DIRECTION_ATTR(6), + DECLARE_FAN_LED_ATTR(1), + DECLARE_FAN_LED_ATTR(2), + DECLARE_FAN_LED_ATTR(3), + DECLARE_FAN_LED_ATTR(4), + DECLARE_FAN_LED_ATTR(5), + DECLARE_FAN_LED_ATTR(6), + DECLARE_FAN_DUTY_CYCLE_ATTR(), + DECLARE_FAN_MAX_RPM_ATTR(), + DECLARE_FAN_LED_MODE_ATTR(), + NULL +}; + +#define FAN_DUTY_CYCLE_REG_MASK 0x0F +#define FAN_MAX_DUTY_CYCLE 100 +#define FAN_REG_VAL_TO_SPEED_RPM_STEP 200 + +static int as9647_32d_fan_read_value(struct i2c_client *client, u8 reg) +{ + return i2c_smbus_read_byte_data(client, reg); +} + +static int as9647_32d_fan_write_value(struct i2c_client *client, u8 reg, u8 value) +{ + return i2c_smbus_write_byte_data(client, reg, value); +} + +/* fan utility functions + */ +static u32 reg_val_to_duty_cycle(u8 reg_val) +{ + reg_val &= FAN_DUTY_CYCLE_REG_MASK; + return (u32)(reg_val+1) * 625 / 100; +} + +static u8 duty_cycle_to_reg_val(u8 duty_cycle) +{ + if (duty_cycle == 0) { + return 0; + } + else if (duty_cycle > FAN_MAX_DUTY_CYCLE) { + duty_cycle = FAN_MAX_DUTY_CYCLE; + } + + return ((u32)duty_cycle * 100 / 625) - 1; +} + +static u32 reg_val_to_speed_rpm(u8 reg_val) +{ + return (u32)reg_val * FAN_REG_VAL_TO_SPEED_RPM_STEP; +} + +static u8 reg_val_to_direction(u8 reg_val, enum fan_id id) +{ + return !!(reg_val & BIT(id)); /* 0: Front to Back, 1: Back to Front*/ +} + +static u8 reg_val_to_is_present(u8 reg_val, enum fan_id id) +{ + return !(reg_val & BIT(id)); +} + +static u8 is_fan_fault(struct as9647_32d_fan_data *data, enum fan_id id) +{ + u8 ret = 1; + int front_fan_index = FAN1_FRONT_SPEED_RPM + id; + int rear_fan_index = FAN1_REAR_SPEED_RPM + id; + + /* Check if the speed of front or rear fan is ZERO, + */ + if (reg_val_to_speed_rpm(data->reg_val[front_fan_index]) && + reg_val_to_speed_rpm(data->reg_val[rear_fan_index])) { + ret = 0; + } + + return ret; +} + +static ssize_t set_duty_cycle(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_fan_data *data = i2c_get_clientdata(client); + + error = kstrtoint(buf, 10, &value); + if (error) { + return error; + } + + if (value < 0 || value > FAN_MAX_DUTY_CYCLE) { + return -EINVAL; + } + + mutex_lock(&data->update_lock); + + as9647_32d_fan_write_value(client, fan_reg[FAN_DUTY_CYCLE_PERCENTAGE], duty_cycle_to_reg_val(value)); + data->valid = 0; + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_fan_led(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + u8 reg, offset, reg_val, fan_id; + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_fan_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < LED_COLOR_RED || value > LED_COLOR_OFF) + return -EINVAL; + + mutex_lock(&data->update_lock); + + data = as9647_32d_fan_update_device(dev); + if (data->valid) { + switch (attr->index) { + case FAN1_LED: + case FAN2_LED: + case FAN3_LED: + case FAN4_LED: + reg = FAN_LED_DISPLAY1; + fan_id = FAN4_ID; + break; + case FAN5_LED: + case FAN6_LED: + reg = FAN_LED_DISPLAY2; + fan_id = FAN6_ID; + break; + default: + goto exit; + } + + offset = 2 * (fan_id - (attr->index - FAN1_LED)); + reg_val = data->reg_val[reg]; + reg_val &= ~(0x03 << offset); + reg_val |= ((value & 0x03) << offset); + as9647_32d_fan_write_value(client, fan_reg[reg], reg_val); + data->valid = 0; + } else { + return count; + } + +exit: + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t set_fan_led_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + int error, value; + u8 reg_val; + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_fan_data *data = i2c_get_clientdata(client); + + error = kstrtoint(buf, 10, &value); + if (error) + return error; + + if (value < LED_MODE_NORMAL || value > LED_MODE_DEBUG) + return -EINVAL; + + mutex_lock(&data->update_lock); + + reg_val = data->reg_val[FAN_LED_MODE]; + reg_val &= ~(0x01 << 7); + reg_val |= (value << 7); + as9647_32d_fan_write_value(client, fan_reg[FAN_LED_MODE], reg_val); + data->valid = 0; + + mutex_unlock(&data->update_lock); + return count; +} + +static ssize_t fan_show_value(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_fan_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + ssize_t ret = 0; + u8 reg, offset; + + mutex_lock(&data->update_lock); + + data = as9647_32d_fan_update_device(dev); + if (data->valid) { + switch (attr->index) { + case FAN_DUTY_CYCLE_PERCENTAGE: + { + u32 duty_cycle = reg_val_to_duty_cycle(data->reg_val[FAN_DUTY_CYCLE_PERCENTAGE]); + ret = sprintf(buf, "%u\n", duty_cycle); + break; + } + case FAN1_FRONT_SPEED_RPM: + case FAN2_FRONT_SPEED_RPM: + case FAN3_FRONT_SPEED_RPM: + case FAN4_FRONT_SPEED_RPM: + case FAN5_FRONT_SPEED_RPM: + case FAN6_FRONT_SPEED_RPM: + case FAN1_REAR_SPEED_RPM: + case FAN2_REAR_SPEED_RPM: + case FAN3_REAR_SPEED_RPM: + case FAN4_REAR_SPEED_RPM: + case FAN5_REAR_SPEED_RPM: + case FAN6_REAR_SPEED_RPM: + ret = sprintf(buf, "%u\n", reg_val_to_speed_rpm(data->reg_val[attr->index])); + break; + case FAN_LED_MODE: + ret = sprintf(buf, "%u\n", (data->reg_val[attr->index] >> 7) & 0x01); + break; + case FAN1_DIRECTION: + case FAN2_DIRECTION: + case FAN3_DIRECTION: + case FAN4_DIRECTION: + case FAN5_DIRECTION: + case FAN6_DIRECTION: + ret = sprintf(buf, "%d\n", + reg_val_to_direction(data->reg_val[FAN_DIRECTION_REG], + attr->index - FAN1_DIRECTION)); + break; + case FAN1_PRESENT: + case FAN2_PRESENT: + case FAN3_PRESENT: + case FAN4_PRESENT: + case FAN5_PRESENT: + case FAN6_PRESENT: + ret = sprintf(buf, "%d\n", + reg_val_to_is_present(data->reg_val[FAN_PRESENT_REG], + attr->index - FAN1_PRESENT)); + break; + case FAN1_FAULT: + case FAN2_FAULT: + case FAN3_FAULT: + case FAN4_FAULT: + case FAN5_FAULT: + case FAN6_FAULT: + ret = sprintf(buf, "%d\n", is_fan_fault(data, attr->index - FAN1_FAULT)); + break; + case FAN1_LED: + case FAN2_LED: + case FAN3_LED: + case FAN4_LED: + reg = FAN_LED_DISPLAY1; + offset = 2 * (FAN4_ID - (attr->index - FAN1_LED)); + ret = sprintf(buf, "%d\n", (data->reg_val[reg] >> offset) & 0x03); + break; + case FAN5_LED: + case FAN6_LED: + reg = FAN_LED_DISPLAY2; + offset = 2 * (FAN6_ID - (attr->index - FAN1_LED)); + ret = sprintf(buf, "%d\n", (data->reg_val[reg] >> offset) & 0x03); + break; + case FAN_MAX_RPM: + ret = sprintf(buf, "%d\n", MAX_FAN_SPEED_RPM); + break; + default: + break; + } + + mutex_unlock(&data->update_lock); + } + + return ret; +} + +static const struct attribute_group as9647_32d_fan_group = { + .attrs = as9647_32d_fan_attributes, +}; + +static struct as9647_32d_fan_data *as9647_32d_fan_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_fan_data *data = i2c_get_clientdata(client); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) || + !data->valid) { + int i; + + dev_dbg(&client->dev, "Starting as9647_32d_fan update\n"); + data->valid = 0; + + /* Update fan data + */ + for (i = 0; i < ARRAY_SIZE(data->reg_val); i++) { + int status = as9647_32d_fan_read_value(client, fan_reg[i]); + + if (status < 0) { + data->valid = 0; + mutex_unlock(&data->update_lock); + dev_dbg(&client->dev, "reg %d, err %d\n", fan_reg[i], status); + return data; + } + else { + data->reg_val[i] = status; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + + return data; +} + +static ssize_t show_version(struct device *dev, struct device_attribute *attr, char *buf) +{ + int val = 0; + struct i2c_client *client = to_i2c_client(dev); + + val = i2c_smbus_read_byte_data(client, 0x1); + + if (val < 0) { + dev_dbg(&client->dev, "cpld(0x%x) reg(0x1) err %d\n", client->addr, val); + } + + return sprintf(buf, "%d\n", val); +} + +static int as9647_32d_fan_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as9647_32d_fan_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as9647_32d_fan_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as9647_32d_fan_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, "as9647_32d_fan", + NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: fan '%s'\n", + dev_name(data->hwmon_dev), client->name); + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as9647_32d_fan_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as9647_32d_fan_remove(struct i2c_client *client) +{ + struct as9647_32d_fan_data *data = i2c_get_clientdata(client); + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as9647_32d_fan_group); + + return 0; +} + +/* Addresses to scan */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +static const struct i2c_device_id as9647_32d_fan_id[] = { + { "as9647_32d_fan", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as9647_32d_fan_id); + +static struct i2c_driver as9647_32d_fan_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = DRVNAME, + }, + .probe = as9647_32d_fan_probe, + .remove = as9647_32d_fan_remove, + .id_table = as9647_32d_fan_id, + .address_list = normal_i2c, +}; + +module_i2c_driver(as9647_32d_fan_driver); + +MODULE_AUTHOR("Phani Karanam "); +MODULE_DESCRIPTION("as9647_32d_fan driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-leds.c b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-leds.c new file mode 100644 index 0000000000..52947348aa --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-leds.c @@ -0,0 +1,434 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * A LED driver for the as9647_32d_led + * + * Copyright (C) 2024 Accton Technology Corporation. + * Phani Karanam + * + * Based on: + * es9632xx-leds.c from Brandon Chuang + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define DRVNAME "as9647_32d_led" + +#define DEBUG_MODE 0 + +#if (DEBUG_MODE == 1) + #define DEBUG_PRINT(fmt, args...) \ + printk (KERN_INFO "%s:%s[%d]: " fmt "\r\n", __FILE__, __FUNCTION__, __LINE__, ##args) +#else + #define DEBUG_PRINT(fmt, args...) +#endif + +extern int as9647_32d_cpld_read(unsigned short cpld_addr, u8 reg); +extern int as9647_32d_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + +struct as9647_32d_led_data { + struct platform_device *pdev; + struct mutex update_lock; + char valid; /* != 0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 reg_val[2]; /* Register value, 0 = FAN/PSU LED, + 1 = DIAG LED + */ +}; + +static struct as9647_32d_led_data *ledctl = NULL; + +#define LED_CNTRLER_I2C_ADDRESS (0x61) + +#define LED_TYPE_DIAG_REG_MASK (0x07) +#define LED_MODE_DIAG_OFF_VALUE (0x00) +#define LED_MODE_DIAG_GREEN_VALUE (0x01) +#define LED_MODE_DIAG_AMBER_VALUE (0x02) +#define LED_MODE_DIAG_GREEN_BLINK_VALUE (0x05) +#define LED_MODE_DIAG_AMBER_BLINK_VALUE (0x06) + +#define LED_TYPE_LOC_REG_MASK (0xC0) +#define LED_MODE_LOC_OFF_VALUE (0x00) +#define LED_MODE_LOC_AMBER_VALUE (0x40) +#define LED_MODE_LOC_AMBER_BLINK_VALUE (0xC0) + +#define LED_TYPE_PSU1_REG_MASK (0x03) +#define LED_MODE_PSU1_OFF_VALUE (0x00) +#define LED_MODE_PSU1_GREEN_VALUE (0x01) +#define LED_MODE_PSU1_AMBER_VALUE (0x02) + +#define LED_TYPE_PSU2_REG_MASK (0x0C) +#define LED_MODE_PSU2_OFF_VALUE (0x00) +#define LED_MODE_PSU2_GREEN_VALUE (0x04) +#define LED_MODE_PSU2_AMBER_VALUE (0x08) + +#define LED_TYPE_FAN_REG_MASK (0x30) +#define LED_MODE_FAN_OFF_VALUE (0x00) +#define LED_MODE_FAN_GREEN_VALUE (0x10) +#define LED_MODE_FAN_AMBER_VALUE (0x20) + +static const u8 led_reg[] = { + 0x30, /* LOC LED */ + 0x31, /* DIAG LED */ +}; + +enum led_type { + LED_TYPE_DIAG, + LED_TYPE_LOC, + LED_TYPE_FAN, + LED_TYPE_PSU1, + LED_TYPE_PSU2 +}; + +/* FAN/PSU/DIAG/RELEASE led mode */ +enum led_light_mode { + LED_MODE_OFF = 0, + LED_MODE_GREEN, + LED_MODE_GREEN_BLINK, + LED_MODE_AMBER, + LED_MODE_AMBER_BLINK, + LED_MODE_RED, + LED_MODE_RED_BLINK, + LED_MODE_BLUE, + LED_MODE_BLUE_BLINK, + LED_MODE_AUTO, + LED_MODE_UNKNOWN +}; + +struct led_type_mode { + enum led_type type; + enum led_light_mode mode; + int type_mask; + int mode_value; +}; + +static struct led_type_mode led_type_mode_data[] = { +{LED_TYPE_LOC, LED_MODE_OFF, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_OFF_VALUE}, +{LED_TYPE_LOC, LED_MODE_AMBER, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_VALUE}, +{LED_TYPE_LOC, LED_MODE_AMBER_BLINK, LED_TYPE_LOC_REG_MASK, LED_MODE_LOC_AMBER_BLINK_VALUE}, +{LED_TYPE_DIAG, LED_MODE_GREEN_BLINK, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_BLINK_VALUE}, +{LED_TYPE_DIAG, LED_MODE_GREEN, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_GREEN_VALUE}, +{LED_TYPE_DIAG, LED_MODE_AMBER, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_VALUE}, +{LED_TYPE_DIAG, LED_MODE_AMBER_BLINK, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_AMBER_BLINK_VALUE}, +{LED_TYPE_DIAG, LED_MODE_OFF, LED_TYPE_DIAG_REG_MASK, LED_MODE_DIAG_OFF_VALUE}, +{LED_TYPE_FAN, LED_MODE_GREEN, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_GREEN_VALUE}, +{LED_TYPE_FAN, LED_MODE_AMBER, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_AMBER_VALUE}, +{LED_TYPE_FAN, LED_MODE_OFF, LED_TYPE_FAN_REG_MASK, LED_MODE_FAN_OFF_VALUE}, +{LED_TYPE_PSU1, LED_MODE_GREEN, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_GREEN_VALUE}, +{LED_TYPE_PSU1, LED_MODE_AMBER, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_AMBER_VALUE}, +{LED_TYPE_PSU1, LED_MODE_OFF, LED_TYPE_PSU1_REG_MASK, LED_MODE_PSU1_OFF_VALUE}, +{LED_TYPE_PSU2, LED_MODE_GREEN, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_GREEN_VALUE}, +{LED_TYPE_PSU2, LED_MODE_AMBER, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_AMBER_VALUE}, +{LED_TYPE_PSU2, LED_MODE_OFF, LED_TYPE_PSU2_REG_MASK, LED_MODE_PSU2_OFF_VALUE}, +}; + +static int led_reg_val_to_light_mode(enum led_type type, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + if (type != led_type_mode_data[i].type) { + continue; + } + + if ((led_type_mode_data[i].type_mask & reg_val) == + led_type_mode_data[i].mode_value) { + return led_type_mode_data[i].mode; + } + } + + return LED_MODE_UNKNOWN; +} + +static u8 led_light_mode_to_reg_val(enum led_type type, + enum led_light_mode mode, u8 reg_val) { + int i; + + for (i = 0; i < ARRAY_SIZE(led_type_mode_data); i++) { + int type_mask, mode_value; + + if (type != led_type_mode_data[i].type) + continue; + + if (mode != led_type_mode_data[i].mode) + continue; + + type_mask = led_type_mode_data[i].type_mask; + mode_value = led_type_mode_data[i].mode_value; + reg_val = (reg_val & ~type_mask) | mode_value; + } + + return reg_val; +} + +static int as9647_32d_led_read_value(u8 reg) +{ + return as9647_32d_cpld_read(LED_CNTRLER_I2C_ADDRESS, reg); +} + +static int as9647_32d_led_write_value(u8 reg, u8 value) +{ + return as9647_32d_cpld_write(LED_CNTRLER_I2C_ADDRESS, reg, value); +} + +static void as9647_32d_led_update(void) +{ + mutex_lock(&ledctl->update_lock); + + if (time_after(jiffies, ledctl->last_updated + HZ + HZ / 2) + || !ledctl->valid) { + int i; + + dev_dbg(&ledctl->pdev->dev, "Starting as9647_32d_led update\n"); + ledctl->valid = 0; + + /* Update LED data + */ + for (i = 0; i < ARRAY_SIZE(ledctl->reg_val); i++) { + int status = as9647_32d_led_read_value(led_reg[i]); + + if (status < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", led_reg[i], status); + goto exit; + } + else + ledctl->reg_val[i] = status; + } + + ledctl->last_updated = jiffies; + ledctl->valid = 1; + } + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void as9647_32d_led_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode, + u8 reg, enum led_type type) +{ + int reg_val; + + mutex_lock(&ledctl->update_lock); + reg_val = as9647_32d_led_read_value(reg); + + if (reg_val < 0) { + dev_dbg(&ledctl->pdev->dev, "reg %d, err %d\n", reg, reg_val); + goto exit; + } + + reg_val = led_light_mode_to_reg_val(type, led_light_mode, reg_val); + as9647_32d_led_write_value(reg, reg_val); + ledctl->valid = 0; + +exit: + mutex_unlock(&ledctl->update_lock); +} + +static void as9647_32d_led_fan_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as9647_32d_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_FAN); +} + +static enum led_brightness as9647_32d_led_fan_get(struct led_classdev *cdev) +{ + as9647_32d_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_FAN, ledctl->reg_val[0]); +} + +static void as9647_32d_led_psu1_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as9647_32d_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_PSU1); +} + +static enum led_brightness as9647_32d_led_psu1_get(struct led_classdev *cdev) +{ + as9647_32d_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU1, ledctl->reg_val[0]); +} + +static void as9647_32d_led_psu2_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as9647_32d_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_PSU2); +} + +static enum led_brightness as9647_32d_led_psu2_get(struct led_classdev *cdev) +{ + as9647_32d_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_PSU2, ledctl->reg_val[0]); +} + +static void as9647_32d_led_diag_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as9647_32d_led_set(led_cdev, led_light_mode, led_reg[1], LED_TYPE_DIAG); +} + +static enum led_brightness as9647_32d_led_diag_get(struct led_classdev *cdev) +{ + as9647_32d_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_DIAG, ledctl->reg_val[1]); +} + +static enum led_brightness as9647_32d_led_loc_get(struct led_classdev *cdev) +{ + as9647_32d_led_update(); + return led_reg_val_to_light_mode(LED_TYPE_LOC, ledctl->reg_val[0]); +} + +static void as9647_32d_led_loc_set(struct led_classdev *led_cdev, + enum led_brightness led_light_mode) +{ + as9647_32d_led_set(led_cdev, led_light_mode, led_reg[0], LED_TYPE_LOC); +} + +static struct led_classdev as9647_32d_leds[] = { + [LED_TYPE_LOC] = { + .name = "as9647_32d_led::loc", + .default_trigger = "unused", + .brightness_set = as9647_32d_led_loc_set, + .brightness_get = as9647_32d_led_loc_get, + .max_brightness = LED_MODE_AMBER_BLINK, + }, + [LED_TYPE_DIAG] = { + .name = "as9647_32d_led::diag", + .default_trigger = "unused", + .brightness_set = as9647_32d_led_diag_set, + .brightness_get = as9647_32d_led_diag_get, + .max_brightness = LED_MODE_AMBER_BLINK, + }, + [LED_TYPE_PSU1] = { + .name = "as9647_32d_led::psu1", + .default_trigger = "unused", + .brightness_set = as9647_32d_led_psu1_set, + .brightness_get = as9647_32d_led_psu1_get, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_PSU2] = { + .name = "as9647_32d_led::psu2", + .default_trigger = "unused", + .brightness_set = as9647_32d_led_psu2_set, + .brightness_get = as9647_32d_led_psu2_get, + .max_brightness = LED_MODE_AMBER, + }, + [LED_TYPE_FAN] = { + .name = "as9647_32d_led::fan", + .default_trigger = "unused", + .brightness_set = as9647_32d_led_fan_set, + .brightness_get = as9647_32d_led_fan_get, + .max_brightness = LED_MODE_AMBER, + }, +}; + +static int as9647_32d_led_probe(struct platform_device *pdev) +{ + int ret, i; + + for (i = 0; i < ARRAY_SIZE(as9647_32d_leds); i++) { + ret = led_classdev_register(&pdev->dev, &as9647_32d_leds[i]); + + if (ret < 0) { + break; + } + } + + /* Check if all LEDs were successfully registered */ + if (i != ARRAY_SIZE(as9647_32d_leds)){ + int j; + + /* only unregister the LEDs that were successfully registered */ + for (j = 0; j < i; j++) { + led_classdev_unregister(&as9647_32d_leds[i]); + } + } + + return ret; +} + +static int as9647_32d_led_remove(struct platform_device *pdev) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(as9647_32d_leds); i++) { + led_classdev_unregister(&as9647_32d_leds[i]); + } + + return 0; +} + +static struct platform_driver as9647_32d_led_driver = { + .probe = as9647_32d_led_probe, + .remove = as9647_32d_led_remove, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + }, +}; + +static int __init as9647_32d_led_init(void) +{ + int ret; + + ret = platform_driver_register(&as9647_32d_led_driver); + if (ret < 0) { + goto exit; + } + + ledctl = kzalloc(sizeof(struct as9647_32d_led_data), GFP_KERNEL); + if (!ledctl) { + ret = -ENOMEM; + goto exit_driver; + } + + mutex_init(&ledctl->update_lock); + + ledctl->pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0); + if (IS_ERR(ledctl->pdev)) { + ret = PTR_ERR(ledctl->pdev); + goto exit_free; + } + + return 0; + +exit_free: + kfree(ledctl); +exit_driver: + platform_driver_unregister(&as9647_32d_led_driver); +exit: + return ret; +} + +static void __exit as9647_32d_led_exit(void) +{ + platform_device_unregister(ledctl->pdev); + platform_driver_unregister(&as9647_32d_led_driver); + kfree(ledctl); +} + +late_initcall(as9647_32d_led_init); +module_exit(as9647_32d_led_exit); + +MODULE_AUTHOR("Phani Karanam "); +MODULE_DESCRIPTION("as9647_32d_led driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-psu.c b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-psu.c new file mode 100644 index 0000000000..0691aca583 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/modules/x86-64-as9647-32d-psu.c @@ -0,0 +1,365 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * An hwmon driver for accton as9647_32d Power Module + * + * Copyright (C) 2024 Accton Technology Corporation. + * Phani Karanam + * + * Based on: + * es9632xx-psu.c from Brandon Chuang + * Copyright (C) 2014 Accton Technology Corporation. + * + * Based on ad7414.c + * Copyright 2006 Stefan Roese , DENX Software Engineering + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define PSU_STATUS_I2C_ADDR 0x68 +#define PSU_STATUS_I2C_REG_OFFSET 0x3 + +#define MODEL_NAME_LEN 13 +#define MODEL_NAME_REG_OFFSET 0x20 + +#define SERIAL_NUM_LEN 18 +#define SERIAL_NUM_REG_OFFSET 0x35 + +#define IS_POWER_GOOD(id, value) (!!(value & BIT(id + 2))) +#define IS_PRESENT(id, value) (!(value & BIT(id))) + +static ssize_t show_status(struct device *dev, struct device_attribute *da, char *buf); +static ssize_t show_string(struct device *dev, struct device_attribute *da, char *buf); +extern int as9647_32d_cpld_read(unsigned short cpld_addr, u8 reg); + +/* Addresses scanned + */ +static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; + +/* Each client has this additional data + */ +struct as9647_32d_psu_data { + struct device *hwmon_dev; + struct mutex update_lock; + char valid; /* !=0 if registers are valid */ + unsigned long last_updated; /* In jiffies */ + u8 index; /* PSU index */ + u8 status; /* Status(present/power_good) register read from CPLD */ + char model_name[MODEL_NAME_LEN+1]; /* Model name, read from eeprom */ + char serial[SERIAL_NUM_LEN+1]; /* Serial number, read from eeprom*/ +}; + +static struct as9647_32d_psu_data *as9647_32d_psu_update_device(struct device *dev); + +enum as9647_32d_psu_sysfs_attributes { + PSU_PRESENT, + PSU_MODEL_NAME, + PSU_POWER_GOOD, + PSU_SERIAL_NUMBER +}; + +/* sysfs attributes for hwmon + */ +static SENSOR_DEVICE_ATTR(psu_present, S_IRUGO, show_status, NULL, PSU_PRESENT); +static SENSOR_DEVICE_ATTR(psu_model_name, S_IRUGO, show_string, NULL, PSU_MODEL_NAME); +static SENSOR_DEVICE_ATTR(psu_power_good, S_IRUGO, show_status, NULL, PSU_POWER_GOOD); +static SENSOR_DEVICE_ATTR(psu_serial_number, S_IRUGO, show_string, NULL, PSU_SERIAL_NUMBER); + +static struct attribute *as9647_32d_psu_attributes[] = { + &sensor_dev_attr_psu_present.dev_attr.attr, + &sensor_dev_attr_psu_model_name.dev_attr.attr, + &sensor_dev_attr_psu_power_good.dev_attr.attr, + &sensor_dev_attr_psu_serial_number.dev_attr.attr, + NULL +}; + +static ssize_t show_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_psu_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + u8 status = 0; + + mutex_lock(&data->update_lock); + + data = as9647_32d_psu_update_device(dev); + if (!data->valid) { + mutex_unlock(&data->update_lock); + return sprintf(buf, "0\n"); + } + + if (attr->index == PSU_PRESENT) { + status = IS_PRESENT(data->index, data->status); + } + else { /* PSU_POWER_GOOD */ + status = IS_POWER_GOOD(data->index, data->status); + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%d\n", status); +} + +static ssize_t show_string(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_psu_data *data = i2c_get_clientdata(client); + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + char *str = NULL; + + mutex_lock(&data->update_lock); + + data = as9647_32d_psu_update_device(dev); + if (!data->valid) { + mutex_unlock(&data->update_lock); + return 0; + } + + if (attr->index == PSU_MODEL_NAME) { + str = data->model_name; + } + else { /* PSU_SERIAL_NUBMER */ + str = data->serial; + } + + mutex_unlock(&data->update_lock); + return sprintf(buf, "%s\n", str); +} + +static const struct attribute_group as9647_32d_psu_group = { + .attrs = as9647_32d_psu_attributes, +}; + +static int as9647_32d_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + struct as9647_32d_psu_data *data; + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { + status = -EIO; + goto exit; + } + + data = kzalloc(sizeof(struct as9647_32d_psu_data), GFP_KERNEL); + if (!data) { + status = -ENOMEM; + goto exit; + } + + i2c_set_clientdata(client, data); + data->valid = 0; + data->index = dev_id->driver_data; + mutex_init(&data->update_lock); + + dev_info(&client->dev, "chip found\n"); + + /* Register sysfs hooks */ + status = sysfs_create_group(&client->dev.kobj, &as9647_32d_psu_group); + if (status) { + goto exit_free; + } + + data->hwmon_dev = hwmon_device_register_with_info(&client->dev, "as9647_32d_psu", + NULL, NULL, NULL); + if (IS_ERR(data->hwmon_dev)) { + status = PTR_ERR(data->hwmon_dev); + goto exit_remove; + } + + dev_info(&client->dev, "%s: psu '%s'\n", + dev_name(data->hwmon_dev), client->name); + + return 0; + +exit_remove: + sysfs_remove_group(&client->dev.kobj, &as9647_32d_psu_group); +exit_free: + kfree(data); +exit: + + return status; +} + +static int as9647_32d_psu_remove(struct i2c_client *client) +{ + struct as9647_32d_psu_data *data = i2c_get_clientdata(client); + + hwmon_device_unregister(data->hwmon_dev); + sysfs_remove_group(&client->dev.kobj, &as9647_32d_psu_group); + kfree(data); + + return 0; +} + +enum psu_index +{ + as9647_32d_psu1, + as9647_32d_psu2 +}; + +static const struct i2c_device_id as9647_32d_psu_id[] = { + { "as9647_32d_psu1", as9647_32d_psu1 }, + { "as9647_32d_psu2", as9647_32d_psu2 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, as9647_32d_psu_id); + +static struct i2c_driver as9647_32d_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "as9647_32d_psu", + }, + .probe = as9647_32d_psu_probe, + .remove = as9647_32d_psu_remove, + .id_table = as9647_32d_psu_id, + .address_list = normal_i2c, +}; + +static int as9647_32d_psu_read_byte(struct i2c_client *client, u8 command, u8 *data) +{ + int status = 0; + int retry_count = 5; + + while (retry_count) { + status = i2c_smbus_read_byte_data(client, command); + if (unlikely(status < 0)) { + msleep(10); + retry_count--; + continue; + } + + break; + } + + if (unlikely(status < 0)) { + dev_dbg(&client->dev, "sfp read byte data failed, command(0x%2x), data(0x%2x)\r\n", command, status); + goto abort; + } + + *data = (u8)status; + +abort: + return status; +} + +static int as9647_32d_psu_read_bytes(struct i2c_client *client, u8 command, u8 *data, + int data_len) +{ + int ret = 0; + + while (data_len) { + ssize_t status; + + status = as9647_32d_psu_read_byte(client, command, data); + if (status <= 0) { + ret = status; + break; + } + + data += 1; + command += 1; + data_len -= 1; + } + + return ret; +} + +static struct as9647_32d_psu_data *as9647_32d_psu_update_device(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct as9647_32d_psu_data *data = i2c_get_clientdata(client); + + if (time_after(jiffies, data->last_updated + HZ + HZ / 2) + || !data->valid) { + int status; + + dev_dbg(&client->dev, "Starting as9647_32d update\n"); + data->valid = 0; + + /* Read psu status */ + status = as9647_32d_cpld_read(PSU_STATUS_I2C_ADDR, PSU_STATUS_I2C_REG_OFFSET); + + if (status < 0) { + dev_dbg(&client->dev, "cpld reg (0x%x) err %d\n", PSU_STATUS_I2C_ADDR, status); + goto exit; + } + else { + data->status = status; + } + + + memset(data->model_name, 0, sizeof(data->model_name)); + memset(data->serial, 0, sizeof(data->serial)); + + if (IS_PRESENT(data->index, data->status)) { + /* Read model name */ + status = as9647_32d_psu_read_bytes(client, MODEL_NAME_REG_OFFSET, data->model_name, + ARRAY_SIZE(data->model_name)-1); + if (status < 0) { + data->model_name[0] = '\0'; + dev_dbg(&client->dev, "unable to read model name from (0x%x)\n", client->addr); + goto exit; + } + else { + /* Skip the meaningless data byte */ + data->model_name[6] = '-'; + data->model_name[7] = data->model_name[9]; + data->model_name[8] = data->model_name[10]; + data->model_name[9] = data->model_name[11]; + data->model_name[10] = data->model_name[12]; + data->model_name[11] = '\0'; + } + + /* Read serial number */ + status = as9647_32d_psu_read_bytes(client, SERIAL_NUM_REG_OFFSET, data->serial, + ARRAY_SIZE(data->serial)-1); + if (status < 0) { + data->serial[0] = '\0'; + dev_dbg(&client->dev, "unable to read serial number from (0x%x)\n", client->addr); + goto exit; + } + else { + data->serial[SERIAL_NUM_LEN] = '\0'; + } + } + + data->last_updated = jiffies; + data->valid = 1; + } + +exit: + return data; +} + +module_i2c_driver(as9647_32d_psu_driver); + +MODULE_AUTHOR("Phani Karanam "); +MODULE_DESCRIPTION("Accton as9647_32d PSU driver"); +MODULE_LICENSE("GPL"); + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/service/as9647-32d-platform-init.service b/platform/xsight/sonic-platform-modules-accton/as9647-32d/service/as9647-32d-platform-init.service new file mode 100644 index 0000000000..74f9b803d6 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/service/as9647-32d-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Accton AS9647-32D Platform initialization service +Before=pmon.service +After=sysinit.target +DefaultDependencies=no + +[Service] +Type=oneshot +ExecStart=/usr/local/bin/as9647_32d_util.py install +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/setup.py b/platform/xsight/sonic-platform-modules-accton/as9647-32d/setup.py new file mode 100644 index 0000000000..a38f587d3c --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/setup.py @@ -0,0 +1,16 @@ +#!/usr/bin/env python + +import os +import sys +from setuptools import setup +os.listdir + +setup( + name='as9647_32d', + version='1.0', + description='Module to initialize Accton AS9647_32D platforms', + + packages=['as9647_32d'], + package_dir={'as9647_32d': 'as9647-32d/classes'}, +) + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/sonic_platform_setup.py b/platform/xsight/sonic-platform-modules-accton/as9647-32d/sonic_platform_setup.py new file mode 100644 index 0000000000..ab4308d671 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/sonic_platform_setup.py @@ -0,0 +1,35 @@ +from setuptools import setup + +DEVICE_NAME = 'accton' +HW_SKU = 'x86_64-accton_as9647_32d-r0' + +setup( + name='sonic-platform', + version='1.0', + description='SONiC platform API implementation on Accton Platforms', + license='Apache 2.0', + author='SONiC Team', + author_email='linuxnetdev@microsoft.com', + url='https://github.com/Azure/sonic-buildimage', + maintainer='Brandon Chuang', + maintainer_email='brandon_chuang@edge-core.com', + packages=[ + 'sonic_platform', + ], + package_dir={ + 'sonic_platform': '../../../../device/{}/{}/sonic_platform'.format(DEVICE_NAME, HW_SKU)}, + 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', + 'Programming Language :: Python :: 2.7', + 'Topic :: Utilities', + ], + keywords='sonic SONiC platform PLATFORM', +) diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/udev/70-persistent-net.rules b/platform/xsight/sonic-platform-modules-accton/as9647-32d/udev/70-persistent-net.rules new file mode 100644 index 0000000000..80e731f1e9 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/udev/70-persistent-net.rules @@ -0,0 +1,3 @@ +## CDC Ethernet device +SUBSYSTEM=="net", DRIVERS=="?*", ATTR{address}=="02:00:00:00:00:02", ATTR{type}=="1", NAME="usb0", ACTION=="add" + diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/as9647_32d_util.py b/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/as9647_32d_util.py new file mode 100755 index 0000000000..0d477a5a5b --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/as9647_32d_util.py @@ -0,0 +1,754 @@ +#!/opt/xplt/venv/bin/python +# Copyright (C) 2016 Accton Networks, Inc. +# Copyright (C) 2024 Xsightlabs Ltd. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +""" +Usage: %(scriptName)s [options] command object + +options: + -h | --help : this help message + -d | --debug : run with debug mode + -f | --force : ignore error during installation or clean +command: + install : install drivers and generate related sysfs nodes + clean : uninstall drivers and remove related sysfs nodes + show : show all system status + sff : dump SFP eeprom + set : change board setting with fan|led|sfp +""" + +import subprocess +import getopt +import shlex +import glob +import sys +import logging +import re +import time +import os + +PROJECT_NAME = 'as9647_32d' +version = '0.1.0' +verbose = False +DEBUG = False +ARGS = [] +ALL_DEVICE = {} +DEVICE_NO = { + 'led': 5, + 'fan': 6, + 'thermal': 8, + 'psu': 2, + 'sfp': 32, + } +FORCE = 0 + +# logging.basicConfig(filename= PROJECT_NAME+'.log', filemode='w',level=logging.DEBUG) +# logging.basicConfig(level=logging.INFO) + +if DEBUG == True: + print(sys.argv[0]) + print('ARGV :', sys.argv[1:]) + + +def main(): + global DEBUG + global ARGS + global FORCE + + if len(sys.argv) < 2: + show_help() + + (options, ARGS) = getopt.getopt(sys.argv[1:], 'hdf', + ['help','debug', 'force']) + if DEBUG == True: + print(options) + print(ARGS) + print(len(sys.argv)) + + for (opt, arg) in options: + if opt in ('-h', '--help'): + show_help() + elif opt in ('-d', '--debug'): + DEBUG = True + logging.basicConfig(level=logging.INFO) + elif opt in ('-f', '--force'): + FORCE = 1 + else: + logging.info('no option') + for arg in ARGS: + if arg == 'install': + do_install() + elif arg == 'clean': + do_uninstall() + elif arg == 'api': + do_sonic_platform_install() + elif arg == 'api_clean': + do_sonic_platform_clean() + elif arg == 'show': + device_traversal() + elif arg == 'sff': + if len(ARGS) != 2: + show_eeprom_help() + elif int(ARGS[1]) == 0 or int(ARGS[1]) > DEVICE_NO['sfp']: + show_eeprom_help() + else: + show_eeprom(ARGS[1]) + return + elif arg == 'set': + if len(ARGS) < 3: + show_set_help() + else: + set_device(ARGS[1:]) + return + else: + show_help() + return 0 + + +def show_help(): + print(__doc__ % {'scriptName': sys.argv[0].split('/')[-1]}) + sys.exit(0) + + +def show_set_help(): + cmd = sys.argv[0].split('/')[-1] + ' ' + ARGS[0] + set_help = """{} [led|led_loc|led_diag|led_fan|led_psu1|led_psu2|sfp|fan] + use "{} fan 0-100" to set all fans duty percetage + use "{} sfp 1-16 {{0|1}}" to set sfp# module_lpmode + use "{} led 0-4 " to set all leds to same color + led colors: + 0 = off + 1 = green + 2 = green blinking + 3 = amber + 4 = amber blinking + use "{} led_xxx {{0|1|2|3|4}} to set specific led color + led: + led_loc : set location led {{0|3|4}} + led_diag : set diagnostic led {{0|1|2|3}} + led_fan : set fan led {{0|1|3}} + led_psu1 : set psu1 led {{0|1|3}} + led_psu2 : set psu2 led {{0|1|3}}""".format(cmd, cmd, cmd, cmd, cmd) + print(set_help) + sys.exit(0) + +def show_eeprom_help(): + cmd = sys.argv[0].split('/')[-1] + ' ' + ARGS[0] + print(' use "' + cmd + ' 1-32" to dump sfp# eeprom') + sys.exit(0) + + +def log_dbg(txt): + if DEBUG: + print('[DBG] ' + txt) + + +def run_command(cmd_str, use_sudo=True): + cmd_list = shlex.split(cmd_str) + if use_sudo: + cmd_list.insert(0, 'sudo') + + logging.info('Run :' + cmd_str) + try: + process = subprocess.run( + cmd_list, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True + ) + stdout = process.stdout.strip() + retcode = process.returncode + except Exception as e: + log_dbg(f"Error running command: {e}") + return (1, str(e)) + + log_dbg(cmd_str + ' with result: ' + str(retcode)) + log_dbg(' output: ' + stdout) + + if retcode != 0: + logging.info('Failed :' + cmd_str) + + return (retcode, stdout) + + +def echo_to_file(value, filepath, use_sudo=True): + # Use 'tee' as a safe way to write via subprocess with sudo + try: + cmd_list = ['sudo', 'tee', filepath] if use_sudo else ['tee', filepath] + process = subprocess.run( + cmd_list, + input=value, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + text=True + ) + if process.returncode != 0: + raise Exception(process.stdout.strip()) + return (0, '') + + except Exception as e: + log_dbg(f"Failed to write '{value}' to '{filepath}' with error: {str(e)}") + return (1, str(e)) + + +def list_modules(): + matches = glob.glob('/sys/module/*as9647*') + if matches: + return (0, '\n'.join(matches)) + else: + return (1, '') + + +def grep_file_for_string(filepath, pattern): + try: + with open(filepath, 'r') as f: + for line in f: + if pattern in line: + return (0, line.strip()) + return (1, '') + except Exception as e: + return (1, str(e)) + + +def driver_check(): + ret, out = list_modules() + if ret: + logging.info("Modules: None found") + return False + else: + logging.info(f"Modules: {out}") + return True + + +def read_file_contents(filepath): + try: + with open(filepath, 'r') as f: + contents = f.read() + return 0, contents + except Exception as e: + return (1, str(e)) + +kos = [ + 'modprobe i2c-dev', + 'modprobe i2c_mux_pca954x', + 'modprobe dps850', + 'modprobe optoe', + 'modprobe x86-64-as9647-32d-cpld', + 'modprobe x86-64-as9647-32d-fan', + 'modprobe x86-64-as9647-32d-leds', + 'modprobe x86-64-as9647-32d-psu', + 'modprobe at24', + 'modprobe lm75', + 'modprobe tmp401' + ] + + +def driver_install(): + global FORCE + run_command('depmod') + for i in range(0, len(kos)): + ret = run_command(kos[i]) + if ret[0] and FORCE == 0: + return ret[0] + return 0 + + +def driver_uninstall(): + global FORCE + for i in range(0, len(kos)): + rm = kos[-(i + 1)].replace('modprobe', 'modprobe -rq') + rm = rm.replace('insmod', 'rmmod') + lst = rm.split(' ') + if len(lst) > 3: + del lst[3] + rm = ' '.join(lst) + ret = run_command(rm) + if ret[0] and FORCE == 0: + return ret[0] + return 0 + + +led_prefix = '/sys/class/leds/' + PROJECT_NAME + '_led::' +hwmon_types = {'led': ['diag', 'fan', 'loc', 'psu1', 'psu2']} +leds_dict = {'led_loc': 'loc', 'led_diag': 'diag', 'led_fan': 'fan', 'led_psu1': 'psu1', 'led_psu2': 'psu2'} +hwmon_nodes = {'led': ['brightness']} +hwmon_prefix = {'led': led_prefix} + +i2c_prefix = '/sys/bus/i2c/devices/' +i2c_bus = { + 'fan': ['10-0066'], + 'thermal': ['11-0048', '11-0049', '11-004a', '11-004b', '11-004c', '11-004d', '11-004e', '11-004f'], + 'psu': ['3-0051', '2-0050'], + 'sfp': ['-0050'], + } +i2c_nodes = { + 'fan': ['present', 'front_speed_rpm', 'rear_speed_rpm'], + 'thermal': ['temp1_input'], + 'psu': ['psu_present ', 'psu_power_good'], + 'sfp': ['module_present', 'module_lpmode'], + } + +mknod_entries = [ + ("pca9548", "0x72", "1"), + ("pca9548", "0x73", "1"), + ("pca9548", "0x74", "1"), + ("pca9548", "0x75", "1"), + ("pca9548", "0x70", "1"), + ("pca9548", "0x71", "1"), + ("pca9548", "0x76", "1"), + ("as9647_32d_cpld1", "0x68", "1"), + ("as9647_32d_cpld2", "0x61", "13"), + ("as9647_32d_cpld3", "0x62", "15"), + ("as9647_32d_psu1", "0x51", "3"), + ("as9647_32d_psu2", "0x50", "2"), + ("as9647_32d_fan", "0x66", "10"), + ("dps850", "0x58", "2"), + ("dps850", "0x59", "3"), + ("lm75", "0x48", "11"), + ("lm75", "0x49", "11"), + ("lm75", "0x4a", "11"), + ("lm75", "0x4b", "11"), + ("lm75", "0x4c", "11"), + ("lm75", "0x4d", "11"), + ("lm75", "0x4e", "11"), + ("lm75", "0x4f", "11"), + ("tmp431", "0x4c", "8"), + ("24c256", "0x55", "16"), +] + +sfp_bus_list = ["13-0061", "15-0062"] +sfp_map = list(range(18, 50)) + + +def device_install(): + global FORCE + + for dev, addr, bus in mknod_entries: + path = f"/sys/bus/i2c/devices/i2c-{bus}/new_device" + ret, msg = echo_to_file(f"{dev} {addr}", path) + if ret and FORCE == 0: + return ret + + if dev == "pca9548": + # Allow pca954x to build new i2c buses + time.sleep(0.3) + # Configure pca954x to disconnect on idle + path = f"/sys/bus/i2c/devices/{bus}-00{addr[2:]}/idle_state" + ret, msg = echo_to_file("-2", path) + if ret and FORCE == 0: + return ret + + for count, bus in enumerate(sfp_map, start=1): + path = f"/sys/bus/i2c/devices/i2c-{bus}/new_device" + ret, msg = echo_to_file("optoe3 0x50", path) + if ret and FORCE == 0: + return ret + + path = f"/sys/bus/i2c/devices/{bus}-0050/port_name" + ret, msg = echo_to_file(f"port{count}", path) + if ret and FORCE == 0: + return ret + + # Increase write_timeout value to 250ms to get rid of: + # error: optoe XX-0050: Restore page register to 0 failed:-110! + path = f"/sys/bus/i2c/devices/{bus}-0050/write_timeout" + ret, msg = echo_to_file("250", path) + if ret and FORCE == 0: + return ret + + sfp_bus = sfp_bus_list[count // 17] + path = f"/sys/bus/i2c/devices/{sfp_bus}/module_lpmode_{count}" + ret, msg = echo_to_file("0", path) + if ret and FORCE == 0: + return ret + + # Bring up modules gradually to reduce the power spike at startup + time.sleep(0.1) + + +def device_uninstall(): + global FORCE + + for i in sfp_map: + path = f"/sys/bus/i2c/devices/i2c-{i}/delete_device" + value = "0x50" + ret, msg = echo_to_file(value, path) + if ret and FORCE == 0: + return ret + + for dev, addr, bus in reversed(mknod_entries): + path = f"/sys/bus/i2c/devices/i2c-{bus}/delete_device" + value = f"{addr}" + ret, msg = echo_to_file(value, path) + if ret and FORCE == 0: + return ret + + +def system_ready(): + if driver_check() is False: + return False + if not device_exist(): + return False + return True + +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_API2_WHL_FILE_PY2 ='sonic_platform-1.0-py2-none-any.whl' +PLATFORM_API2_WHL_FILE_PY3 ='sonic_platform-1.0-py3-none-any.whl' +def do_sonic_platform_install(): + device_path = "{}{}{}{}{}".format(PLATFORM_ROOT_PATH, '/x86_64-', 'accton_', PROJECT_NAME, '-r0') + SONIC_PLATFORM_BSP_WHL_PKG_PY3 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY3]) + SONIC_PLATFORM_BSP_WHL_PKG_PY2 = "/".join([device_path, PLATFORM_API2_WHL_FILE_PY2]) + + #Check API2.0 on py whl file + status, output = run_command("pip3 show sonic-platform") + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY3): + status, output = run_command("pip3 install " + SONIC_PLATFORM_BSP_WHL_PKG_PY3) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY3)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY3)) + + #Check API2.0 on py2.7 whl file + status, output = run_command("pip2 show sonic-platform") + if status: + if os.path.exists(SONIC_PLATFORM_BSP_WHL_PKG_PY2): + status, output = run_command("pip2 install " + SONIC_PLATFORM_BSP_WHL_PKG_PY2) + if status: + print("Error: Failed to install {}".format(PLATFORM_API2_WHL_FILE_PY2)) + return status + else: + print("Successfully installed {} package".format(PLATFORM_API2_WHL_FILE_PY2)) + else: + print('{} is not found'.format(PLATFORM_API2_WHL_FILE_PY2)) + else: + print('{} has installed'.format(PLATFORM_API2_WHL_FILE_PY2)) + return + + +def do_sonic_platform_clean(): + status, output = run_command("pip3 show sonic-platform") + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY3)) + + else: + status, output = run_command("pip3 uninstall sonic-platform -y") + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY3)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY3)) + + status, output = run_command("pip2 show sonic-platform") + if status: + print('{} does not install, not need to uninstall'.format(PLATFORM_API2_WHL_FILE_PY2)) + + else: + status, output = run_command("pip2 uninstall sonic-platform -y") + if status: + print('Error: Failed to uninstall {}'.format(PLATFORM_API2_WHL_FILE_PY2)) + return status + else: + print('{} is uninstalled'.format(PLATFORM_API2_WHL_FILE_PY2)) + + return + + +def set_i2c_bus_indexing_order(): + fname = os.path.basename(__file__) + try: + path = "/sys/bus/i2c/devices/i2c-{}/name" + patt = "I801" + res0, i2c_0 = grep_file_for_string(path.format(0), patt) + res1, i2c_1 = grep_file_for_string(path.format(1), patt) + if int(res0) + int(res1) > 1: + raise SystemExit(f'{fname}: Cannot find i2c master device!') + if int(res0) == 0: + path = "/dev/kmsg" + value = f"echo {fname}: Swapp i2c buses" + ret0, log = echo_to_file(value, path) + ret1, log = run_command("rmmod i2c_ismt") + ret2, log = run_command("rmmod i2c_i801") + ret3, log = run_command("modprobe i2c_ismt") + ret4, log = run_command("modprobe i2c_i801") + if ret1 or ret2 or ret3 or ret4: + return False + return True + + except Exception as err: + print(f'{fname}: {err=}, {type(err)=}') + raise + + +def do_install(): + print('Checking system....') + + if not set_i2c_bus_indexing_order(): + sys.exit(1) + + if driver_check() is False: + print('No driver, installing....') + status = driver_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' drivers detected....') + if not device_exist(): + print('No device, installing....') + status = device_install() + if status: + if FORCE == 0: + return status + else: + print(PROJECT_NAME.upper() + ' devices detected....') + + do_sonic_platform_install() + + return 0 + + +def do_uninstall(): + print('Checking system....') + if not device_exist(): + print(PROJECT_NAME.upper() + ' has no device installed....') + else: + print('Removing device....') + status = device_uninstall() + if status and FORCE == 0: + return status + + if driver_check() is False: + print(PROJECT_NAME.upper() + ' has no driver installed....') + else: + print('Removing installed driver....') + status = driver_uninstall() + if status and FORCE == 0: + return status + + do_sonic_platform_clean() + + return 0 + + +def devices_info(): + global DEVICE_NO + global ALL_DEVICE + global i2c_bus, hwmon_types + for key in DEVICE_NO: + ALL_DEVICE[key] = {} + for i in range(0, DEVICE_NO[key]): + ALL_DEVICE[key][key + str(i + 1)] = [] + + for key in i2c_bus: + buses = i2c_bus[key] + nodes = i2c_nodes[key] + for i in range(0, len(buses)): + for j in range(0, len(nodes)): + if 'fan' == key: + for k in range(0, DEVICE_NO[key]): + node = key + str(k + 1) + path = i2c_prefix + buses[i] + '/fan' + str(k + + 1) + '_' + nodes[j] + log_dbg(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + elif 'sfp' == key: + for k in range(0, DEVICE_NO[key]): + node = key + str(k + 1) + fmt = i2c_prefix + "13-0061/{}_{}" + path = fmt.format(nodes[j], k + 1) + log_dbg(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + elif 'thermal' == key: + node = key + str(i + 1) + fmt = i2c_prefix + "{}/hwmon/hwmon{}/{}" + path = fmt.format(buses[i], int(buses[0][6:]) + i, nodes[j]) + log_dbg(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + else: + node = key + str(i + 1) + path = i2c_prefix + buses[i] + '/' + nodes[j] + log_dbg(node + ': ' + path) + ALL_DEVICE[key][node].append(path) + + for key in hwmon_types: + itypes = hwmon_types[key] + nodes = hwmon_nodes[key] + for i in range(0, len(itypes)): + for j in range(0, len(nodes)): + node = key + '_' + itypes[i] + path = hwmon_prefix[key] + itypes[i] + '/' + nodes[j] + log_dbg(node + ': ' + path) + ALL_DEVICE[key][key + str(i + 1)].append(path) + + if DEBUG == True: + for i in sorted(ALL_DEVICE.keys()): + print(i + ': ') + for j in sorted(ALL_DEVICE[i].keys()): + print(' ' + j) + for k in ALL_DEVICE[i][j]: + print(' ' + ' ' + k) + return + + +def show_eeprom(index): + if system_ready() is False: + print('Systems not ready.') + print('Please install first!') + return + + if len(ALL_DEVICE) == 0: + devices_info() + + node = f"{i2c_prefix}{sfp_map[int(index) - 1]}{i2c_bus['sfp'][0]}/eeprom" + # Check if got hexdump command in current environment + ret, out = run_command('which hexdump') + ret, out2 = run_command('which busybox hexdump') + if out: + hex_cmd = ["hexdump", "-C"] + elif out2: + hex_cmd = ["busybox", "hexdump", "-C"] + else: + logging.info(out) + print(out) + return 1 + + print(node + ':') + + # Read the binary contents of the EEPROM file + with open(node, "rb") as f: + data = f.read(256) + + # Run hexdump -C using subprocess, pass binary data through stdin + process = subprocess.run( + hex_cmd, + input=data, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + retcode = process.returncode + + if retcode == 0: + print(process.stdout.decode()) + else: + print( '**********device no found**********') + return + + +def set_device(args): + global DEVICE_NO + global ALL_DEVICE + if system_ready() is False: + print('System is not ready.') + print('Please install first!') + return + + if not ALL_DEVICE: + devices_info() + + if args[0] == 'led': + if int(args[1]) > 4: + show_set_help() + return + + for i in range(0, len(ALL_DEVICE['led'])): + for k in ALL_DEVICE['led']['led' + str(i + 1)]: + ret, log = echo_to_file(args[1], k) + if ret: + return ret + + elif args[0] in leds_dict: + ret = set_specific_led(leds_dict[args[0]], args[1]) + if ret: + return ret + + elif args[0] == 'fan': + if int(args[1]) > 100: + show_set_help() + return + + node = ALL_DEVICE['fan']['fan1'][0] + node = node.replace(node.split('/')[-1], + 'fan_duty_cycle_percentage') + ret, log = read_file_contents(node) + if ret == 0: + print('Previous fan duty: ' + log.strip() + '%') + ret, log = echo_to_file(args[1], node) + if ret == 0: + print('Current fan duty: ' + args[1] + '%') + return ret + elif args[0] == 'sfp': + if len(args) < 2 or int(args[1]) == 0 or int(args[2]) > 1: + show_set_help() + return + + for j in ALL_DEVICE[args[0]][args[0] + str(args[1])]: + if j.find('module_lpmode') != -1: + ret, log = echo_to_file(args[2], j) + if ret: + return ret + return + +def set_specific_led(led, mode): + for i in range(0, len(ALL_DEVICE['led'])): + for k in ALL_DEVICE['led']['led' + str(i + 1)]: + if led in k: + ret, log = echo_to_file(mode, k) + return ret + +# Extract digits from string +def get_value(i): + digit = re.findall('\d+', i) + return int(digit[0]) + + +def device_traversal(): + if system_ready() is False: + print("System is not ready.") + print('Please install first!') + return + + if not ALL_DEVICE: + devices_info() + for i in sorted(ALL_DEVICE.keys()): + print('============================================') + print(i.upper() + ': ') + print('============================================') + for j in sorted(ALL_DEVICE[i].keys(), key=get_value): + print(' ' + j + ':',) + for k in ALL_DEVICE[i][j]: + (ret, log) = run_command('cat ' + k, 0) + func = k.split('/')[-1].strip() + func = re.sub(j + '_', '', func, 1) + func = re.sub(i.lower() + '_', '', func, 1) + if ret == 0: + print(func + '=' + log + ' ',) + else: + print(func + '=' + 'X' + ' ',) + print() + print() + return + +def device_exist(): + return os.path.exists("{}1-0072".format(i2c_prefix)) + +if __name__ == '__main__': + main() diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/cpu_wdt.py b/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/cpu_wdt.py new file mode 100755 index 0000000000..5568ea4c35 --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/cpu_wdt.py @@ -0,0 +1,45 @@ +#!/usr/bin/python + +from sonic_platform.chassis import Chassis +from sonic_py_common import logger +import time +import os +import signal +import sys + + +TIMEOUT=180 +KEEPALIVE=60 +sonic_logger = logger.Logger('Watchdog') +sonic_logger.set_min_log_priority_info() +chassis = Chassis() +watchdog = chassis.get_watchdog() + +def stopWdtService(signal, frame): + watchdog._disablewatchdog() + sonic_logger.log_notice("CPUWDT Disabled: watchdog armed=%s" % watchdog.is_armed() ) + sys.exit() + +def main(): + + signal.signal(signal.SIGHUP, signal.SIG_IGN) + signal.signal(signal.SIGINT, stopWdtService) + signal.signal(signal.SIGTERM, stopWdtService) + + watchdog.arm(TIMEOUT) + sonic_logger.log_notice("CPUWDT Enabled: watchdog armed=%s" % watchdog.is_armed() ) + + + while True: + time.sleep(KEEPALIVE) + watchdog._keepalive() + sonic_logger.log_info("CPUWDT keepalive") + done + + stopWdtService + + return + + +if __name__ == '__main__': + main() diff --git a/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/hw-management-generate-dump.sh b/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/hw-management-generate-dump.sh new file mode 100644 index 0000000000..a3bf32e3ca --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/as9647-32d/utils/hw-management-generate-dump.sh @@ -0,0 +1,54 @@ +#!/bin/bash + +dump_folder="/tmp/hw-mgmt-dump" +tmp_script="tmp_script.sh" + +if [ -d $dump_folder ]; then + rm -rf $dump_folder +fi + +mkdir $dump_folder + +dump_cmd() { + echo "=============================== $@ (start)" + "$@" + echo -e "=============================== $@ (end)\n\n\n" +} + +{ + dump_cmd show platform firmware status + dump_cmd show platform firmware updates + dump_cmd show platform ssdhealth + dump_cmd show boot + dump_cmd w + dump_cmd dmidecode -t1 -t2 -t 11 + +} > $dump_folder/general.txt + +{ + for file in `ls /sys/bus/i2c/devices/ | sort -g`; + do + device_name=$(cat /sys/bus/i2c/devices/$file/name) + echo -e "${file} name: $device_name \n" + done +} > $dump_folder/i2cdevices.txt + +cat > /tmp/$tmp_script < Wed, 14 Apr 2021 12:52:27 +0000 + +sonic-accton-platform-modules (1.1) unstable; urgency=low + + * Add support for Accton AS9647-32D + + -- Xsight Labs Wed, 3 Sep 2025 10:50:30 +0000 diff --git a/platform/xsight/sonic-platform-modules-accton/debian/control b/platform/xsight/sonic-platform-modules-accton/debian/control index 5a4245b4a7..6118358a8d 100755 --- a/platform/xsight/sonic-platform-modules-accton/debian/control +++ b/platform/xsight/sonic-platform-modules-accton/debian/control @@ -8,3 +8,7 @@ Standards-Version: 3.9.3 Package: sonic-platform-accton-es9618xx Architecture: amd64 Description: kernel modules for platform devices such as fan, led, sfp + +Package: sonic-platform-accton-as9647-32d +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp diff --git a/platform/xsight/sonic-platform-modules-accton/debian/rules b/platform/xsight/sonic-platform-modules-accton/debian/rules index 66e1942efc..45d6a1c3b7 100755 --- a/platform/xsight/sonic-platform-modules-accton/debian/rules +++ b/platform/xsight/sonic-platform-modules-accton/debian/rules @@ -19,7 +19,7 @@ PACKAGE_PRE_NAME := sonic-platform-accton KVERSION ?= $(shell uname -r) KERNEL_SRC := /lib/modules/$(KVERSION) MOD_SRC_DIR:= $(shell pwd) -MODULE_DIRS := es9618xx +MODULE_DIRS := es9618xx as9647-32d MODULE_DIR := modules UTILS_DIR := utils SERVICE_DIR := service diff --git a/platform/xsight/sonic-platform-modules-accton/debian/sonic-platform-accton-as9647-32d.install b/platform/xsight/sonic-platform-modules-accton/debian/sonic-platform-accton-as9647-32d.install new file mode 100644 index 0000000000..d57dbf5bce --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/debian/sonic-platform-accton-as9647-32d.install @@ -0,0 +1,7 @@ +as9647-32d/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/x86_64-accton_as9647_32d-r0 +as9647-32d/files/link/70-xsight-eth10g0.link usr/lib/systemd/network +as9647-32d/files/link/70-xsight-eth10g1.link usr/lib/systemd/network +as9647-32d/files/link/70-xsight-eth10g2.link usr/lib/systemd/network +as9647-32d/files/link/70-xsight-eth10g3.link usr/lib/systemd/network +as9647-32d/files/link/70-xsight-eth1g0.link usr/lib/systemd/network +as9647-32d/files/link/70-xsight-eth1g1.link usr/lib/systemd/network diff --git a/platform/xsight/sonic-platform-modules-accton/debian/sonic-platform-accton-as9647-32d.postinst b/platform/xsight/sonic-platform-modules-accton/debian/sonic-platform-accton-as9647-32d.postinst new file mode 100644 index 0000000000..43f729116d --- /dev/null +++ b/platform/xsight/sonic-platform-modules-accton/debian/sonic-platform-accton-as9647-32d.postinst @@ -0,0 +1 @@ +#DEBHELPER# diff --git a/platform/xsight/xplt.mk b/platform/xsight/xplt.mk index 7f03b04ce6..2eff9ee472 100644 --- a/platform/xsight/xplt.mk +++ b/platform/xsight/xplt.mk @@ -2,9 +2,15 @@ # Add platform specific tools +XPLT_SRV = "https://raw.githubusercontent.com/xsightlabs/SONiC/main/amd64/utils/" -ACCTON_ES9618XX_XPLT_PLATFORM_MODULE = xplt-es9618xx-sonicnos_3.4.0-17-g4c4924b_amd64.deb -ES9618XX_XPLT_SRV = "https://raw.githubusercontent.com/xsightlabs/SONiC/main/amd64/utils/" -$(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE)_URL = $(ES9618XX_XPLT_SRV)$(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE) +ACCTON_ES9618XX_XPLT_PLATFORM_MODULE = xplt-es9618xx-sonicnos_3.4.0-30-g23215d0_amd64.deb +$(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE)_URL = $(XPLT_SRV)$(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE) $(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE)_PLATFORM = x86_64-accton_es9618xx-r0 SONIC_ONLINE_DEBS += $(ACCTON_ES9618XX_XPLT_PLATFORM_MODULE) + +ACCTON_AS9647_32D_XPLT_PLATFORM_MODULE = xplt-as9647-32d-sonicnos_3.4.0-83-g154a4ca_amd64.deb +$(ACCTON_AS9647_32D_XPLT_PLATFORM_MODULE)_URL = $(XPLT_SRV)$(ACCTON_AS9647_32D_XPLT_PLATFORM_MODULE) +$(ACCTON_AS9647_32D_XPLT_PLATFORM_MODULE)_PLATFORM = x86_64-accton_as9647_32d-r0 +SONIC_ONLINE_DEBS += $(ACCTON_AS9647_32D_XPLT_PLATFORM_MODULE) +