diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/default_sku b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/default_sku new file mode 100644 index 000000000000..5dc4f8a03888 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/default_sku @@ -0,0 +1 @@ +fn8656-bnf l2 diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers.json.j2 b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers.json.j2 new file mode 100644 index 000000000000..9354b7ec5b59 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers.json.j2 @@ -0,0 +1,2 @@ +{%- set default_topo = 't0' %} +{%- include 'buffers_config.j2' %} \ No newline at end of file diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers_defaults_t0.j2 b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers_defaults_t0.j2 new file mode 100644 index 000000000000..1cd9a15bc86e --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers_defaults_t0.j2 @@ -0,0 +1,61 @@ +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '20971328' %} +{% set ingress_lossy_pool_size = '20971328' %} +{% set egress_lossless_pool_size = '20971328' %} +{% set egress_lossy_pool_size = '20971328' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0, 56) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx*4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_lossless_pool_size }}", + "type": "ingress", + "mode": "static" + }, + "ingress_lossy_pool": { + "size": "{{ ingress_lossy_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_lossless_pool_size }}", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossy_pool": { + "size": "{{ egress_lossy_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "xon":"78400", + "xoff":"132160", + "size":"3584", + "static_th":"82880" + }, + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"3584", + "dynamic_th":"-1" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "static_th":"{{ egress_lossless_pool_size }}" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"3584", + "dynamic_th":"-4" + } + }, +{%- endmacro %} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers_defaults_t1.j2 b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers_defaults_t1.j2 new file mode 100644 index 000000000000..1cd9a15bc86e --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/buffers_defaults_t1.j2 @@ -0,0 +1,61 @@ +{% set default_cable = '5m' %} +{% set ingress_lossless_pool_size = '20971328' %} +{% set ingress_lossy_pool_size = '20971328' %} +{% set egress_lossless_pool_size = '20971328' %} +{% set egress_lossy_pool_size = '20971328' %} + +{%- macro generate_port_lists(PORT_ALL) %} + {# Generate list of ports #} + {%- for port_idx in range(0, 56) %} + {%- if PORT_ALL.append("Ethernet%d" % (port_idx*4)) %}{%- endif %} + {%- endfor %} +{%- endmacro %} + +{%- macro generate_buffer_pool_and_profiles() %} + "BUFFER_POOL": { + "ingress_lossless_pool": { + "size": "{{ ingress_lossless_pool_size }}", + "type": "ingress", + "mode": "static" + }, + "ingress_lossy_pool": { + "size": "{{ ingress_lossy_pool_size }}", + "type": "ingress", + "mode": "dynamic" + }, + "egress_lossless_pool": { + "size": "{{ egress_lossless_pool_size }}", + "type": "egress", + "mode": "dynamic" + }, + "egress_lossy_pool": { + "size": "{{ egress_lossy_pool_size }}", + "type": "egress", + "mode": "dynamic" + } + }, + "BUFFER_PROFILE": { + "ingress_lossless_profile": { + "pool":"[BUFFER_POOL|ingress_lossless_pool]", + "xon":"78400", + "xoff":"132160", + "size":"3584", + "static_th":"82880" + }, + "ingress_lossy_profile": { + "pool":"[BUFFER_POOL|ingress_lossy_pool]", + "size":"3584", + "dynamic_th":"-1" + }, + "egress_lossless_profile": { + "pool":"[BUFFER_POOL|egress_lossless_pool]", + "size":"0", + "static_th":"{{ egress_lossless_pool_size }}" + }, + "egress_lossy_profile": { + "pool":"[BUFFER_POOL|egress_lossy_pool]", + "size":"3584", + "dynamic_th":"-4" + } + }, +{%- endmacro %} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/lightning-fn8656_bnf.dsh b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/lightning-fn8656_bnf.dsh new file mode 100755 index 000000000000..b55e10de11ab --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/lightning-fn8656_bnf.dsh @@ -0,0 +1,1011 @@ +init start stage unit=0 low-level +init set port-map unit=0 port=0 eth-macro=12 lane=4 max-speed=100g active=true +init set port-map unit=0 port=1 eth-macro=12 lane=5 max-speed=50g active=false +init set port-map unit=0 port=2 eth-macro=12 lane=6 max-speed=100g active=false +init set port-map unit=0 port=3 eth-macro=12 lane=7 max-speed=50g active=false +init set port-map unit=0 port=4 eth-macro=13 lane=4 max-speed=100g active=true +init set port-map unit=0 port=5 eth-macro=13 lane=5 max-speed=50g active=false +init set port-map unit=0 port=6 eth-macro=13 lane=6 max-speed=100g active=false +init set port-map unit=0 port=7 eth-macro=13 lane=7 max-speed=50g active=false +init set port-map unit=0 port=8 eth-macro=12 lane=0 max-speed=100g active=true +init set port-map unit=0 port=9 eth-macro=12 lane=1 max-speed=50g active=false +init set port-map unit=0 port=10 eth-macro=12 lane=2 max-speed=100g active=false +init set port-map unit=0 port=11 eth-macro=12 lane=3 max-speed=50g active=false +init set port-map unit=0 port=12 eth-macro=13 lane=0 max-speed=100g active=true +init set port-map unit=0 port=13 eth-macro=13 lane=1 max-speed=50g active=false +init set port-map unit=0 port=14 eth-macro=13 lane=2 max-speed=100g active=false +init set port-map unit=0 port=15 eth-macro=13 lane=3 max-speed=50g active=false +init set port-map unit=0 port=16 eth-macro=14 lane=4 max-speed=100g active=true +init set port-map unit=0 port=17 eth-macro=14 lane=5 max-speed=50g active=false +init set port-map unit=0 port=18 eth-macro=14 lane=6 max-speed=100g active=false +init set port-map unit=0 port=19 eth-macro=14 lane=7 max-speed=50g active=false +init set port-map unit=0 port=20 eth-macro=15 lane=4 max-speed=100g active=true +init set port-map unit=0 port=21 eth-macro=15 lane=5 max-speed=50g active=false +init set port-map unit=0 port=22 eth-macro=15 lane=6 max-speed=100g active=false +init set port-map unit=0 port=23 eth-macro=15 lane=7 max-speed=50g active=false +init set port-map unit=0 port=24 eth-macro=14 lane=0 max-speed=100g active=true +init set port-map unit=0 port=25 eth-macro=14 lane=1 max-speed=50g active=false +init set port-map unit=0 port=26 eth-macro=14 lane=2 max-speed=100g active=false +init set port-map unit=0 port=27 eth-macro=14 lane=3 max-speed=50g active=false +init set port-map unit=0 port=28 eth-macro=15 lane=0 max-speed=100g active=true +init set port-map unit=0 port=29 eth-macro=15 lane=1 max-speed=50g active=false +init set port-map unit=0 port=30 eth-macro=15 lane=2 max-speed=100g active=false +init set port-map unit=0 port=31 eth-macro=15 lane=3 max-speed=50g active=false +init set port-map unit=0 port=32 eth-macro=16 lane=0 max-speed=100g active=true +init set port-map unit=0 port=33 eth-macro=16 lane=1 max-speed=50g active=false +init set port-map unit=0 port=34 eth-macro=16 lane=2 max-speed=100g active=false +init set port-map unit=0 port=35 eth-macro=16 lane=3 max-speed=50g active=false +init set port-map unit=0 port=36 eth-macro=17 lane=0 max-speed=100g active=true +init set port-map unit=0 port=37 eth-macro=17 lane=1 max-speed=50g active=false +init set port-map unit=0 port=38 eth-macro=17 lane=2 max-speed=100g active=false +init set port-map unit=0 port=39 eth-macro=17 lane=3 max-speed=50g active=false +init set port-map unit=0 port=40 eth-macro=16 lane=4 max-speed=100g active=true +init set port-map unit=0 port=41 eth-macro=16 lane=5 max-speed=50g active=false +init set port-map unit=0 port=42 eth-macro=16 lane=6 max-speed=100g active=false +init set port-map unit=0 port=43 eth-macro=16 lane=7 max-speed=50g active=false +init set port-map unit=0 port=44 eth-macro=17 lane=4 max-speed=100g active=true +init set port-map unit=0 port=45 eth-macro=17 lane=5 max-speed=50g active=false +init set port-map unit=0 port=46 eth-macro=17 lane=6 max-speed=100g active=false +init set port-map unit=0 port=47 eth-macro=17 lane=7 max-speed=50g active=false +init set port-map unit=0 port=48 eth-macro=18 lane=0 max-speed=100g active=true +init set port-map unit=0 port=49 eth-macro=18 lane=1 max-speed=50g active=false +init set port-map unit=0 port=50 eth-macro=18 lane=2 max-speed=100g active=false +init set port-map unit=0 port=51 eth-macro=18 lane=3 max-speed=50g active=false +init set port-map unit=0 port=52 eth-macro=19 lane=0 max-speed=100g active=true +init set port-map unit=0 port=53 eth-macro=19 lane=1 max-speed=50g active=false +init set port-map unit=0 port=54 eth-macro=19 lane=2 max-speed=100g active=false +init set port-map unit=0 port=55 eth-macro=19 lane=3 max-speed=50g active=false +init set port-map unit=0 port=56 eth-macro=18 lane=4 max-speed=100g active=true +init set port-map unit=0 port=57 eth-macro=18 lane=5 max-speed=50g active=false +init set port-map unit=0 port=58 eth-macro=18 lane=6 max-speed=100g active=false +init set port-map unit=0 port=59 eth-macro=18 lane=7 max-speed=50g active=false +init set port-map unit=0 port=60 eth-macro=19 lane=4 max-speed=100g active=true +init set port-map unit=0 port=61 eth-macro=19 lane=5 max-speed=50g active=false +init set port-map unit=0 port=62 eth-macro=19 lane=6 max-speed=100g active=false +init set port-map unit=0 port=63 eth-macro=19 lane=7 max-speed=50g active=false +init set port-map unit=0 port=64 eth-macro=4 lane=4 max-speed=100g active=true +init set port-map unit=0 port=65 eth-macro=4 lane=5 max-speed=50g active=false +init set port-map unit=0 port=66 eth-macro=4 lane=6 max-speed=100g active=false +init set port-map unit=0 port=67 eth-macro=4 lane=7 max-speed=50g active=false +init set port-map unit=0 port=68 eth-macro=5 lane=4 max-speed=100g active=true +init set port-map unit=0 port=69 eth-macro=5 lane=5 max-speed=50g active=false +init set port-map unit=0 port=70 eth-macro=5 lane=6 max-speed=100g active=false +init set port-map unit=0 port=71 eth-macro=5 lane=7 max-speed=50g active=false +init set port-map unit=0 port=72 eth-macro=4 lane=0 max-speed=100g active=true +init set port-map unit=0 port=73 eth-macro=4 lane=1 max-speed=50g active=false +init set port-map unit=0 port=74 eth-macro=4 lane=2 max-speed=100g active=false +init set port-map unit=0 port=75 eth-macro=4 lane=3 max-speed=50g active=false +init set port-map unit=0 port=76 eth-macro=5 lane=0 max-speed=100g active=true +init set port-map unit=0 port=77 eth-macro=5 lane=1 max-speed=50g active=false +init set port-map unit=0 port=78 eth-macro=5 lane=2 max-speed=100g active=false +init set port-map unit=0 port=79 eth-macro=5 lane=3 max-speed=50g active=false +init set port-map unit=0 port=80 eth-macro=6 lane=4 max-speed=100g active=true +init set port-map unit=0 port=81 eth-macro=6 lane=5 max-speed=50g active=false +init set port-map unit=0 port=82 eth-macro=6 lane=6 max-speed=100g active=false +init set port-map unit=0 port=83 eth-macro=6 lane=7 max-speed=50g active=false +init set port-map unit=0 port=84 eth-macro=7 lane=4 max-speed=100g active=true +init set port-map unit=0 port=85 eth-macro=7 lane=5 max-speed=50g active=false +init set port-map unit=0 port=86 eth-macro=7 lane=6 max-speed=100g active=false +init set port-map unit=0 port=87 eth-macro=7 lane=7 max-speed=50g active=false +init set port-map unit=0 port=88 eth-macro=6 lane=0 max-speed=100g active=true +init set port-map unit=0 port=89 eth-macro=6 lane=1 max-speed=50g active=false +init set port-map unit=0 port=90 eth-macro=6 lane=2 max-speed=100g active=false +init set port-map unit=0 port=91 eth-macro=6 lane=3 max-speed=50g active=false +init set port-map unit=0 port=92 eth-macro=7 lane=0 max-speed=100g active=true +init set port-map unit=0 port=93 eth-macro=7 lane=1 max-speed=50g active=false +init set port-map unit=0 port=94 eth-macro=7 lane=2 max-speed=100g active=false +init set port-map unit=0 port=95 eth-macro=7 lane=3 max-speed=50g active=false +init set port-map unit=0 port=96 eth-macro=8 lane=0 max-speed=100g active=true +init set port-map unit=0 port=97 eth-macro=8 lane=1 max-speed=50g active=false +init set port-map unit=0 port=98 eth-macro=8 lane=2 max-speed=100g active=false +init set port-map unit=0 port=99 eth-macro=8 lane=3 max-speed=50g active=false +init set port-map unit=0 port=100 eth-macro=9 lane=0 max-speed=100g active=true +init set port-map unit=0 port=101 eth-macro=9 lane=1 max-speed=50g active=false +init set port-map unit=0 port=102 eth-macro=9 lane=2 max-speed=100g active=false +init set port-map unit=0 port=103 eth-macro=9 lane=3 max-speed=50g active=false +init set port-map unit=0 port=104 eth-macro=8 lane=4 max-speed=100g active=true +init set port-map unit=0 port=105 eth-macro=8 lane=5 max-speed=50g active=false +init set port-map unit=0 port=106 eth-macro=8 lane=6 max-speed=100g active=false +init set port-map unit=0 port=107 eth-macro=8 lane=7 max-speed=50g active=false +init set port-map unit=0 port=108 eth-macro=9 lane=4 max-speed=100g active=true +init set port-map unit=0 port=109 eth-macro=9 lane=5 max-speed=50g active=false +init set port-map unit=0 port=110 eth-macro=9 lane=6 max-speed=100g active=false +init set port-map unit=0 port=111 eth-macro=9 lane=7 max-speed=50g active=false +init set port-map unit=0 port=112 eth-macro=10 lane=0 max-speed=100g active=true +init set port-map unit=0 port=113 eth-macro=10 lane=1 max-speed=50g active=false +init set port-map unit=0 port=114 eth-macro=10 lane=2 max-speed=100g active=false +init set port-map unit=0 port=115 eth-macro=10 lane=3 max-speed=50g active=false +init set port-map unit=0 port=116 eth-macro=11 lane=0 max-speed=100g active=true +init set port-map unit=0 port=117 eth-macro=11 lane=1 max-speed=50g active=false +init set port-map unit=0 port=118 eth-macro=11 lane=2 max-speed=100g active=false +init set port-map unit=0 port=119 eth-macro=11 lane=3 max-speed=50g active=false +init set port-map unit=0 port=120 eth-macro=10 lane=4 max-speed=100g active=true +init set port-map unit=0 port=121 eth-macro=10 lane=5 max-speed=50g active=false +init set port-map unit=0 port=122 eth-macro=10 lane=6 max-speed=100g active=false +init set port-map unit=0 port=123 eth-macro=10 lane=7 max-speed=50g active=false +init set port-map unit=0 port=124 eth-macro=11 lane=4 max-speed=100g active=true +init set port-map unit=0 port=125 eth-macro=11 lane=5 max-speed=50g active=false +init set port-map unit=0 port=126 eth-macro=11 lane=6 max-speed=100g active=false +init set port-map unit=0 port=127 eth-macro=11 lane=7 max-speed=50g active=false +init set port-map unit=0 port=128 eth-macro=28 lane=4 max-speed=100g active=true +init set port-map unit=0 port=129 eth-macro=28 lane=5 max-speed=50g active=false +init set port-map unit=0 port=130 eth-macro=28 lane=6 max-speed=100g active=false +init set port-map unit=0 port=131 eth-macro=28 lane=7 max-speed=50g active=false +init set port-map unit=0 port=132 eth-macro=29 lane=4 max-speed=100g active=true +init set port-map unit=0 port=133 eth-macro=29 lane=5 max-speed=50g active=false +init set port-map unit=0 port=134 eth-macro=29 lane=6 max-speed=100g active=false +init set port-map unit=0 port=135 eth-macro=29 lane=7 max-speed=50g active=false +init set port-map unit=0 port=136 eth-macro=28 lane=0 max-speed=100g active=true +init set port-map unit=0 port=137 eth-macro=28 lane=1 max-speed=50g active=false +init set port-map unit=0 port=138 eth-macro=28 lane=2 max-speed=100g active=false +init set port-map unit=0 port=139 eth-macro=28 lane=3 max-speed=50g active=false +init set port-map unit=0 port=140 eth-macro=29 lane=0 max-speed=100g active=true +init set port-map unit=0 port=141 eth-macro=29 lane=1 max-speed=50g active=false +init set port-map unit=0 port=142 eth-macro=29 lane=2 max-speed=100g active=false +init set port-map unit=0 port=143 eth-macro=29 lane=3 max-speed=50g active=false +init set port-map unit=0 port=144 eth-macro=30 lane=4 max-speed=100g active=true +init set port-map unit=0 port=145 eth-macro=30 lane=5 max-speed=50g active=false +init set port-map unit=0 port=146 eth-macro=30 lane=6 max-speed=100g active=false +init set port-map unit=0 port=147 eth-macro=30 lane=7 max-speed=50g active=false +init set port-map unit=0 port=148 eth-macro=31 lane=4 max-speed=100g active=true +init set port-map unit=0 port=149 eth-macro=31 lane=5 max-speed=50g active=false +init set port-map unit=0 port=150 eth-macro=31 lane=6 max-speed=100g active=false +init set port-map unit=0 port=151 eth-macro=31 lane=7 max-speed=50g active=false +init set port-map unit=0 port=152 eth-macro=30 lane=0 max-speed=100g active=true +init set port-map unit=0 port=153 eth-macro=30 lane=1 max-speed=50g active=false +init set port-map unit=0 port=154 eth-macro=30 lane=2 max-speed=100g active=false +init set port-map unit=0 port=155 eth-macro=30 lane=3 max-speed=50g active=false +init set port-map unit=0 port=156 eth-macro=31 lane=0 max-speed=100g active=true +init set port-map unit=0 port=157 eth-macro=31 lane=1 max-speed=50g active=false +init set port-map unit=0 port=158 eth-macro=31 lane=2 max-speed=100g active=false +init set port-map unit=0 port=159 eth-macro=31 lane=3 max-speed=50g active=false +init set port-map unit=0 port=160 eth-macro=0 lane=0 max-speed=100g active=true +init set port-map unit=0 port=161 eth-macro=0 lane=1 max-speed=50g active=false +init set port-map unit=0 port=162 eth-macro=0 lane=2 max-speed=100g active=false +init set port-map unit=0 port=163 eth-macro=0 lane=3 max-speed=50g active=false +init set port-map unit=0 port=164 eth-macro=1 lane=0 max-speed=100g active=true +init set port-map unit=0 port=165 eth-macro=1 lane=1 max-speed=50g active=false +init set port-map unit=0 port=166 eth-macro=1 lane=2 max-speed=100g active=false +init set port-map unit=0 port=167 eth-macro=1 lane=3 max-speed=50g active=false +init set port-map unit=0 port=168 eth-macro=0 lane=4 max-speed=100g active=true +init set port-map unit=0 port=169 eth-macro=0 lane=5 max-speed=50g active=false +init set port-map unit=0 port=170 eth-macro=0 lane=6 max-speed=100g active=false +init set port-map unit=0 port=171 eth-macro=0 lane=7 max-speed=50g active=false +init set port-map unit=0 port=172 eth-macro=1 lane=4 max-speed=100g active=true +init set port-map unit=0 port=173 eth-macro=1 lane=5 max-speed=50g active=false +init set port-map unit=0 port=174 eth-macro=1 lane=6 max-speed=100g active=false +init set port-map unit=0 port=175 eth-macro=1 lane=7 max-speed=50g active=false +init set port-map unit=0 port=176 eth-macro=2 lane=0 max-speed=100g active=true +init set port-map unit=0 port=177 eth-macro=2 lane=1 max-speed=50g active=false +init set port-map unit=0 port=178 eth-macro=2 lane=2 max-speed=100g active=false +init set port-map unit=0 port=179 eth-macro=2 lane=3 max-speed=50g active=false +init set port-map unit=0 port=180 eth-macro=3 lane=0 max-speed=100g active=true +init set port-map unit=0 port=181 eth-macro=3 lane=1 max-speed=50g active=false +init set port-map unit=0 port=182 eth-macro=3 lane=2 max-speed=100g active=false +init set port-map unit=0 port=183 eth-macro=3 lane=3 max-speed=50g active=false +init set port-map unit=0 port=184 eth-macro=2 lane=4 max-speed=100g active=true +init set port-map unit=0 port=185 eth-macro=2 lane=5 max-speed=50g active=false +init set port-map unit=0 port=186 eth-macro=2 lane=6 max-speed=100g active=false +init set port-map unit=0 port=187 eth-macro=2 lane=7 max-speed=50g active=false +init set port-map unit=0 port=188 eth-macro=3 lane=4 max-speed=100g active=true +init set port-map unit=0 port=189 eth-macro=3 lane=5 max-speed=50g active=false +init set port-map unit=0 port=190 eth-macro=3 lane=6 max-speed=100g active=false +init set port-map unit=0 port=191 eth-macro=3 lane=7 max-speed=50g active=false +init set port-map unit=0 port=192 eth-macro=20 lane=0 max-speed=400g active=true +init set port-map unit=0 port=193 eth-macro=20 lane=1 max-speed=50g active=false +init set port-map unit=0 port=194 eth-macro=20 lane=2 max-speed=100g active=false +init set port-map unit=0 port=195 eth-macro=20 lane=3 max-speed=50g active=false +init set port-map unit=0 port=196 eth-macro=20 lane=4 max-speed=200g active=false +init set port-map unit=0 port=197 eth-macro=20 lane=5 max-speed=50g active=false +init set port-map unit=0 port=198 eth-macro=20 lane=6 max-speed=100g active=false +init set port-map unit=0 port=199 eth-macro=20 lane=7 max-speed=50g active=false +init set port-map unit=0 port=200 eth-macro=21 lane=0 max-speed=400g active=true +init set port-map unit=0 port=201 eth-macro=21 lane=1 max-speed=50g active=false +init set port-map unit=0 port=202 eth-macro=21 lane=2 max-speed=100g active=false +init set port-map unit=0 port=203 eth-macro=21 lane=3 max-speed=50g active=false +init set port-map unit=0 port=204 eth-macro=21 lane=4 max-speed=200g active=false +init set port-map unit=0 port=205 eth-macro=21 lane=5 max-speed=50g active=false +init set port-map unit=0 port=206 eth-macro=21 lane=6 max-speed=100g active=false +init set port-map unit=0 port=207 eth-macro=21 lane=7 max-speed=50g active=false +init set port-map unit=0 port=208 eth-macro=22 lane=0 max-speed=400g active=true +init set port-map unit=0 port=209 eth-macro=22 lane=1 max-speed=50g active=false +init set port-map unit=0 port=210 eth-macro=22 lane=2 max-speed=100g active=false +init set port-map unit=0 port=211 eth-macro=22 lane=3 max-speed=50g active=false +init set port-map unit=0 port=212 eth-macro=22 lane=4 max-speed=200g active=false +init set port-map unit=0 port=213 eth-macro=22 lane=5 max-speed=50g active=false +init set port-map unit=0 port=214 eth-macro=22 lane=6 max-speed=100g active=false +init set port-map unit=0 port=215 eth-macro=22 lane=7 max-speed=50g active=false +init set port-map unit=0 port=216 eth-macro=23 lane=0 max-speed=400g active=true +init set port-map unit=0 port=217 eth-macro=23 lane=1 max-speed=50g active=false +init set port-map unit=0 port=218 eth-macro=23 lane=2 max-speed=100g active=false +init set port-map unit=0 port=219 eth-macro=23 lane=3 max-speed=50g active=false +init set port-map unit=0 port=220 eth-macro=23 lane=4 max-speed=200g active=false +init set port-map unit=0 port=221 eth-macro=23 lane=5 max-speed=50g active=false +init set port-map unit=0 port=222 eth-macro=23 lane=6 max-speed=100g active=false +init set port-map unit=0 port=223 eth-macro=23 lane=7 max-speed=50g active=false +init set port-map unit=0 port=224 eth-macro=24 lane=0 max-speed=400g active=true +init set port-map unit=0 port=225 eth-macro=24 lane=1 max-speed=50g active=false +init set port-map unit=0 port=226 eth-macro=24 lane=2 max-speed=100g active=false +init set port-map unit=0 port=227 eth-macro=24 lane=3 max-speed=50g active=false +init set port-map unit=0 port=228 eth-macro=24 lane=4 max-speed=200g active=false +init set port-map unit=0 port=229 eth-macro=24 lane=5 max-speed=50g active=false +init set port-map unit=0 port=230 eth-macro=24 lane=6 max-speed=100g active=false +init set port-map unit=0 port=231 eth-macro=24 lane=7 max-speed=50g active=false +init set port-map unit=0 port=232 eth-macro=25 lane=0 max-speed=400g active=true +init set port-map unit=0 port=233 eth-macro=25 lane=1 max-speed=50g active=false +init set port-map unit=0 port=234 eth-macro=25 lane=2 max-speed=100g active=false +init set port-map unit=0 port=235 eth-macro=25 lane=3 max-speed=50g active=false +init set port-map unit=0 port=236 eth-macro=25 lane=4 max-speed=200g active=false +init set port-map unit=0 port=237 eth-macro=25 lane=5 max-speed=50g active=false +init set port-map unit=0 port=238 eth-macro=25 lane=6 max-speed=100g active=false +init set port-map unit=0 port=239 eth-macro=25 lane=7 max-speed=50g active=false +init set port-map unit=0 port=240 eth-macro=26 lane=0 max-speed=400g active=true +init set port-map unit=0 port=241 eth-macro=26 lane=1 max-speed=50g active=false +init set port-map unit=0 port=242 eth-macro=26 lane=2 max-speed=100g active=false +init set port-map unit=0 port=243 eth-macro=26 lane=3 max-speed=50g active=false +init set port-map unit=0 port=244 eth-macro=26 lane=4 max-speed=200g active=false +init set port-map unit=0 port=245 eth-macro=26 lane=5 max-speed=50g active=false +init set port-map unit=0 port=246 eth-macro=26 lane=6 max-speed=100g active=false +init set port-map unit=0 port=247 eth-macro=26 lane=7 max-speed=50g active=false +init set port-map unit=0 port=248 eth-macro=27 lane=0 max-speed=400g active=true +init set port-map unit=0 port=249 eth-macro=27 lane=1 max-speed=50g active=false +init set port-map unit=0 port=250 eth-macro=27 lane=2 max-speed=100g active=false +init set port-map unit=0 port=251 eth-macro=27 lane=3 max-speed=50g active=false +init set port-map unit=0 port=252 eth-macro=27 lane=4 max-speed=200g active=false +init set port-map unit=0 port=253 eth-macro=27 lane=5 max-speed=50g active=false +init set port-map unit=0 port=254 eth-macro=27 lane=6 max-speed=100g active=false +init set port-map unit=0 port=255 eth-macro=27 lane=7 max-speed=50g active=false +init set port-map unit=0 port=257 eth-macro=32 lane=0 max-speed=10g active=true guarantee=true cpi=true +init set port-map unit=0 port=258 eth-macro=32 lane=1 max-speed=10g active=true guarantee=true cpi=true init-done=true +init start stage unit=0 task-rsrc +init start stage unit=0 module +init start stage unit=0 task + +phy set lane-swap unit=0 portlist=0 lane-cnt=4 property=tx data=0x7.5.4.6 +phy set lane-swap unit=0 portlist=4 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=8 lane-cnt=4 property=tx data=0x3.0.1.2 +phy set lane-swap unit=0 portlist=12 lane-cnt=4 property=tx data=0x2.1.3.0 +phy set lane-swap unit=0 portlist=16 lane-cnt=4 property=tx data=0x6.4.5.7 +phy set lane-swap unit=0 portlist=20 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=24 lane-cnt=4 property=tx data=0x2.0.3.1 +phy set lane-swap unit=0 portlist=28 lane-cnt=4 property=tx data=0x3.0.1.2 +phy set lane-swap unit=0 portlist=32 lane-cnt=4 property=tx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=36 lane-cnt=4 property=tx data=0x2.0.3.1 +phy set lane-swap unit=0 portlist=40 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=44 lane-cnt=4 property=tx data=0x6.4.5.7 +phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=tx data=0x2.1.3.0 +phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=tx data=0x3.0.1.2 +phy set lane-swap unit=0 portlist=56 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=60 lane-cnt=4 property=tx data=0x7.5.4.6 +phy set lane-swap unit=0 portlist=64 lane-cnt=4 property=tx data=0x7.4.5.6 +phy set lane-swap unit=0 portlist=68 lane-cnt=4 property=tx data=0x7.5.4.6 +phy set lane-swap unit=0 portlist=72 lane-cnt=4 property=tx data=0x3.1.0.2 +phy set lane-swap unit=0 portlist=76 lane-cnt=4 property=tx data=0x2.0.3.1 +phy set lane-swap unit=0 portlist=80 lane-cnt=4 property=tx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=84 lane-cnt=4 property=tx data=0x7.5.4.6 +phy set lane-swap unit=0 portlist=88 lane-cnt=4 property=tx data=0x3.0.2.1 +phy set lane-swap unit=0 portlist=92 lane-cnt=4 property=tx data=0x3.1.0.2 +phy set lane-swap unit=0 portlist=96 lane-cnt=4 property=tx data=0x3.1.2.0 +phy set lane-swap unit=0 portlist=100 lane-cnt=4 property=tx data=0x3.0.1.2 +phy set lane-swap unit=0 portlist=104 lane-cnt=4 property=tx data=0x6.5.7.4 +phy set lane-swap unit=0 portlist=108 lane-cnt=4 property=tx data=0x6.4.7.5 +phy set lane-swap unit=0 portlist=112 lane-cnt=4 property=tx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=116 lane-cnt=4 property=tx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=120 lane-cnt=4 property=tx data=0x6.4.5.7 +phy set lane-swap unit=0 portlist=124 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=128 lane-cnt=4 property=tx data=0x7.6.5.4 +phy set lane-swap unit=0 portlist=132 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=136 lane-cnt=4 property=tx data=0x3.1.0.2 +phy set lane-swap unit=0 portlist=140 lane-cnt=4 property=tx data=0x2.0.1.3 +phy set lane-swap unit=0 portlist=144 lane-cnt=4 property=tx data=0x7.5.4.6 +phy set lane-swap unit=0 portlist=148 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=152 lane-cnt=4 property=tx data=0x3.1.0.2 +phy set lane-swap unit=0 portlist=156 lane-cnt=4 property=tx data=0x2.1.0.3 +phy set lane-swap unit=0 portlist=160 lane-cnt=4 property=tx data=0x2.1.0.3 +phy set lane-swap unit=0 portlist=164 lane-cnt=4 property=tx data=0x3.1.0.2 +phy set lane-swap unit=0 portlist=168 lane-cnt=4 property=tx data=0x7.4.6.5 +phy set lane-swap unit=0 portlist=172 lane-cnt=4 property=tx data=0x7.5.4.6 +phy set lane-swap unit=0 portlist=176 lane-cnt=4 property=tx data=0x2.0.1.3 +phy set lane-swap unit=0 portlist=180 lane-cnt=4 property=tx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=184 lane-cnt=4 property=tx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=188 lane-cnt=4 property=tx data=0x7.6.5.4 +phy set lane-swap unit=0 portlist=192 lane-cnt=8 property=tx data=0x7.6.4.5.1.3.2.0 +phy set lane-swap unit=0 portlist=200 lane-cnt=8 property=tx data=0x6.7.4.5.3.0.1.2 +phy set lane-swap unit=0 portlist=208 lane-cnt=8 property=tx data=0x6.7.4.5.3.2.0.1 +phy set lane-swap unit=0 portlist=216 lane-cnt=8 property=tx data=0x5.4.6.7.3.2.1.0 +phy set lane-swap unit=0 portlist=224 lane-cnt=8 property=tx data=0x7.6.5.4.0.3.1.2 +phy set lane-swap unit=0 portlist=232 lane-cnt=8 property=tx data=0x5.7.4.6.0.1.3.2 +phy set lane-swap unit=0 portlist=240 lane-cnt=8 property=tx data=0x5.6.4.7.2.3.0.1 +phy set lane-swap unit=0 portlist=248 lane-cnt=8 property=tx data=0x4.5.7.6.3.2.1.0 +phy set lane-swap unit=0 portlist=258 lane-cnt=1 property=tx data=0x1 +phy set lane-swap unit=0 portlist=0 lane-cnt=4 property=rx data=0x7.6.5.4 +phy set lane-swap unit=0 portlist=4 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=8 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=12 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=16 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=20 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=24 lane-cnt=4 property=rx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=28 lane-cnt=4 property=rx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=32 lane-cnt=4 property=rx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=36 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=40 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=44 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=48 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=52 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=56 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=60 lane-cnt=4 property=rx data=0x7.6.5.4 +phy set lane-swap unit=0 portlist=64 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=68 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=72 lane-cnt=4 property=rx data=0x1.0.2.3 +phy set lane-swap unit=0 portlist=76 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=80 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=84 lane-cnt=4 property=rx data=0x6.5.4.7 +phy set lane-swap unit=0 portlist=88 lane-cnt=4 property=rx data=0x2.1.0.3 +phy set lane-swap unit=0 portlist=92 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=96 lane-cnt=4 property=rx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=100 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=104 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=108 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=112 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=116 lane-cnt=4 property=rx data=0x1.0.2.3 +phy set lane-swap unit=0 portlist=120 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=124 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=128 lane-cnt=4 property=rx data=0x7.6.4.5 +phy set lane-swap unit=0 portlist=132 lane-cnt=4 property=rx data=0x7.6.5.4 +phy set lane-swap unit=0 portlist=136 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=140 lane-cnt=4 property=rx data=0x1.0.3.2 +phy set lane-swap unit=0 portlist=144 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=148 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=152 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=156 lane-cnt=4 property=rx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=160 lane-cnt=4 property=rx data=0x3.2.0.1 +phy set lane-swap unit=0 portlist=164 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=168 lane-cnt=4 property=rx data=0x5.4.6.7 +phy set lane-swap unit=0 portlist=172 lane-cnt=4 property=rx data=0x5.4.7.6 +phy set lane-swap unit=0 portlist=176 lane-cnt=4 property=rx data=0x1.0.2.3 +phy set lane-swap unit=0 portlist=180 lane-cnt=4 property=rx data=0x3.2.1.0 +phy set lane-swap unit=0 portlist=184 lane-cnt=4 property=rx data=0x7.6.4.5 +phy set lane-swap unit=0 portlist=188 lane-cnt=4 property=rx data=0x7.6.5.4 +phy set lane-swap unit=0 portlist=192 lane-cnt=8 property=rx data=0x5.4.7.6.1.0.3.2 +phy set lane-swap unit=0 portlist=200 lane-cnt=8 property=rx data=0x6.7.5.4.2.0.3.1 +phy set lane-swap unit=0 portlist=208 lane-cnt=8 property=rx data=0x6.4.7.5.2.0.3.1 +phy set lane-swap unit=0 portlist=216 lane-cnt=8 property=rx data=0x6.7.5.4.1.3.0.2 +phy set lane-swap unit=0 portlist=224 lane-cnt=8 property=rx data=0x4.6.7.5.2.1.3.0 +phy set lane-swap unit=0 portlist=232 lane-cnt=8 property=rx data=0x4.5.6.7.3.1.0.2 +phy set lane-swap unit=0 portlist=240 lane-cnt=8 property=rx data=0x6.7.5.4.3.0.2.1 +phy set lane-swap unit=0 portlist=248 lane-cnt=8 property=rx data=0x5.4.6.7.3.1.2.0 +phy set lane-swap unit=0 portlist=258 lane-cnt=1 property=rx data=0x1 +phy set polarity-rev unit=0 portlist=0 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=4 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=8 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=12 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=16 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=20 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=24 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=28 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=32 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=36 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=40 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=44 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=48 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=56 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=60 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=64 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=68 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=72 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=76 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=80 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=84 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=88 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=92 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=96 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=100 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=104 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=108 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=112 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=116 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=120 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=124 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=128 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=132 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=136 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=140 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=144 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=148 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=152 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=156 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=160 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=164 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=168 lane-cnt=4 property=tx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=172 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=176 lane-cnt=4 property=tx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=180 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=184 lane-cnt=4 property=tx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=188 lane-cnt=4 property=tx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=192 lane-cnt=8 property=tx data=0x1.0.1.1.1.1.0.1 +phy set polarity-rev unit=0 portlist=200 lane-cnt=8 property=tx data=0x0.0.0.0.0.0.0.1 +phy set polarity-rev unit=0 portlist=208 lane-cnt=8 property=tx data=0x0.1.0.1.1.1.1.0 +phy set polarity-rev unit=0 portlist=216 lane-cnt=8 property=tx data=0x0.1.1.0.1.0.1.0 +phy set polarity-rev unit=0 portlist=224 lane-cnt=8 property=tx data=0x1.1.0.1.0.1.1.0 +phy set polarity-rev unit=0 portlist=232 lane-cnt=8 property=tx data=0x1.1.0.0.0.0.0.1 +phy set polarity-rev unit=0 portlist=240 lane-cnt=8 property=tx data=0x0.1.0.0.0.0.0.0 +phy set polarity-rev unit=0 portlist=248 lane-cnt=8 property=tx data=0x1.1.0.0.0.0.1.1 +phy set polarity-rev unit=0 portlist=258 lane-cnt=1 property=tx data=0x0 +phy set polarity-rev unit=0 portlist=0 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=4 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=8 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=12 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=16 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=20 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=24 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=28 lane-cnt=4 property=rx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=32 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=36 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=40 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=44 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=48 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=52 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=56 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=60 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=64 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=68 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=72 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=76 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=80 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=84 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=88 lane-cnt=4 property=rx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=92 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=96 lane-cnt=4 property=rx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=100 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=104 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=108 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=112 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=116 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=120 lane-cnt=4 property=rx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=124 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=128 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=132 lane-cnt=4 property=rx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=136 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=140 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=144 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=148 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=152 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=156 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=160 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=164 lane-cnt=4 property=rx data=0x0.0.1.0 +phy set polarity-rev unit=0 portlist=168 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=172 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=176 lane-cnt=4 property=rx data=0x0.0.0.1 +phy set polarity-rev unit=0 portlist=180 lane-cnt=4 property=rx data=0x0.0.1.1 +phy set polarity-rev unit=0 portlist=184 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=188 lane-cnt=4 property=rx data=0x0.0.0.0 +phy set polarity-rev unit=0 portlist=192 lane-cnt=8 property=rx data=0x0.0.0.1.0.1.0.1 +phy set polarity-rev unit=0 portlist=200 lane-cnt=8 property=rx data=0x0.1.1.1.0.1.1.1 +phy set polarity-rev unit=0 portlist=208 lane-cnt=8 property=rx data=0x1.1.0.0.0.0.1.1 +phy set polarity-rev unit=0 portlist=216 lane-cnt=8 property=rx data=0x0.1.1.0.1.0.1.0 +phy set polarity-rev unit=0 portlist=224 lane-cnt=8 property=rx data=0x0.0.1.1.1.1.1.0 +phy set polarity-rev unit=0 portlist=232 lane-cnt=8 property=rx data=0x1.0.1.0.1.0.1.1 +phy set polarity-rev unit=0 portlist=240 lane-cnt=8 property=rx data=0x0.1.1.1.1.1.0.1 +phy set polarity-rev unit=0 portlist=248 lane-cnt=8 property=rx data=0x0.0.1.0.0.0.1.0 +phy set polarity-rev unit=0 portlist=258 lane-cnt=1 property=rx data=0x0 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c0 data=0x2a.29.2a.2a +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=cn2 data=0x02.01.01.01 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f7 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=c1 data=0xf5.f6.f5.f6 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=4 lane-cnt=4 property=c0 data=0x29.27.28.29 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=8 lane-cnt=4 property=c0 data=0x2a.2a.2a.29 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=cn2 data=0x02.02.02.02 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=cn1 data=0xf7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=c1 data=0xf6.f6.f6.f5 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=12 lane-cnt=4 property=c0 data=0x2a.29.2a.28 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f8 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=16 lane-cnt=4 property=c0 data=0x29.2a.2a.29 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=cn2 data=0x02.01.02.01 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=cn1 data=0xf7.f6.f7.f9 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=20 lane-cnt=4 property=c0 data=0x2a.29.2a.29 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=24 lane-cnt=4 property=c0 data=0x29.2a.2a.2a +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=cn2 data=0x02.02.02.02 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=cn1 data=0xf7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=28 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=cn1 data=0xf6.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=c1 data=0xf6.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=32 lane-cnt=4 property=c0 data=0x2a.2c.2c.29 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=cn2 data=0x02.02.02.02 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=cn1 data=0xf7.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=c1 data=0xf6.f5.f6.f5 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=36 lane-cnt=4 property=c0 data=0x2a.28.2a.28 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=cn2 data=0x01.01.01.02 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=cn1 data=0xf6.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=c1 data=0xf6.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=40 lane-cnt=4 property=c0 data=0x2a.2a.2a.2b +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=cn2 data=0x02.02.01.02 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=cn1 data=0xf7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=44 lane-cnt=4 property=c0 data=0x2a.2a.29.2a +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=cn1 data=0xf7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=c1 data=0xf7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=48 lane-cnt=4 property=c0 data=0x2a.2c.2c.2a +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=cn2 data=0x01.02.02.02 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=cn1 data=0xf8.f7.f8.f7 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=c1 data=0xf7.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=52 lane-cnt=4 property=c0 data=0x29.2a.2a.2a +phy set pre-emphasis unit=0 portlist=56 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=56 lane-cnt=4 property=cn1 data=0xf6.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=56 lane-cnt=4 property=c1 data=0xf6.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=56 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=56 lane-cnt=4 property=c0 data=0x29.2c.2b.29 +phy set pre-emphasis unit=0 portlist=60 lane-cnt=4 property=cn2 data=0x01.02.02.02 +phy set pre-emphasis unit=0 portlist=60 lane-cnt=4 property=cn1 data=0xf8.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=60 lane-cnt=4 property=c1 data=0xf7.f5.f6.f6 +phy set pre-emphasis unit=0 portlist=60 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=60 lane-cnt=4 property=c0 data=0x29.28.2a.2a +phy set pre-emphasis unit=0 portlist=64 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=64 lane-cnt=4 property=cn1 data=0xf7.f7.f8.f8 +phy set pre-emphasis unit=0 portlist=64 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=64 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=64 lane-cnt=4 property=c0 data=0x28.28.28.28 +phy set pre-emphasis unit=0 portlist=68 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=68 lane-cnt=4 property=cn1 data=0xf7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=68 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=68 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=68 lane-cnt=4 property=c0 data=0x29.29.29.29 +phy set pre-emphasis unit=0 portlist=72 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=72 lane-cnt=4 property=cn1 data=0xf7.f8.f7.f7 +phy set pre-emphasis unit=0 portlist=72 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=72 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=72 lane-cnt=4 property=c0 data=0x28.28.28.28 +phy set pre-emphasis unit=0 portlist=76 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=76 lane-cnt=4 property=cn1 data=0xf6.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=76 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=76 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=76 lane-cnt=4 property=c0 data=0x2a.2a.29.29 +phy set pre-emphasis unit=0 portlist=80 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=80 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=80 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=80 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=80 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=84 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=84 lane-cnt=4 property=cn1 data=0xf6.f7.f6.f6 +phy set pre-emphasis unit=0 portlist=84 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=84 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=84 lane-cnt=4 property=c0 data=0x2a.29.2a.2a +phy set pre-emphasis unit=0 portlist=88 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=88 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=88 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=88 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=88 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=92 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=92 lane-cnt=4 property=cn1 data=0xf7.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=92 lane-cnt=4 property=c1 data=0xf7.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=92 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=92 lane-cnt=4 property=c0 data=0x29.2a.2a.2a +phy set pre-emphasis unit=0 portlist=96 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=96 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=96 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=96 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=96 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=100 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=100 lane-cnt=4 property=cn1 data=0xf6.f7.f6.f6 +phy set pre-emphasis unit=0 portlist=100 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=100 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=100 lane-cnt=4 property=c0 data=0x2a.29.2a.2a +phy set pre-emphasis unit=0 portlist=104 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=104 lane-cnt=4 property=cn1 data=0xf6.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=104 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=104 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=104 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=108 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=108 lane-cnt=4 property=cn1 data=0xf6.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=108 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=108 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=108 lane-cnt=4 property=c0 data=0x2a.2a.28.2a +phy set pre-emphasis unit=0 portlist=112 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=112 lane-cnt=4 property=cn1 data=0xf6.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=112 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=112 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=112 lane-cnt=4 property=c0 data=0x2a.29.29.29 +phy set pre-emphasis unit=0 portlist=116 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=116 lane-cnt=4 property=cn1 data=0xf8.f6.f6.f8 +phy set pre-emphasis unit=0 portlist=116 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=116 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=116 lane-cnt=4 property=c0 data=0x29.2a.2a.27 +phy set pre-emphasis unit=0 portlist=120 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=120 lane-cnt=4 property=cn1 data=0xf7.f7.f8.f7 +phy set pre-emphasis unit=0 portlist=120 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=120 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=120 lane-cnt=4 property=c0 data=0x2a.29.2a.29 +phy set pre-emphasis unit=0 portlist=124 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=124 lane-cnt=4 property=cn1 data=0xf6.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=124 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=124 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=124 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=128 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=128 lane-cnt=4 property=cn1 data=0xf7.f7.f8.f8 +phy set pre-emphasis unit=0 portlist=128 lane-cnt=4 property=c1 data=0xf7.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=128 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=128 lane-cnt=4 property=c0 data=0x2c.2b.2a.2b +phy set pre-emphasis unit=0 portlist=132 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=132 lane-cnt=4 property=cn1 data=0xf8.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=132 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=132 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=132 lane-cnt=4 property=c0 data=0x2b.2a.2a.2a +phy set pre-emphasis unit=0 portlist=136 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=136 lane-cnt=4 property=cn1 data=0xf6.f7.f6.f7 +phy set pre-emphasis unit=0 portlist=136 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=136 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=136 lane-cnt=4 property=c0 data=0x2a.2b.2a.2b +phy set pre-emphasis unit=0 portlist=140 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=140 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f7 +phy set pre-emphasis unit=0 portlist=140 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=140 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=140 lane-cnt=4 property=c0 data=0x2a.2a.2a.2b +phy set pre-emphasis unit=0 portlist=144 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=144 lane-cnt=4 property=cn1 data=0xf7.f8.f6.f7 +phy set pre-emphasis unit=0 portlist=144 lane-cnt=4 property=c1 data=0xf7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=144 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=144 lane-cnt=4 property=c0 data=0x2c.2c.2b.2c +phy set pre-emphasis unit=0 portlist=148 lane-cnt=4 property=cn2 data=0x02.01.01.01 +phy set pre-emphasis unit=0 portlist=148 lane-cnt=4 property=cn1 data=0xf8.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=148 lane-cnt=4 property=c1 data=0xf6.f7.f6.f6 +phy set pre-emphasis unit=0 portlist=148 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=148 lane-cnt=4 property=c0 data=0x29.2c.2a.2b +phy set pre-emphasis unit=0 portlist=152 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=152 lane-cnt=4 property=cn1 data=0xf7.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=152 lane-cnt=4 property=c1 data=0xf7.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=152 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=152 lane-cnt=4 property=c0 data=0x2c.2a.2a.2a +phy set pre-emphasis unit=0 portlist=156 lane-cnt=4 property=cn2 data=0x02.02.02.02 +phy set pre-emphasis unit=0 portlist=156 lane-cnt=4 property=cn1 data=0xf7.f6.f7.f7 +phy set pre-emphasis unit=0 portlist=156 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=156 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=156 lane-cnt=4 property=c0 data=0x2a.29.2a.2a +phy set pre-emphasis unit=0 portlist=160 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=160 lane-cnt=4 property=cn1 data=0xf7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=160 lane-cnt=4 property=c1 data=0xf7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=160 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=160 lane-cnt=4 property=c0 data=0x2c.2c.2c.2a +phy set pre-emphasis unit=0 portlist=164 lane-cnt=4 property=cn2 data=0x02.02.02.02 +phy set pre-emphasis unit=0 portlist=164 lane-cnt=4 property=cn1 data=0xf7.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=164 lane-cnt=4 property=c1 data=0xf6.f5.f6.f5 +phy set pre-emphasis unit=0 portlist=164 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=164 lane-cnt=4 property=c0 data=0x2a.28.2a.28 +phy set pre-emphasis unit=0 portlist=168 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=168 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f7 +phy set pre-emphasis unit=0 portlist=168 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=168 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=168 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=172 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=172 lane-cnt=4 property=cn1 data=0xf6.f7.f6.f6 +phy set pre-emphasis unit=0 portlist=172 lane-cnt=4 property=c1 data=0xf6.f6.f5.f5 +phy set pre-emphasis unit=0 portlist=172 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=172 lane-cnt=4 property=c0 data=0x2a.2a.29.29 +phy set pre-emphasis unit=0 portlist=176 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=176 lane-cnt=4 property=cn1 data=0xf7.f6.f6.f7 +phy set pre-emphasis unit=0 portlist=176 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=176 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=176 lane-cnt=4 property=c0 data=0x2b.2a.2a.2b +phy set pre-emphasis unit=0 portlist=180 lane-cnt=4 property=cn2 data=0x02.02.01.02 +phy set pre-emphasis unit=0 portlist=180 lane-cnt=4 property=cn1 data=0xf6.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=180 lane-cnt=4 property=c1 data=0xf5.f6.f6.f5 +phy set pre-emphasis unit=0 portlist=180 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=180 lane-cnt=4 property=c0 data=0x28.29.2a.28 +phy set pre-emphasis unit=0 portlist=184 lane-cnt=4 property=cn2 data=0x01.01.01.01 +phy set pre-emphasis unit=0 portlist=184 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=184 lane-cnt=4 property=c1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=184 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=184 lane-cnt=4 property=c0 data=0x2a.2a.2a.2a +phy set pre-emphasis unit=0 portlist=188 lane-cnt=4 property=cn2 data=0x02.02.02.02 +phy set pre-emphasis unit=0 portlist=188 lane-cnt=4 property=cn1 data=0xf6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=188 lane-cnt=4 property=c1 data=0xf4.f4.f5.f4 +phy set pre-emphasis unit=0 portlist=188 lane-cnt=4 property=c2 data=0x00.00.00.00 +phy set pre-emphasis unit=0 portlist=188 lane-cnt=4 property=c0 data=0x25.27.28.23 +phy set pre-emphasis unit=0 portlist=192 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=192 lane-cnt=8 property=cn1 data=0xf7.f7.f7.f7.f7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=192 lane-cnt=8 property=c1 data=0xf7.f7.f7.f7.f7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=192 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=192 lane-cnt=8 property=c0 data=0x2c.2c.2b.2b.2c.2c.2c.2c +phy set pre-emphasis unit=0 portlist=200 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=200 lane-cnt=8 property=cn1 data=0xf7.f6.f7.f7.f7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=200 lane-cnt=8 property=c1 data=0xf7.f6.f7.f7.f7.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=200 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=200 lane-cnt=8 property=c0 data=0x2c.2a.2c.2c.2c.2c.2c.2a +phy set pre-emphasis unit=0 portlist=208 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=208 lane-cnt=8 property=cn1 data=0xf7.f7.f7.f6.f7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=208 lane-cnt=8 property=c1 data=0xf7.f6.f7.f6.f7.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=208 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=208 lane-cnt=8 property=c0 data=0x2c.2b.2c.2a.2b.2b.2c.2b +phy set pre-emphasis unit=0 portlist=216 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=216 lane-cnt=8 property=cn1 data=0xf7.f7.f7.f7.f7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=216 lane-cnt=8 property=c1 data=0xf6.f6.f7.f6.f6.f6.f7.f6 +phy set pre-emphasis unit=0 portlist=216 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=216 lane-cnt=8 property=c0 data=0x2b.2b.2c.2b.2b.2b.2b.2b +phy set pre-emphasis unit=0 portlist=224 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=224 lane-cnt=8 property=cn1 data=0xf7.f7.f7.f7.f7.f7.f7.f7 +phy set pre-emphasis unit=0 portlist=224 lane-cnt=8 property=c1 data=0xf6.f6.f6.f6.f7.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=224 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=224 lane-cnt=8 property=c0 data=0x2b.2b.2b.2b.2a.2a.2a.2b +phy set pre-emphasis unit=0 portlist=232 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=232 lane-cnt=8 property=cn1 data=0xf7.f7.f7.f7.f8.f7.f7.f6 +phy set pre-emphasis unit=0 portlist=232 lane-cnt=8 property=c1 data=0xf6.f6.f6.f6.f6.f6.f6.f7 +phy set pre-emphasis unit=0 portlist=232 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=232 lane-cnt=8 property=c0 data=0x2a.2a.2a.2b.28.2b.2b.2b +phy set pre-emphasis unit=0 portlist=240 lane-cnt=8 property=cn2 data=0x01.02.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=240 lane-cnt=8 property=cn1 data=0xf6.f5.f6.f7.f6.f7.f8.f7 +phy set pre-emphasis unit=0 portlist=240 lane-cnt=8 property=c1 data=0xf6.f6.f6.f6.f6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=240 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=240 lane-cnt=8 property=c0 data=0x2a.28.2a.2a.2a.2a.2b.2a +phy set pre-emphasis unit=0 portlist=248 lane-cnt=8 property=cn2 data=0x01.01.01.01.01.01.01.01 +phy set pre-emphasis unit=0 portlist=248 lane-cnt=8 property=cn1 data=0xf6.f6.f6.f7.f6.f7.f6.f7 +phy set pre-emphasis unit=0 portlist=248 lane-cnt=8 property=c1 data=0xf6.f6.f6.f6.f6.f6.f6.f6 +phy set pre-emphasis unit=0 portlist=248 lane-cnt=8 property=c2 data=0x00.00.00.00.00.00.00.00 +phy set pre-emphasis unit=0 portlist=248 lane-cnt=8 property=c0 data=0x2a.2a.2a.2a.2a.2b.2a.2a +phy set pre-emphasis unit=0 portlist=257 lane-cnt=1 property=cn2 data=0x0 +phy set pre-emphasis unit=0 portlist=257 lane-cnt=1 property=cn1 data=0x0 +phy set pre-emphasis unit=0 portlist=257 lane-cnt=1 property=c1 data=0xfa +phy set pre-emphasis unit=0 portlist=257 lane-cnt=1 property=c2 data=0x0 +phy set pre-emphasis unit=0 portlist=257 lane-cnt=1 property=c0 data=0x24 +phy set pre-emphasis unit=0 portlist=258 lane-cnt=1 property=cn2 data=0x0 +phy set pre-emphasis unit=0 portlist=258 lane-cnt=1 property=cn1 data=0x0 +phy set pre-emphasis unit=0 portlist=258 lane-cnt=1 property=c1 data=0xfa +phy set pre-emphasis unit=0 portlist=258 lane-cnt=1 property=c2 data=0x0 +phy set pre-emphasis unit=0 portlist=258 lane-cnt=1 property=c0 data=0x24 +port set property unit=0 portlist=0 speed=100g +port set property unit=0 portlist=4 speed=100g +port set property unit=0 portlist=8 speed=100g +port set property unit=0 portlist=12 speed=100g +port set property unit=0 portlist=16 speed=100g +port set property unit=0 portlist=20 speed=100g +port set property unit=0 portlist=24 speed=100g +port set property unit=0 portlist=28 speed=100g +port set property unit=0 portlist=32 speed=100g +port set property unit=0 portlist=36 speed=100g +port set property unit=0 portlist=40 speed=100g +port set property unit=0 portlist=44 speed=100g +port set property unit=0 portlist=48 speed=100g +port set property unit=0 portlist=52 speed=100g +port set property unit=0 portlist=56 speed=100g +port set property unit=0 portlist=60 speed=100g +port set property unit=0 portlist=64 speed=100g +port set property unit=0 portlist=68 speed=100g +port set property unit=0 portlist=72 speed=100g +port set property unit=0 portlist=76 speed=100g +port set property unit=0 portlist=80 speed=100g +port set property unit=0 portlist=84 speed=100g +port set property unit=0 portlist=88 speed=100g +port set property unit=0 portlist=92 speed=100g +port set property unit=0 portlist=96 speed=100g +port set property unit=0 portlist=100 speed=100g +port set property unit=0 portlist=104 speed=100g +port set property unit=0 portlist=108 speed=100g +port set property unit=0 portlist=112 speed=100g +port set property unit=0 portlist=116 speed=100g +port set property unit=0 portlist=120 speed=100g +port set property unit=0 portlist=124 speed=100g +port set property unit=0 portlist=128 speed=100g +port set property unit=0 portlist=132 speed=100g +port set property unit=0 portlist=136 speed=100g +port set property unit=0 portlist=140 speed=100g +port set property unit=0 portlist=144 speed=100g +port set property unit=0 portlist=148 speed=100g +port set property unit=0 portlist=152 speed=100g +port set property unit=0 portlist=156 speed=100g +port set property unit=0 portlist=160 speed=100g +port set property unit=0 portlist=164 speed=100g +port set property unit=0 portlist=168 speed=100g +port set property unit=0 portlist=172 speed=100g +port set property unit=0 portlist=176 speed=100g +port set property unit=0 portlist=180 speed=100g +port set property unit=0 portlist=184 speed=100g +port set property unit=0 portlist=188 speed=100g +port set property unit=0 portlist=192 speed=400g +port set property unit=0 portlist=200 speed=400g +port set property unit=0 portlist=208 speed=400g +port set property unit=0 portlist=216 speed=400g +port set property unit=0 portlist=224 speed=400g +port set property unit=0 portlist=232 speed=400g +port set property unit=0 portlist=240 speed=400g +port set property unit=0 portlist=248 speed=400g +port set property unit=0 portlist=258 speed=10g +port set property unit=0 portlist=0 medium-type=cr2 +port set property unit=0 portlist=4 medium-type=cr2 +port set property unit=0 portlist=8 medium-type=cr2 +port set property unit=0 portlist=12 medium-type=cr2 +port set property unit=0 portlist=16 medium-type=cr2 +port set property unit=0 portlist=20 medium-type=cr2 +port set property unit=0 portlist=24 medium-type=cr2 +port set property unit=0 portlist=28 medium-type=cr2 +port set property unit=0 portlist=32 medium-type=cr2 +port set property unit=0 portlist=36 medium-type=cr2 +port set property unit=0 portlist=40 medium-type=cr2 +port set property unit=0 portlist=44 medium-type=cr2 +port set property unit=0 portlist=48 medium-type=cr2 +port set property unit=0 portlist=52 medium-type=cr2 +port set property unit=0 portlist=56 medium-type=cr2 +port set property unit=0 portlist=60 medium-type=cr2 +port set property unit=0 portlist=64 medium-type=cr2 +port set property unit=0 portlist=68 medium-type=cr2 +port set property unit=0 portlist=72 medium-type=cr2 +port set property unit=0 portlist=76 medium-type=cr2 +port set property unit=0 portlist=80 medium-type=cr2 +port set property unit=0 portlist=84 medium-type=cr2 +port set property unit=0 portlist=88 medium-type=cr2 +port set property unit=0 portlist=92 medium-type=cr2 +port set property unit=0 portlist=96 medium-type=cr2 +port set property unit=0 portlist=100 medium-type=cr2 +port set property unit=0 portlist=104 medium-type=cr2 +port set property unit=0 portlist=108 medium-type=cr2 +port set property unit=0 portlist=112 medium-type=cr2 +port set property unit=0 portlist=116 medium-type=cr2 +port set property unit=0 portlist=120 medium-type=cr2 +port set property unit=0 portlist=124 medium-type=cr2 +port set property unit=0 portlist=128 medium-type=cr2 +port set property unit=0 portlist=132 medium-type=cr2 +port set property unit=0 portlist=136 medium-type=cr2 +port set property unit=0 portlist=140 medium-type=cr2 +port set property unit=0 portlist=144 medium-type=cr2 +port set property unit=0 portlist=148 medium-type=cr2 +port set property unit=0 portlist=152 medium-type=cr2 +port set property unit=0 portlist=156 medium-type=cr2 +port set property unit=0 portlist=160 medium-type=cr2 +port set property unit=0 portlist=164 medium-type=cr2 +port set property unit=0 portlist=168 medium-type=cr2 +port set property unit=0 portlist=172 medium-type=cr2 +port set property unit=0 portlist=176 medium-type=cr2 +port set property unit=0 portlist=180 medium-type=cr2 +port set property unit=0 portlist=184 medium-type=cr2 +port set property unit=0 portlist=188 medium-type=cr2 +port set property unit=0 portlist=192 medium-type=cr8 +port set property unit=0 portlist=200 medium-type=cr8 +port set property unit=0 portlist=208 medium-type=cr8 +port set property unit=0 portlist=216 medium-type=cr8 +port set property unit=0 portlist=224 medium-type=cr8 +port set property unit=0 portlist=232 medium-type=cr8 +port set property unit=0 portlist=240 medium-type=cr8 +port set property unit=0 portlist=248 medium-type=cr8 +port set property unit=0 portlist=258 medium-type=kr +port set property unit=0 portlist=0 fec=rs544 +port set property unit=0 portlist=4 fec=rs544 +port set property unit=0 portlist=8 fec=rs544 +port set property unit=0 portlist=12 fec=rs544 +port set property unit=0 portlist=16 fec=rs544 +port set property unit=0 portlist=20 fec=rs544 +port set property unit=0 portlist=24 fec=rs544 +port set property unit=0 portlist=28 fec=rs544 +port set property unit=0 portlist=32 fec=rs544 +port set property unit=0 portlist=36 fec=rs544 +port set property unit=0 portlist=40 fec=rs544 +port set property unit=0 portlist=44 fec=rs544 +port set property unit=0 portlist=48 fec=rs544 +port set property unit=0 portlist=52 fec=rs544 +port set property unit=0 portlist=56 fec=rs544 +port set property unit=0 portlist=60 fec=rs544 +port set property unit=0 portlist=64 fec=rs544 +port set property unit=0 portlist=68 fec=rs544 +port set property unit=0 portlist=72 fec=rs544 +port set property unit=0 portlist=76 fec=rs544 +port set property unit=0 portlist=80 fec=rs544 +port set property unit=0 portlist=84 fec=rs544 +port set property unit=0 portlist=88 fec=rs544 +port set property unit=0 portlist=92 fec=rs544 +port set property unit=0 portlist=96 fec=rs544 +port set property unit=0 portlist=100 fec=rs544 +port set property unit=0 portlist=104 fec=rs544 +port set property unit=0 portlist=108 fec=rs544 +port set property unit=0 portlist=112 fec=rs544 +port set property unit=0 portlist=116 fec=rs544 +port set property unit=0 portlist=120 fec=rs544 +port set property unit=0 portlist=124 fec=rs544 +port set property unit=0 portlist=128 fec=rs544 +port set property unit=0 portlist=132 fec=rs544 +port set property unit=0 portlist=136 fec=rs544 +port set property unit=0 portlist=140 fec=rs544 +port set property unit=0 portlist=144 fec=rs544 +port set property unit=0 portlist=148 fec=rs544 +port set property unit=0 portlist=152 fec=rs544 +port set property unit=0 portlist=156 fec=rs544 +port set property unit=0 portlist=160 fec=rs544 +port set property unit=0 portlist=164 fec=rs544 +port set property unit=0 portlist=168 fec=rs544 +port set property unit=0 portlist=172 fec=rs544 +port set property unit=0 portlist=176 fec=rs544 +port set property unit=0 portlist=180 fec=rs544 +port set property unit=0 portlist=184 fec=rs544 +port set property unit=0 portlist=188 fec=rs544 +port set property unit=0 portlist=192 fec=rs544 +port set property unit=0 portlist=200 fec=rs544 +port set property unit=0 portlist=208 fec=rs544 +port set property unit=0 portlist=216 fec=rs544 +port set property unit=0 portlist=224 fec=rs544 +port set property unit=0 portlist=232 fec=rs544 +port set property unit=0 portlist=240 fec=rs544 +port set property unit=0 portlist=248 fec=rs544 +port set property unit=0 portlist=0 admin=disable +port set property unit=0 portlist=4 admin=disable +port set property unit=0 portlist=8 admin=disable +port set property unit=0 portlist=12 admin=disable +port set property unit=0 portlist=16 admin=disable +port set property unit=0 portlist=20 admin=disable +port set property unit=0 portlist=24 admin=disable +port set property unit=0 portlist=28 admin=disable +port set property unit=0 portlist=32 admin=disable +port set property unit=0 portlist=36 admin=disable +port set property unit=0 portlist=40 admin=disable +port set property unit=0 portlist=44 admin=disable +port set property unit=0 portlist=48 admin=disable +port set property unit=0 portlist=52 admin=disable +port set property unit=0 portlist=56 admin=disable +port set property unit=0 portlist=60 admin=disable +port set property unit=0 portlist=64 admin=disable +port set property unit=0 portlist=68 admin=disable +port set property unit=0 portlist=72 admin=disable +port set property unit=0 portlist=76 admin=disable +port set property unit=0 portlist=80 admin=disable +port set property unit=0 portlist=84 admin=disable +port set property unit=0 portlist=88 admin=disable +port set property unit=0 portlist=92 admin=disable +port set property unit=0 portlist=96 admin=disable +port set property unit=0 portlist=100 admin=disable +port set property unit=0 portlist=104 admin=disable +port set property unit=0 portlist=108 admin=disable +port set property unit=0 portlist=112 admin=disable +port set property unit=0 portlist=116 admin=disable +port set property unit=0 portlist=120 admin=disable +port set property unit=0 portlist=124 admin=disable +port set property unit=0 portlist=128 admin=disable +port set property unit=0 portlist=132 admin=disable +port set property unit=0 portlist=136 admin=disable +port set property unit=0 portlist=140 admin=disable +port set property unit=0 portlist=144 admin=disable +port set property unit=0 portlist=148 admin=disable +port set property unit=0 portlist=152 admin=disable +port set property unit=0 portlist=156 admin=disable +port set property unit=0 portlist=160 admin=disable +port set property unit=0 portlist=164 admin=disable +port set property unit=0 portlist=168 admin=disable +port set property unit=0 portlist=172 admin=disable +port set property unit=0 portlist=176 admin=disable +port set property unit=0 portlist=180 admin=disable +port set property unit=0 portlist=184 admin=disable +port set property unit=0 portlist=188 admin=disable +port set property unit=0 portlist=192 admin=disable +port set property unit=0 portlist=200 admin=disable +port set property unit=0 portlist=208 admin=disable +port set property unit=0 portlist=216 admin=disable +port set property unit=0 portlist=224 admin=disable +port set property unit=0 portlist=232 admin=disable +port set property unit=0 portlist=240 admin=disable +port set property unit=0 portlist=248 admin=disable + +port set adver unit=0 portlist=258 speed-10g-kr +port set property unit=0 portlist=258 an-lt=enable +port set property unit=0 portlist=258 admin=disable diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/lightning-fn8656_bnf.led b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/lightning-fn8656_bnf.led new file mode 100644 index 000000000000..2f0476d8870e Binary files /dev/null and b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/lightning-fn8656_bnf.led differ diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/pg_profile_lookup.ini b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/pg_profile_lookup.ini new file mode 100644 index 000000000000..d98b0eca6d19 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/pg_profile_lookup.ini @@ -0,0 +1,17 @@ +# PG lossless profiles. +# speed cable size xon xoff threshold + 10000 5m 3584 32256 59136 36736 + 25000 5m 3584 41216 68096 45696 + 40000 5m 3584 47488 74368 51968 + 50000 5m 3584 52864 79744 57344 + 100000 5m 3584 78400 132160 82880 + 10000 40m 3584 32256 59136 36736 + 25000 40m 3584 41216 68096 45696 + 40000 40m 3584 47488 74368 51968 + 50000 40m 3584 52864 79744 57344 + 100000 40m 3584 78400 132160 82880 + 10000 300m 3584 32256 65856 36736 + 25000 300m 3584 41216 84672 45696 + 40000 300m 3584 47488 101024 51968 + 50000 300m 3584 52864 113120 57344 + 100000 300m 3584 78400 198688 82880 \ No newline at end of file diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/port_config.ini b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/port_config.ini new file mode 100755 index 000000000000..67266566606b --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/port_config.ini @@ -0,0 +1,57 @@ +# name lanes alias speed index mtu fec +Ethernet0 100,101 Ethernet0 100000 0 9100 rs +Ethernet4 108,109 Ethernet4 100000 1 9100 rs +Ethernet8 96,97 Ethernet8 100000 2 9100 rs +Ethernet12 104,105 Ethernet12 100000 3 9100 rs +Ethernet16 116,117 Ethernet16 100000 4 9100 rs +Ethernet20 124,125 Ethernet20 100000 5 9100 rs +Ethernet24 112,113 Ethernet24 100000 6 9100 rs +Ethernet28 120,121 Ethernet28 100000 7 9100 rs +Ethernet32 128,129 Ethernet32 100000 8 9100 rs +Ethernet36 136,137 Ethernet36 100000 9 9100 rs +Ethernet40 132,133 Ethernet40 100000 10 9100 rs +Ethernet44 140,141 Ethernet44 100000 11 9100 rs +Ethernet48 144,145 Ethernet48 100000 12 9100 rs +Ethernet52 152,153 Ethernet52 100000 13 9100 rs +Ethernet56 148,149 Ethernet56 100000 14 9100 rs +Ethernet60 156,157 Ethernet60 100000 15 9100 rs +Ethernet64 36,37 Ethernet64 100000 16 9100 rs +Ethernet68 44,45 Ethernet68 100000 17 9100 rs +Ethernet72 32,33 Ethernet72 100000 18 9100 rs +Ethernet76 40,41 Ethernet76 100000 19 9100 rs +Ethernet80 52,53 Ethernet80 100000 20 9100 rs +Ethernet84 60,61 Ethernet84 100000 21 9100 rs +Ethernet88 48,49 Ethernet88 100000 22 9100 rs +Ethernet92 56,57 Ethernet92 100000 23 9100 rs +Ethernet96 64,65 Ethernet96 100000 24 9100 rs +Ethernet100 72,73 Ethernet100 100000 25 9100 rs +Ethernet104 68,69 Ethernet104 100000 26 9100 rs +Ethernet108 76,77 Ethernet108 100000 27 9100 rs +Ethernet112 80,81 Ethernet112 100000 28 9100 rs +Ethernet116 88,89 Ethernet116 100000 29 9100 rs +Ethernet120 84,85 Ethernet120 100000 30 9100 rs +Ethernet124 92,93 Ethernet124 100000 31 9100 rs +Ethernet128 228,229 Ethernet128 100000 32 9100 rs +Ethernet132 236,237 Ethernet132 100000 33 9100 rs +Ethernet136 224,225 Ethernet136 100000 34 9100 rs +Ethernet140 232,233 Ethernet140 100000 35 9100 rs +Ethernet144 244,245 Ethernet144 100000 36 9100 rs +Ethernet148 252,253 Ethernet148 100000 37 9100 rs +Ethernet152 240,241 Ethernet152 100000 38 9100 rs +Ethernet156 248,249 Ethernet156 100000 39 9100 rs +Ethernet160 0,1 Ethernet160 100000 40 9100 rs +Ethernet164 8,9 Ethernet168 100000 41 9100 rs +Ethernet168 4,5 Ethernet164 100000 42 9100 rs +Ethernet172 12,13 Ethernet172 100000 43 9100 rs +Ethernet176 16,17 Ethernet176 100000 44 9100 rs +Ethernet180 24,25 Ethernet180 100000 45 9100 rs +Ethernet184 20,21 Ethernet184 100000 46 9100 rs +Ethernet188 28,29 Ethernet188 100000 47 9100 rs +Ethernet192 160,161,162,163,164,165,166,167 Ethernet192 400000 48 9100 rs +Ethernet200 168,169,170,171,172,173,174,175 Ethernet200 400000 49 9100 rs +Ethernet208 176,177,178,179,180,181,182,183 Ethernet208 400000 50 9100 rs +Ethernet216 184,185,186,187,188,189,190,191 Ethernet216 400000 51 9100 rs +Ethernet224 192,193,194,195,196,197,198,199 Ethernet224 400000 52 9100 rs +Ethernet232 200,201,202,203,204,205,206,207 Ethernet232 400000 53 9100 rs +Ethernet240 208,209,210,211,212,213,214,215 Ethernet240 400000 54 9100 rs +Ethernet248 216,217,218,219,220,221,222,223 Ethernet248 400000 55 9100 rs diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/qos.json.j2 b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/qos.json.j2 new file mode 100644 index 000000000000..08dd0322d639 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/qos.json.j2 @@ -0,0 +1,198 @@ +{ + "TC_TO_PRIORITY_GROUP_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_QUEUE_MAP": { + "AZURE": { + "0": "0", + "1": "1", + "2": "2", + "3": "3", + "4": "4", + "5": "5", + "6": "6", + "7": "7" + } + }, + "DSCP_TO_TC_MAP": { + "AZURE": { + "0" : "1", + "1" : "1", + "2" : "1", + "3" : "3", + "4" : "4", + "5" : "2", + "6" : "1", + "7" : "1", + "8" : "0", + "9" : "1", + "10": "1", + "11": "1", + "12": "1", + "13": "1", + "14": "1", + "15": "1", + "16": "1", + "17": "1", + "18": "1", + "19": "1", + "20": "1", + "21": "1", + "22": "1", + "23": "1", + "24": "1", + "25": "1", + "26": "1", + "27": "1", + "28": "1", + "29": "1", + "30": "1", + "31": "1", + "32": "1", + "33": "1", + "34": "1", + "35": "1", + "36": "1", + "37": "1", + "38": "1", + "39": "1", + "40": "1", + "41": "1", + "42": "1", + "43": "1", + "44": "1", + "45": "1", + "46": "5", + "47": "1", + "48": "6", + "49": "1", + "50": "1", + "51": "1", + "52": "1", + "53": "1", + "54": "1", + "55": "1", + "56": "1", + "57": "1", + "58": "1", + "59": "1", + "60": "1", + "61": "1", + "62": "1", + "63": "1" + } + }, + "SCHEDULER": { + "scheduler.0" : { + "type":"DWRR", + "weight": "25" + }, + "scheduler.1" : { + "type":"DWRR", + "weight": "30" + }, + "scheduler.2" : { + "type":"DWRR", + "weight": "20" + } + }, + "PORT_QOS_MAP": { + {% for port in PORT %} + "{{ port }}": { + "dscp_to_tc_map" : "[DSCP_TO_TC_MAP|AZURE]", + "tc_to_queue_map" : "[TC_TO_QUEUE_MAP|AZURE]", + "tc_to_pg_map" : "[TC_TO_PRIORITY_GROUP_MAP|AZURE]", + "pfc_to_queue_map": "[MAP_PFC_PRIORITY_TO_QUEUE|AZURE]", + "pfc_enable" : "3,4" + }{% if not loop.last %},{% endif %} + + {% endfor %} + }, + "WRED_PROFILE": { + "AZURE_LOSSY" : { + "wred_green_enable":"true", + "wred_yellow_enable":"true", + "wred_red_enable":"true", + "ecn":"ecn_all", + "red_max_threshold":"516096", + "red_min_threshold":"516096", + "yellow_max_threshold":"516096", + "yellow_min_threshold":"516096", + "green_max_threshold": "184128", + "green_min_threshold": "184128" + }, + "AZURE_LOSSLESS" : { + "wred_green_enable":"true", + "wred_yellow_enable":"true", + "wred_red_enable":"true", + "ecn":"ecn_all", + "red_max_threshold":"516096", + "red_min_threshold":"516096", + "yellow_max_threshold":"516096", + "yellow_min_threshold":"516096", + "green_max_threshold": "184128", + "green_min_threshold": "184128" + } + }, + "QUEUE": { +{% for port in PORT %} + "{{ port }}|3": { + "scheduler" : "[SCHEDULER|scheduler.1]", + "wred_profile": "[WRED_PROFILE|AZURE_LOSSLESS]" + }, +{% endfor %} +{% for port in PORT %} + "{{ port }}|4": { + "scheduler" : "[SCHEDULER|scheduler.1]", + "wred_profile": "[WRED_PROFILE|AZURE_LOSSLESS]" + }, +{% endfor %} +{% for port in PORT %} + "{{ port }}|0": { + "scheduler": "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT %} + "{{ port }}|1": { + "scheduler": "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT %} + "{{ port }}|2": { + "scheduler": "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT %} + "{{ port }}|5": { + "scheduler": "[SCHEDULER|scheduler.0]" + }, +{% endfor %} +{% for port in PORT %} + "{{ port }}|6": { + "scheduler": "[SCHEDULER|scheduler.0]" + }{% if not loop.last %},{% endif %} + +{% endfor %} + } +} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/sai.profile b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/sai.profile new file mode 100755 index 000000000000..d86f9ede0609 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/fn8656-bnf/sai.profile @@ -0,0 +1,3 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/lightning-fn8656_bnf.cfg +SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/lightning-fn8656_bnf.dsh +SAI_INIT_LED_CONFIG_FILE=/usr/share/sonic/hwsku/lightning-fn8656_bnf.led diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/installer.conf b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/installer.conf new file mode 100644 index 000000000000..9db3677850cb --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/installer.conf @@ -0,0 +1 @@ +ONIE_PLATFORM_EXTRA_CMDLINE_LINUX= diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/lightning-fn8656_bnf.cfg b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/lightning-fn8656_bnf.cfg new file mode 100755 index 000000000000..24c1094b0e50 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/lightning-fn8656_bnf.cfg @@ -0,0 +1,24 @@ +#This configuration file is for customer init value feature. Please refer to clx_cfg.h/clx_cfg.c for detail. +#1. The lines beginning with # are comment lines. The lines beginning with number are the setting lines. +#2. There are five parameters which can be set. +# 1) the first is unit. +# 2) the second is CLX_CFG_TYPE_XXX. Refer to CLX_CFG_TYPE_T. +# 3) the 3-5 are {param0, param1, value} pairs. Refer to CLX_CFG_VALUE_T. Support HEX format. +# 4) the (unit, CLX_CFG_TYPE_XXX, param0, param1) group is the key to get the correspingding value. +# There should be no same (unit, CLX_CFG_TYPE_XXX, param0, param1) group. +#3. User must follow correct format to apply the setting. Please refer to below commentted example(#0 CLX_CFG_TYPE_L2_ADDR_MODE 0 0 1); +#4. Usage under the linux shell: +# 1) ./image-path/image-name -c cfg-path/CLX_Ari_EVB_24.cfg : mamually specify directory path if they are not in current work dirctory. +# 2) ./image-name -c CLX_Ari_EVB_24.cfg : the image and the CLX_Ari_EVB_24.cfg are in the current work directory. + +#unit CLX_CFG_TYPE_XXX param0 param1 value +#---- ---------------- ------ ------ ----- +0 CLX_CFG_TYPE_USE_UNIT_PORT 0 0 1 +#0 CLX_CFG_TYPE_LED_CFG 0 0 3 +0 CLX_CFG_TYPE_CPI_PORT_MODE 257 0 1 +0 CLX_CFG_TYPE_CPI_PORT_MODE 258 0 1 +0 CLX_CFG_TYPE_USER_BUF_CTRL 0 0 1 +0 CLX_CFG_TYPE_HASH_L2_FDB_REGION_ENTRY_NUM 0 0 49152 +0 CLX_CFG_TYPE_HASH_L3_WITH_IPV6_PREFIX_64_REGION_ENTRY_NUM 0 0 32768 +0 CLX_CFG_TYPE_L2_POLLING_INTERVAL 0 0 400 +0 CLX_CFG_TYPE_PORT_BREAKOUT_LANE_NUM_MAX 0 0 8 diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/media_settings.json b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/media_settings.json new file mode 100644 index 000000000000..39690c0edd14 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/media_settings.json @@ -0,0 +1,4437 @@ +{ + "PORT_MEDIA_SETTINGS": { + "0": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x29", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfd", + "lane1":"0xfa", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2c", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "1": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf5", + "lane2":"0xf5", + "lane3":"0xf5" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x28", + "lane2":"0x27", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x35", + "lane1":"0x34", + "lane2":"0x35", + "lane3":"0x34" + } + } + }, + "2": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfd", + "lane1":"0xfa", + "lane2":"0xfa", + "lane3":"0xfa" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c" + } + } + }, + "3": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf5", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x28", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x34", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "4": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf8", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfe", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfa", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c" + } + } + }, + "5": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x02", + "lane2":"0x01", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf9", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x34", + "lane1":"0x34", + "lane2":"0x35", + "lane3":"0x34" + } + } + }, + "6": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfe", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfa", + "lane2":"0xfa", + "lane3":"0xfa" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c" + } + } + }, + "7": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x34", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "8": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfa" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2c", + "lane2":"0x2a", + "lane3":"0x2c" + } + } + }, + "9": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf5", + "lane1":"0xf6", + "lane2":"0xf5", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x28", + "lane1":"0x2a", + "lane2":"0x28", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x35", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "10": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfd", + "lane1":"0xfd", + "lane2":"0xfa", + "lane3":"0xfa" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x31", + "lane1":"0x2a", + "lane2":"0x2c", + "lane3":"0x2c" + } + } + }, + "11": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x01", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x29", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "12": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfa", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x30", + "lane1":"0x2d", + "lane2":"0x2a", + "lane3":"0x2c" + } + } + }, + "13": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf8", + "lane2":"0xf7", + "lane3":"0xf8" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "14": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x2b", + "lane2":"0x2c", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfa", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2c" + } + } + }, + "15": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf8" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf5", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x28", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "16": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf8", + "lane1":"0xf8", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x28", + "lane1":"0x28", + "lane2":"0x28", + "lane3":"0x28" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x34", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "17": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x29", + "lane2":"0x29", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "18": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf8", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x28", + "lane1":"0x28", + "lane2":"0x28", + "lane3":"0x28" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x33", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "19": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x29", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x35", + "lane2":"0x36", + "lane3":"0x32" + } + } + }, + "20": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "21": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "22": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "23": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2b", + "lane2":"0x33", + "lane3":"0x2b" + } + } + }, + "24": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2d", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "25": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b" + } + } + }, + "26": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x34", + "lane1":"0x2d", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "27": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x28", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2f", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b" + } + } + }, + "28": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x29", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2d", + "lane1":"0x2d", + "lane2":"0x32", + "lane3":"0x2d" + } + } + }, + "29": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf8", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf8" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x27", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2d", + "lane3":"0x2b" + } + } + }, + "30": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf8", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2d", + "lane1":"0x23", + "lane2":"0x2d", + "lane3":"0x2d" + } + } + }, + "31": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b" + } + } + }, + "32": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf8", + "lane1":"0xf8", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2b", + "lane3":"0x2c" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2d", + "lane2":"0x2a", + "lane3":"0x2b" + } + } + }, + "33": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf8" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2b" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "34": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2b", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfd", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfd" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2d", + "lane2":"0x2c", + "lane3":"0x2d" + } + } + }, + "35": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "36": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf8", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2b", + "lane2":"0x2c", + "lane3":"0x2c" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2c", + "lane2":"0x2a", + "lane3":"0x2a" + } + } + }, + "37": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf8" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2c", + "lane3":"0x29" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x34" + } + } + }, + "38": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2c" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfa", + "lane3":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2c", + "lane2":"0x30", + "lane3":"0x2c" + } + } + }, + "39": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "40": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfa", + "lane1":"0xfd", + "lane2":"0xfc", + "lane3":"0xfd" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2a", + "lane2":"0x2c", + "lane3":"0x2a" + } + } + }, + "41": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf5", + "lane1":"0xf6", + "lane2":"0xf5", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x28", + "lane1":"0x2a", + "lane2":"0x28", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x34", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "42": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfd", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc" + }, + "post1":{ + "lane0":"0xfd", + "lane1":"0xfa", + "lane2":"0xfa", + "lane3":"0xfa" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c" + } + } + }, + "43": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf7", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf5", + "lane1":"0xf5", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x29", + "lane1":"0x29", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x35", + "lane1":"0x36", + "lane2":"0x35", + "lane3":"0x34" + } + } + }, + "44": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2b" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfd", + "lane2":"0xfd", + "lane3":"0xfd" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "45": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x01", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf5", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf5" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x28", + "lane1":"0x2a", + "lane2":"0x29", + "lane3":"0x28" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfd", + "lane2":"0xfb", + "lane3":"0xfd" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfd", + "lane2":"0xfb", + "lane3":"0xfd" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x34", + "lane3":"0x32" + } + } + }, + "46": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfa", + "lane2":"0xfd", + "lane3":"0xfa" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfa", + "lane2":"0xfd", + "lane3":"0xfa" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32" + } + } + }, + "47": { + "Default": { + "pre2":{ + "lane0":"0x02", + "lane1":"0x02", + "lane2":"0x02", + "lane3":"0x02" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6" + }, + "post1":{ + "lane0":"0xf4", + "lane1":"0xf5", + "lane2":"0xf4", + "lane3":"0xf4" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x23", + "lane1":"0x28", + "lane2":"0x27", + "lane3":"0x25" + } + }, + "DSFP-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfb", + "lane2":"0xfc", + "lane3":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00" + }, + "main":{ + "lane0":"0x35", + "lane1":"0x33", + "lane2":"0x32", + "lane3":"0x33" + } + } + }, + "48": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf7", + "lane7":"0xf7" + }, + "post1":{ + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf7", + "lane7":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2c", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c", + "lane4":"0x2b", + "lane5":"0x2b", + "lane6":"0x2c", + "lane7":"0x2c" + } + + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2d", + "lane1":"0x2d", + "lane2":"0x2d", + "lane3":"0x2d", + "lane4":"0x2d", + "lane5":"0x2d", + "lane6":"0x2d", + "lane7":"0x2d" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2d", + "lane1":"0x2d", + "lane2":"0x2d", + "lane3":"0x2d", + "lane4":"0x2d", + "lane5":"0x2d", + "lane6":"0x2d", + "lane7":"0x2d" + } + } + }, + "49": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf6", + "lane7":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf6", + "lane7":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2c", + "lane2":"0x2c", + "lane3":"0x2c", + "lane4":"0x2c", + "lane5":"0x2c", + "lane6":"0x2a", + "lane7":"0x2c" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b", + "lane4":"0x2b", + "lane5":"0x2b", + "lane6":"0x2b", + "lane7":"0x2b" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b", + "lane4":"0x2b", + "lane5":"0x2b", + "lane6":"0x2b", + "lane7":"0x2b" + } + } + }, + "50": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf6", + "lane5":"0xf7", + "lane6":"0xf7", + "lane7":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf7", + "lane4":"0xf6", + "lane5":"0xf7", + "lane6":"0xf6", + "lane7":"0xf7" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2c", + "lane2":"0x2b", + "lane3":"0x2b", + "lane4":"0x2a", + "lane5":"0x2c", + "lane6":"0x2b", + "lane7":"0x2c" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2d", + "lane2":"0x32", + "lane3":"0x2d", + "lane4":"0x32", + "lane5":"0x2d", + "lane6":"0x32", + "lane7":"0x2d" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x2d", + "lane2":"0x32", + "lane3":"0x2d", + "lane4":"0x32", + "lane5":"0x2d", + "lane6":"0x32", + "lane7":"0x2d" + } + } + }, + "51": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf7", + "lane7":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf6", + "lane3":"0xf6", + "lane4":"0xf6", + "lane5":"0xf7", + "lane6":"0xf6", + "lane7":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b", + "lane4":"0x2b", + "lane5":"0x2c", + "lane6":"0x2b", + "lane7":"0x2b" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b", + "lane4":"0x2b", + "lane5":"0x2b", + "lane6":"0x32", + "lane7":"0x2b" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfc", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x2b", + "lane4":"0x2b", + "lane5":"0x2b", + "lane6":"0x32", + "lane7":"0x2b" + } + } + }, + "52": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf7", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf7", + "lane7":"0xf7" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6", + "lane4":"0xf6", + "lane5":"0xf6", + "lane6":"0xf6", + "lane7":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2a", + "lane2":"0x2a", + "lane3":"0x2a", + "lane4":"0x2b", + "lane5":"0x2b", + "lane6":"0x2b", + "lane7":"0x2b" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfb", + "lane6":"0xfc", + "lane7":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfb", + "lane6":"0xfc", + "lane7":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x32", + "lane6":"0x32", + "lane7":"0x32" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfb", + "lane6":"0xfc", + "lane7":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfc", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfb", + "lane6":"0xfc", + "lane7":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x32", + "lane6":"0x32", + "lane7":"0x32" + } + } + }, + "53": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf6", + "lane1":"0xf7", + "lane2":"0xf7", + "lane3":"0xf8", + "lane4":"0xf7", + "lane5":"0xf7", + "lane6":"0xf7", + "lane7":"0xf7" + }, + "post1":{ + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6", + "lane4":"0xf6", + "lane5":"0xf6", + "lane6":"0xf6", + "lane7":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2b", + "lane1":"0x2b", + "lane2":"0x2b", + "lane3":"0x28", + "lane4":"0x2b", + "lane5":"0x2a", + "lane6":"0x2a", + "lane7":"0x2a" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x2b", + "lane6":"0x32", + "lane7":"0x2b" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfc", + "lane6":"0xfb", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x2b", + "lane6":"0x32", + "lane7":"0x2b" + } + } + }, + "54": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x02", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf8", + "lane2":"0xf7", + "lane3":"0xf6", + "lane4":"0xf7", + "lane5":"0xf6", + "lane6":"0xf5", + "lane7":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6", + "lane4":"0xf6", + "lane5":"0xf6", + "lane6":"0xf6", + "lane7":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2b", + "lane2":"0x2a", + "lane3":"0x2a", + "lane4":"0x2a", + "lane5":"0x2a", + "lane6":"0x28", + "lane7":"0x2a" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x32", + "lane6":"0x32", + "lane7":"0x32" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfc", + "lane2":"0xfb", + "lane3":"0xfc", + "lane4":"0xfc", + "lane5":"0xfc", + "lane6":"0xfc", + "lane7":"0xfc" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x32", + "lane6":"0x32", + "lane7":"0x32" + } + } + }, + "55": { + "Default": { + "pre2":{ + "lane0":"0x01", + "lane1":"0x01", + "lane2":"0x01", + "lane3":"0x01", + "lane4":"0x01", + "lane5":"0x01", + "lane6":"0x01", + "lane7":"0x01" + }, + "pre1": { + "lane0":"0xf7", + "lane1":"0xf6", + "lane2":"0xf7", + "lane3":"0xf6", + "lane4":"0xf7", + "lane5":"0xf6", + "lane6":"0xf6", + "lane7":"0xf6" + }, + "post1":{ + "lane0":"0xf6", + "lane1":"0xf6", + "lane2":"0xf6", + "lane3":"0xf6", + "lane4":"0xf6", + "lane5":"0xf6", + "lane6":"0xf6", + "lane7":"0xf6" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x2a", + "lane1":"0x2a", + "lane2":"0x2b", + "lane3":"0x2a", + "lane4":"0x2a", + "lane5":"0x2a", + "lane6":"0x2a", + "lane7":"0x2a" + } + }, + "QSFP-DD-media_interface: AOC": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfb", + "lane6":"0xfb", + "lane7":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfb", + "lane6":"0xfb", + "lane7":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x32", + "lane6":"0x32", + "lane7":"0x32" + } + }, + "QSFP28-{'media_interface':'AOC'}": { + "pre2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "pre1": { + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfb", + "lane6":"0xfb", + "lane7":"0xfb" + }, + "post1":{ + "lane0":"0xfb", + "lane1":"0xfb", + "lane2":"0xfb", + "lane3":"0xfb", + "lane4":"0xfb", + "lane5":"0xfb", + "lane6":"0xfb", + "lane7":"0xfb" + }, + "post2":{ + "lane0":"0x00", + "lane1":"0x00", + "lane2":"0x00", + "lane3":"0x00", + "lane4":"0x00", + "lane5":"0x00", + "lane6":"0x00", + "lane7":"0x00" + }, + "main":{ + "lane0":"0x32", + "lane1":"0x32", + "lane2":"0x32", + "lane3":"0x32", + "lane4":"0x32", + "lane5":"0x32", + "lane6":"0x32", + "lane7":"0x32" + } + } + } + } +} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/pcie.yaml b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/pcie.yaml new file mode 100644 index 000000000000..6fecdda382d0 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/pcie.yaml @@ -0,0 +1,5 @@ +- bus: '01' + dev: '00' + fn: '0' + id: '8579' + name: 'Ethernet controller: Device 1d9f:8579 (rev 01)' diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/platform.json b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/platform.json new file mode 100644 index 000000000000..05ffde70d759 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/platform.json @@ -0,0 +1,344 @@ +{ + "chassis": { + "name": "fn8656-bnf", + "watchdog": { + "name":"watchdog0" + }, + "components": [ + { + "name": "CPLD-A", + "description":"Main board side CPLD A", + "version":"21.0", + "firmware_version_path":"/sys/bus/i2c/devices/6-0074/cpld_sw_version", + "hw_version_path":"/sys/bus/i2c/devices/6-0074/cpld_hw_version" + }, + { + "name": "CPLD-B", + "description":"Main board side CPLD B", + "version":"21.0", + "firmware_version_path":"/sys/bus/i2c/devices/7-0075/cpld_sw_version", + "hw_version_path":"/sys/bus/i2c/devices/7-0075/cpld_hw_version" + }, + { + "name": "CPLD-C", + "description":"Main board side CPLD C", + "version":"21.0", + "firmware_version_path":"/sys/bus/i2c/devices/8-0076/cpld_sw_version", + "hw_version_path":"/sys/bus/i2c/devices/8-0076/cpld_hw_version" + }, + { + "name": "CPLD-D", + "description":"NPU board side CPLD", + "version":"20.0", + "firmware_version_path":"/sys/bus/i2c/devices/1-0018/cpld_sw_version", + "hw_version_path":"/sys/bus/i2c/devices/1-0018/cpld_hw_version" + }, + { + "name": "MCU-MB", + "description":"Main board side MCU", + "version":"0.5", + "firmware_version_path":"/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/mb_fw_version", + "hw_version_path":"/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/mb_hw_version" + }, + { + "name": "MCU-FB", + "description":"Fan board side MCU", + "version":"0.10", + "firmware_version_path":"/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/fb_fw_version", + "hw_version_path":"/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/fb_hw_version" + }, + { + "name": "FPGA", + "description":"Main board side FPGA", + "version":"18.0", + "firmware_version_path":"/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/fpga_sw_version", + "hw_version_path":"/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/fpga_hw_version" + }, + { + "name": "BIOS", + "description":"Performs initialization of hardware components during booting", + "version":"0.10", + "firmware_version_path":"dmidecode -s bios-version", + "hw_version_path":"dmidecode -s bios-version" + } + ], + "fans": [], + "fan_drawers": [ + { + "name": "Draw1", + "fans": [ + { + "name": "FAN1" + }, + { + "name": "FAN2" + }, + { + "name": "FAN3" + }, + { + "name": "FAN4" + }, + { + "name": "FAN5" + }, + { + "name": "FAN6" + } + ] + } + ], + "psus": [ + { + "name": "PSU1", + "fans": [ + { + "name": "PSU1-FAN1" + } + ], + "thermals": [ + { + "name": "PSU1 Ambient", + "position": "PSU" + }, + { + "name": "PSU1 SR Hotspot", + "position": "PSU" + }, + { + "name": "PSU1 PFC Hotspot", + "position": "PSU" + } + ] + }, + { + "name": "PSU2", + "fans": [ + { + "name": "PSU2-FAN1" + } + ], + "thermals" :[ + { + "name": "PSU2 Ambient", + "position": "PSU" + }, + { + "name": "PSU2 SR Hotspot", + "position": "PSU" + }, + { + "name": "PSU2 PFC Hotspot", + "position": "PSU" + } + ] + } + ], + "thermals": [ + { + "name": "LM75BD / Ambient MAC side", + "position": "LM75BD" + }, + { + "name": "LM75BD / Ambient MAC", + "position": "LM75BD" + }, + { + "name": "LM75BD / Ambient FAN", + "position": "LM75BD" + }, + { + "name": "LM75BD / Ambient NPU", + "position": "LM75BD" + }, + { + "name": "CPU / Core 0", + "position": "CPU" + }, + { + "name": "CPU / Core 1", + "position": "CPU" + }, + { + "name": "CPU / Core 2", + "position": "CPU" + }, + { + "name": "CPU / Core 3", + "position": "CPU" + } + ], + "sfps": [ + { + "name": "Ethernet0" + }, + { + "name": "Ethernet4" + }, + { + "name": "Ethernet8" + }, + { + "name": "Ethernet12" + }, + { + "name": "Ethernet16" + }, + { + "name": "Ethernet20" + }, + { + "name": "Ethernet24" + }, + { + "name": "Ethernet28" + }, + { + "name": "Ethernet32" + }, + { + "name": "Ethernet36" + }, + { + "name": "Ethernet40" + }, + { + "name": "Ethernet44" + }, + { + "name": "Ethernet48" + }, + { + "name": "Ethernet52" + }, + { + "name": "Ethernet56" + }, + { + "name": "Ethernet60" + }, + { + "name": "Ethernet64" + }, + { + "name": "Ethernet68" + }, + { + "name": "Ethernet72" + }, + { + "name": "Ethernet76" + }, + { + "name": "Ethernet80" + }, + { + "name": "Ethernet84" + }, + { + "name": "Ethernet88" + }, + { + "name": "Ethernet92" + }, + { + "name": "Ethernet96" + }, + { + "name": "Etherne100" + }, + { + "name": "Etherne104" + }, + { + "name": "Etherne108" + }, + { + "name": "Ethernet112" + }, + { + "name": "Ethernet116" + }, + { + "name": "Ethernet120" + }, + { + "name": "Ethernet124" + }, + { + "name": "Ethernet128" + }, + { + "name": "Ethernet132" + }, + { + "name": "Ethernet136" + }, + { + "name": "Ethernet140" + }, + { + "name": "Ethernet144" + }, + { + "name": "Ethernet148" + }, + { + "name": "Ethernet152" + }, + { + "name": "Ethernet156" + }, + { + "name": "Ethernet160" + }, + { + "name": "Ethernet164" + }, + { + "name": "Ethernet168" + }, + { + "name": "Ethernet172" + }, + { + "name": "Ethernet176" + }, + { + "name": "Ethernet180" + }, + { + "name": "Ethernet184" + }, + { + "name": "Ethernet188" + }, + { + "name": "Ethernet192" + }, + { + "name": "Ethernet200" + }, + { + "name": "Ethernet208" + }, + { + "name": "Ethernet216" + }, + { + "name": "Ethernet224" + }, + { + "name": "Ethernet232" + }, + { + "name": "Ethernet240" + }, + { + "name": "Ethernet248" + } + ] + }, + "interfaces" :{} + +} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/platform_components.json b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/platform_components.json new file mode 100644 index 000000000000..8be1fbdb5f5f --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/platform_components.json @@ -0,0 +1,14 @@ +{ + "chassis": { + "FN8656-BNF": { + "component": { + "CPLD-A": {}, + "CPLD-B": {}, + "CPLD-C": {}, + "CPLD-D": {}, + "MCU": {}, + "BIOS": {} + } + } + } +} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/eeprom.py b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/eeprom.py new file mode 100755 index 000000000000..6a9dd2400f24 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/eeprom.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python + +try: + #import binascii + #import time + #import optparse + #import warnings + #import os + #import sys + #from sonic_eeprom import eeprom_base + from sonic_eeprom import eeprom_tlvinfo + #import subprocess +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +class board(eeprom_tlvinfo.TlvInfoDecoder): + _TLV_INFO_MAX_LEN = 256 + def __init__(self, name, path, cpld_root, ro): + self.eeprom_path = "/sys/bus/i2c/devices/9-0054/eeprom" + super(board, self).__init__(self.eeprom_path, 0, '', True) diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/psuutil.py b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/psuutil.py new file mode 100755 index 000000000000..400900337d98 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/psuutil.py @@ -0,0 +1,92 @@ +# +# psuutil.py +# Platform-specific PSU status interface for SONiC +# + + +import os.path + +try: + from sonic_psu.psu_base import PsuBase +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class PsuUtil(PsuBase): + """Platform-specific PSUutil class""" + + SYSFS_PSU_DIR = "/sys/bus/i2c/devices/6-0074" + + def __init__(self): + PsuBase.__init__(self) + + + # Get sysfs attribute + def get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip('\r\n') + + fd.close() + return retval + + def get_num_psus(self): + """ + Retrieves the number of PSUs available on the device + :return: An integer, the number of PSUs available on the device + """ + MAX_PSUS = 2 + return MAX_PSUS + + def get_psu_status(self, index): + """ + Retrieves the oprational status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is operating properly, False if PSU is\ + faulty + """ + status = 0 + attr_file = 'psu_'+str(index)+'_status' + attr_path = self.SYSFS_PSU_DIR +'/' + attr_file + + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check for PSU status + if (attr_value == 1): + status = 1 + + return status + + def get_psu_presence(self, index): + """ + Retrieves the presence status of power supply unit (PSU) defined + by index + :param index: An integer, index of the PSU of which to query status + :return: Boolean, True if PSU is plugged, False if not + """ + status = 0 + attr_file = 'psu_'+str(index)+'_present' + attr_path = self.SYSFS_PSU_DIR +'/' + attr_file + + attr_value = self.get_attr_value(attr_path) + + if (attr_value != 'ERR'): + attr_value = int(attr_value, 16) + # Check for PSU presence + if (attr_value == 0): + status = 1 + + return status + diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/sfputil.py b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/sfputil.py new file mode 100755 index 000000000000..50a716997e97 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/plugins/sfputil.py @@ -0,0 +1,483 @@ +#!/usr/bin/env python + +try: + import os + import sys + import re + import time + from sonic_sfp.sfputilbase import SfpUtilBase + from sonic_sfp.sff8472 import sff8472Dom +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 112 +SFP_MODULE_THRESHOLD_WIDTH = 5 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 6 + +class SfpUtil(SfpUtilBase): + """Platform specific sfputil class""" + + PORT_START = 0 + PORT_END = 55 + PORTS_IN_BLOCK = 55 + QSFP_PORT_START = 0 + QSFP_PORT_END = 55 + + cplda_sfp_num = 0 + cpldb_sfp_num = 28 + cpldc_sfp_num = 28 + + _port_to_eeprom_mapping = {} + port_to_i2c_mapping = {} + + @property + def port_start(self): + return self.PORT_START + + @property + def port_end(self): + return self.PORT_END + + @property + def qsfp_port_start(self): + return self.QSFP_PORT_START + + @property + def qsfp_port_end(self): + return self.QSFP_PORT_END + + @property + def qsfp_ports(self): + return range(self.QSFP_PORT_START, self.PORTS_IN_BLOCK + 1) + + @property + def port_to_eeprom_mapping(self): + return self._port_to_eeprom_mapping + + + def __init__(self): + for x in range(self.port_start, self.port_end+1): + eeprom_path = '/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/sfp'+str(x+1)+'_eeprom' + self.port_to_eeprom_mapping[x] = eeprom_path + SfpUtilBase.__init__(self) + + + def get_presence(self, port_num): + if port_num < self.port_start or port_num > self.port_end: + return False + + if port_num < self.cpldb_sfp_num: + presence_path = '/sys/bus/i2c/devices/7-0075/sfp'+str(port_num+1)+'_present' + elif port_num < self.cpldb_sfp_num + self.cpldc_sfp_num: + presence_path = '/sys/bus/i2c/devices/8-0076/sfp'+str(port_num+1)+'_present' + + try: + file = open(presence_path) + except IOError as e: + print ("Error: unable to open file: %s" % str(e)) + return False + + value = int(file.readline().rstrip(),16) + + file.close() + if value & 0x1 == 1: + return True + + return False + + def get_low_power_mode(self, port_num): + if port_num not in self.qsfp_ports: + return False + + if port_num < self.cpldb_sfp_num: + lowpower_path = '/sys/bus/i2c/devices/7-0075/sfp'+str(port_num+1)+'_lowpower' + else: + lowpower_path = '/sys/bus/i2c/devices/8-0076/sfp'+str(port_num+1)+'_lowpower' + + try: + file = open(lowpower_path) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + value = int(file.readline().rstrip(),16) + + file.close() + if value == 1: + return True + + return False + + def set_low_power_mode(self, port_num, lpmode): + if port_num not in self.qsfp_ports: + return False + + if port_num < self.cpldb_sfp_num: + lowpower_path = '/sys/bus/i2c/devices/7-0075/sfp'+str(port_num+1)+'_lowpower' + else: + lowpower_path = '/sys/bus/i2c/devices/8-0076/sfp'+str(port_num+1)+'_lowpower' + + # LPMode is active high; set or clear the bit accordingly + if lpmode is True: + value = 1 + else: + value = 0 + + try: + file = open(lowpower_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + file.seek(0) + file.write(str(value)) + file.close() + + return True + + def reset(self, port_num): + if port_num not in self.qsfp_ports: + return False + if port_num < self.cpldb_sfp_num: + reset_path = '/sys/bus/i2c/devices/7-0075/sfp'+str(port_num+1)+'_reset' + else: + reset_path = '/sys/bus/i2c/devices/8-0076/sfp'+str(port_num+1)+'_reset' + + try: + file = open(reset_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + file.seek(0) + file.write(str(1)) + file.write(str(0)) + file.close() + + # Sleep 1 second to allow it to settle + time.sleep(1) + + try: + file = open(reset_path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + file.seek(0) + file.write(str(1)) + file.close() + + return True + + def read_porttab_mappings(self, porttabfile,asic_inst=0): + logical = [] + logical_to_bcm = {} + logical_to_physical = {} + physical_to_logical = {} + last_fp_port_index = 0 + last_portname = "" + first = 1 + port_pos_in_file = 0 + parse_fmt_port_config_ini = False + + try: + f = open(porttabfile) + except: + raise + + parse_fmt_port_config_ini = (os.path.basename(porttabfile) == "port_config.ini") + + # Read the porttab file and generate dicts + # with mapping for future reference. + # XXX: move the porttab + # parsing stuff to a separate module, or reuse + # if something already exists + for line in f: + line.strip() + if re.search("^#", line) is not None: + continue + + # Parsing logic for 'port_config.ini' file + if (parse_fmt_port_config_ini): + # bcm_port is not explicitly listed in port_config.ini format + # Currently we assume ports are listed in numerical order according to bcm_port + # so we use the port's position in the file (zero-based) as bcm_port + portname = line.split()[0] + + bcm_port = str(port_pos_in_file) + + if len(line.split()) >= 4: + fp_port_index = int(line.split()[4]) + else: + fp_port_index = portname.split("Ethernet").pop() + fp_port_index = int(fp_port_index.split("s").pop(0))/4 + else: # Parsing logic for older 'portmap.ini' file + (portname, bcm_port) = line.split("=")[1].split(",")[:2] + + fp_port_index = portname.split("Ethernet").pop() + fp_port_index = int(fp_port_index.split("s").pop(0))/4 + + if ((len(self.sfp_ports) > 0) and (fp_port_index not in self.sfp_ports)): + continue + + if(fp_port_index > self.QSFP_PORT_END): + continue + + if first == 1: + # Initialize last_[physical|logical]_port + # to the first valid port + last_fp_port_index = fp_port_index + last_portname = portname + first = 0 + + logical.append(portname) + + logical_to_bcm[portname] = "xe" + bcm_port + logical_to_physical[portname] = [fp_port_index] + if physical_to_logical.get(fp_port_index) is None: + physical_to_logical[fp_port_index] = [portname] + else: + physical_to_logical[fp_port_index].append( + portname) + + if (fp_port_index - last_fp_port_index) > 1: + # last port was a gang port + for p in range(last_fp_port_index+1, fp_port_index): + logical_to_physical[last_portname].append(p) + if physical_to_logical.get(p) is None: + physical_to_logical[p] = [last_portname] + else: + physical_to_logical[p].append(last_portname) + + last_fp_port_index = fp_port_index + last_portname = portname + + port_pos_in_file += 1 + + self.logical = logical + self.logical_to_bcm = logical_to_bcm + self.logical_to_physical = logical_to_physical + self.physical_to_logical = physical_to_logical + + """ + print "logical: " + self.logical + print "logical to bcm: " + self.logical_to_bcm + print "logical to physical: " + self.logical_to_physical + print "physical to logical: " + self.physical_to_logical + """ + + @property + def _get_presence_bitmap(self): + + bits = [] + for x in range(self.port_start, self.port_end+1): + bits.append(str(int(self.get_presence(x)))) + + rev = "".join(bits[::-1]) + return int(rev,2) + + data = {'present':1} + def get_transceiver_change_event(self, timeout=0): + port_dict = {} + + if timeout == 0: + cd_ms = sys.maxsize + else: + cd_ms = timeout + + #poll per second + while cd_ms > 0: + reg_value = self._get_presence_bitmap + changed_ports = self.data['present'] ^ reg_value + if changed_ports != 0: + break + time.sleep(1) + cd_ms = cd_ms - 1000 + + if changed_ports != 0: + for port in range (self.port_start, self.port_end+1): + # Mask off the bit corresponding to our port + mask = (1 << (port - self.port_start)) + if changed_ports & mask: + if (reg_value & mask) == 0: + port_dict[port] = SFP_STATUS_REMOVED + else: + port_dict[port] = SFP_STATUS_INSERTED + + # Update cache + self.data['present'] = reg_value + return True, port_dict + else: + return True, {} + + def get_transceiver_dom_info_dict(self, port_num): + transceiver_dom_info_dict = {} + + dom_info_dict_keys = ['temperature', 'voltage', 'rx1power', + 'rx2power', 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', 'tx3bias', + 'tx4bias', 'tx1power', 'tx2power', + 'tx3power', 'tx4power', + ] + transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if port_num in self.qsfp_ports: + return SfpUtilBase.get_transceiver_dom_info_dict(self, port_num) + elif port_num in self.osfp_ports: + return SfpUtilBase.get_transceiver_dom_info_dict(self, port_num) + else: + bdata='' + offset = 256 + file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) + bdata = sysfsfile_eeprom.read() + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + if len(bdata) <= 256: + sysfsfile_eeprom.close() + return None + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + dom_temperature_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + else: + return None + + dom_voltage_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + else: + return None + + dom_channel_monitor_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, (offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + else: + return None + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RXPower']['value'] + transceiver_dom_info_dict['rx2power'] = 'N/A' + transceiver_dom_info_dict['rx3power'] = 'N/A' + transceiver_dom_info_dict['rx4power'] = 'N/A' + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TXBias']['value'] + transceiver_dom_info_dict['tx2bias'] = 'N/A' + transceiver_dom_info_dict['tx3bias'] = 'N/A' + transceiver_dom_info_dict['tx4bias'] = 'N/A' + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TXPower']['value'] + transceiver_dom_info_dict['tx2power'] = 'N/A' + transceiver_dom_info_dict['tx3power'] = 'N/A' + transceiver_dom_info_dict['tx4power'] = 'N/A' + + return transceiver_dom_info_dict + + def get_transceiver_dom_threshold_info_dict(self, port_num): + transceiver_dom_threshold_info_dict = {} + + dom_info_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning' + ] + transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + if port_num in self.qsfp_ports: + return SfpUtilBase.get_transceiver_dom_threshold_info_dict(self, port_num) + elif port_num in self.osfp_ports: + # Below part is added to avoid fail xcvrd, shall be implemented later + return SfpUtilBase.get_transceiver_dom_threshold_info_dict(self, port_num) + else: + offset = 256 + bdata='' + file_path = self._get_port_eeprom_path(port_num, self.DOM_EEPROM_ADDR) + if not self._sfp_eeprom_present(file_path, 0): + return None + + try: + sysfsfile_eeprom = open(file_path, mode="rb", buffering=0) + bdata = sysfsfile_eeprom.read() + except IOError: + print("Error: reading sysfs file %s" % file_path) + return None + if len(bdata) <= 256: + sysfsfile_eeprom.close() + return None + + sfpd_obj = sff8472Dom() + if sfpd_obj is None: + return None + + dom_module_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, + (offset + SFP_MODULE_THRESHOLD_OFFSET), + SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_module_monitor_params(dom_module_threshold_raw, 0) + else: + return None + + dom_channel_threshold_raw = self._read_eeprom_specific_bytes(sysfsfile_eeprom, + (offset + SFP_CHANNL_THRESHOLD_OFFSET), + SFP_CHANNL_THRESHOLD_WIDTH) + if dom_channel_threshold_raw is not None: + dom_channel_threshold_data = sfpd_obj.parse_channel_thresh_monitor_params(dom_channel_threshold_raw, 0) + else: + return None + + try: + sysfsfile_eeprom.close() + except IOError: + print("Error: closing sysfs file %s" % file_path) + return None + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_channel_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_channel_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_channel_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_channel_threshold_data['data']['BiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_channel_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_channel_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_channel_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_channel_threshold_data['data']['TxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_channel_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_channel_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_channel_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_channel_threshold_data['data']['RxPowerLowWarning']['value'] + + return transceiver_dom_threshold_info_dict diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/pmon_daemon_control.json b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/pmon_daemon_control.json new file mode 100644 index 000000000000..a1e8eac808f1 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/pmon_daemon_control.json @@ -0,0 +1,6 @@ +{ + "skip_ledd": true, + "skip_xcvrd": false, + "skip_pcied": false, + "skip_syseepromd": false +} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/sensors.conf b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/sensors.conf new file mode 100644 index 000000000000..c43ef94a7173 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/sensors.conf @@ -0,0 +1,42 @@ +# libsensors configuration file for Clounix. +# The i2c bus portion is omit because adapter name +# changes every time when system boot up. + +chip "lm75b-i2c-*-4a" + label temp1 "LM75BD / Ambient NPU" + set temp1_max 80 + set temp1_max_hyst 95 + +chip "pega_hwmon_mcu-i2c-*-70" + label temp1 "LM75BD / Ambient MAC side" + label temp2 "LM75BD / Ambient MAC" + label temp3 "LM75BD / Ambient FAN" + set temp1_max 80 + set temp2_max 80 + set temp3_max 80 + set temp1_crit 90 + set temp2_crit 90 + set temp3_crit 90 + +chip "fn8656_bnf_psu-i2c-*-58" + label temp1 "PSU1 Ambient" + label temp2 "PSU1 SR Hotspot" + label temp3 "PSU1 PFC Hotspot" + set temp1_max 60 + set temp2_max 80 + set temp3_max 80 + set temp1_crit 65 #no higher than 65,manufacture temperature max + set temp2_crit 122 #no higher than 122,manufacture temperature max + set temp3_crit 96 #no higher than 96,manufacture temperature max + +chip "fn8656_bnf_psu-i2c-*-59" + label temp1 "PSU2 Ambient" + label temp2 "PSU2 SR Hotspot" + label temp3 "PSU2 PFC Hotspot" + set temp1_max 60 + set temp2_max 80 + set temp3_max 80 + set temp1_crit 65 #no higher than 65,manufacture temperature max + set temp2_crit 122 #no higher than 122,manufacture temperature max + set temp3_crit 96 #no higher than 96,manufacture temperature max + \ No newline at end of file diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/system_health_monitoring_config.json b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/system_health_monitoring_config.json new file mode 100644 index 000000000000..acf607dc4c3a --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/system_health_monitoring_config.json @@ -0,0 +1,11 @@ +{ + "services_to_ignore": [], + "devices_to_ignore": ["asic"], + "user_defined_checkers": [], + "polling_interval": 60, + "led_color": { + "fault": "red", + "normal": "green", + "booting": "blink_green" + } +} diff --git a/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/thermal_policy.json b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/thermal_policy.json new file mode 100644 index 000000000000..f67c982f8681 --- /dev/null +++ b/device/pegatron/x86_64-pegatron_fn8656_bnf-r0/thermal_policy.json @@ -0,0 +1,31 @@ +{ + "thermal_control_algorithm": { + "run_at_boot_up": "true" + }, + "info_types": [ + { + "type": "chassis_info" + }, + { + "type": "fan_info" + }, + { + "type": "thermal_info" + } + ], + "policies": [ + { + "name": "temp over high critical threshold", + "conditions": [ + { + "type": "thermal.over.high_critical_threshold" + } + ], + "actions": [ + { + "type": "switch.power_cycling" + } + ] + } + ] +} \ No newline at end of file diff --git a/files/build_templates/per_namespace/syncd.service.j2 b/files/build_templates/per_namespace/syncd.service.j2 index 9acf97c29fd4..e099a6986725 100644 --- a/files/build_templates/per_namespace/syncd.service.j2 +++ b/files/build_templates/per_namespace/syncd.service.j2 @@ -13,6 +13,9 @@ After=opennsl-modules.service {% elif sonic_asic_platform == 'nephos' %} Requires=nps-modules.service After=nps-modules.service +{% elif sonic_asic_platform == 'clounix' %} +Requires=clx-modules.service +After=clx-modules.service {% endif %} Requires=updategraph.service After=updategraph.service diff --git a/platform/clounix/clounix-modules.dep b/platform/clounix/clounix-modules.dep new file mode 100644 index 000000000000..0bbfc3e4c2ca --- /dev/null +++ b/platform/clounix/clounix-modules.dep @@ -0,0 +1,11 @@ + +SPATH := $($(CLOUNIX_MODULE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/clounix-modules.mk platform/clounix/clounix-modules.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && git ls-files)) + +$(CLOUNIX_MODULE)_CACHE_MODE := GIT_CONTENT_SHA +$(CLOUNIX_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(CLOUNIX_MODULE)_DEP_FILES := $(DEP_FILES) +$(CLOUNIX_MODULE)_SMDEP_FILES := $(SMDEP_FILES) +$(CLOUNIX_MODULE)_SMDEP_PATHS := $(SPATH) diff --git a/platform/clounix/clounix-modules.mk b/platform/clounix/clounix-modules.mk new file mode 100644 index 000000000000..34c419d26eb7 --- /dev/null +++ b/platform/clounix/clounix-modules.mk @@ -0,0 +1,8 @@ +# Clounix Platform modules + +VERSION = 1.0.1 + +CLOUNIX_MODULE = clounix-modules_$(VERSION)_amd64.deb +$(CLOUNIX_MODULE)_SRC_PATH = $(PLATFORM_PATH)/clounix-modules +$(CLOUNIX_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) $(CLOUNIX_SAI) +SONIC_DPKG_DEBS += $(CLOUNIX_MODULE) diff --git a/platform/clounix/clounix-modules/README.md b/platform/clounix/clounix-modules/README.md new file mode 100644 index 000000000000..7dcf5034bd6e --- /dev/null +++ b/platform/clounix/clounix-modules/README.md @@ -0,0 +1,2 @@ +# Clounix-modules +Device drivers for support of Clounix platform for the SONiC project diff --git a/platform/clounix/clounix-modules/debian/changelog b/platform/clounix/clounix-modules/debian/changelog new file mode 100644 index 000000000000..581abba03fd8 --- /dev/null +++ b/platform/clounix/clounix-modules/debian/changelog @@ -0,0 +1,11 @@ +clounix-modules (1.0.1) unstable; urgency=low + + * Upgrade ko version to 3.0.0 + + -- Support Tue, 17 Mar 2020 15:54:00 +0800 + +clounix-modules (1.0.0) unstable; urgency=low + + * Initial release + + -- Support Fri, 15 Mar 2019 15:54:00 +0800 diff --git a/platform/clounix/clounix-modules/debian/compat b/platform/clounix/clounix-modules/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/platform/clounix/clounix-modules/debian/compat @@ -0,0 +1 @@ +9 diff --git a/platform/clounix/clounix-modules/debian/control b/platform/clounix/clounix-modules/debian/control new file mode 100644 index 000000000000..184b102e5123 --- /dev/null +++ b/platform/clounix/clounix-modules/debian/control @@ -0,0 +1,12 @@ +Source: clounix-modules +Section: main +Priority: extra +Maintainer: support +Build-Depends: debhelper (>= 8.0.0), bzip2 +Standards-Version: 3.9.3 + +Package: clounix-modules +Architecture: amd64 +Depends: linux-image-4.19.0-12-2-amd64-unsigned +Description: kernel modules for clounix asic + diff --git a/platform/clounix/clounix-modules/debian/rules b/platform/clounix/clounix-modules/debian/rules new file mode 100755 index 000000000000..27e4a94db35b --- /dev/null +++ b/platform/clounix/clounix-modules/debian/rules @@ -0,0 +1,34 @@ +#!/usr/bin/make -f +export INSTALL_MOD_DIR:=extra + +PACKAGE_NAME := clounix-modules +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +SERVICE_DIR := service +INITD_DIR := init.d +MODULE_SRC := $(shell pwd)/modules +CURRENT_DIR := $(cd "$(dirname "$0")"; pwd) + +%: + dh $@ + +override_dh_auto_build: + ls + make -C $(MODULE_SRC) + +override_dh_auto_install: + dh_installdirs -p$(PACKAGE_NAME) /lib/systemd/system + cp $(MODULE_SRC)/service/*.service debian/$(PACKAGE_NAME)/lib/systemd/system/ + dh_installdirs -p$(PACKAGE_NAME) /etc/init.d + cp $(MODULE_SRC)/init.d/* debian/$(PACKAGE_NAME)/etc/init.d/ + dh_installdirs -p$(PACKAGE_NAME) $(KERNEL_SRC)/extra/ + cp $(MODULE_SRC)/build/module/*.ko debian/$(PACKAGE_NAME)/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); + +override_dh_usrlocal: + +override_dh_pysupport: + +override_dh_clean: + dh_clean + test -d $(MODULE_SRC)/build || rm -rf $(MODULE_SRC)/build + diff --git a/platform/clounix/clounix-modules/modules/Makefile b/platform/clounix/clounix-modules/modules/Makefile new file mode 100755 index 000000000000..c424338180f3 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/Makefile @@ -0,0 +1,94 @@ +################################################################################ +# Copyright (C) 2021 Clounix, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# 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 +# version 2 along with this program. +################################################################################ +################################################################################ +KERNEL_MODULE := $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) + +################################################################################ +MAKE := $(shell which make) +RM := rm -rf +MKDIR := mkdir -p +CP := cp +MV := mv +TEST_PATH := test -d + +#KVERSION ?= $(shell uname -r) +KVERSION ?= 4.19.0-12-2-amd64 +OS_PATH := /lib/modules/$(KVERSION)/build +SRC_PATH := $(KERNEL_MODULE)/src +INC_PATH := $(SRC_PATH)/inc +BUILD_OUTPUT_DIR := $(KERNEL_MODULE)/build +MODULE_OUTPUT_DIR := $(BUILD_OUTPUT_DIR)/module + +all: compile install +################################################################################ +EXTRA_CFLAGS += -I$(INC_PATH) +EXTRA_CFLAGS += -I$(SRC_PATH)/clx_netif/inc/ +EXTRA_CFLAGS += -DCLX_EN_NETIF +EXTRA_CFLAGS += -DCLX_EN_DAWN +EXTRA_CFLAGS += -DCLX_EN_LIGHTNING +EXTRA_CFLAGS += -DCLX_EN_DEBUG +EXTRA_CFLAGS += -DCLX_LINUX_USER_MODE +EXTRA_CFLAGS += -DCLX_EN_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCLX_EN_COMPILER_SUPPORT_FUNCTION +EXTRA_CFLAGS += -DCLX_EN_COMPILER_SUPPORT_LONG_LONG + +ifeq ($(shell uname -m),x86_64) +EXTRA_CFLAGS += -DCLX_EN_HOST_64_BIT_LITTLE_ENDIAN +EXTRA_CFLAGS += -DCLX_EN_64BIT_ADDR +else +EXTRA_CFLAGS += -DCLX_EN_HOST_32_BIT_LITTLE_ENDIAN +endif + +################################################################################ +DEV_MODULE_NAME := clx_dev +NETIF_MODULE_NAME := clx_netif + +################################################################################ +DEV_OBJS_TOTAL := ./src/clx_dev/osal_mdc.o +DEV_OBJS_TOTAL += ./src/clx_dev/osal_isymbol.o + +NETIF_OBJS_TOTAL := ./src/clx_netif/netif_knl.o +NETIF_OBJS_TOTAL += ./src/clx_netif/netif_osal.o +NETIF_OBJS_TOTAL += ./src/clx_netif/netif_perf.o +NETIF_OBJS_TOTAL += ./src/clx_netif/netif_nl.o +NETIF_OBJS_TOTAL += ./src/clx_netif/hal_dawn_pkt_knl.o +NETIF_OBJS_TOTAL += ./src/clx_netif/hal_lightning_pkt_knl.o + +obj-m := $(DEV_MODULE_NAME).o $(NETIF_MODULE_NAME).o +$(DEV_MODULE_NAME)-objs := $(DEV_OBJS_TOTAL) +$(NETIF_MODULE_NAME)-objs := $(NETIF_OBJS_TOTAL) + +KBUILD_EXTRA_SYMBOLS := $(BUILD_OUTPUT_DIR)/Module.symvers +################################################################################ +folder: + $(TEST_PATH) $(BUILD_OUTPUT_DIR) || $(MKDIR) $(BUILD_OUTPUT_DIR) + $(TEST_PATH) $(BUILD_OUTPUT_DIR)/src || $(MKDIR) $(BUILD_OUTPUT_DIR)/src + +compile:: folder + touch $(BUILD_OUTPUT_DIR)/Makefile + $(MAKE) -C $(OS_PATH) M=$(BUILD_OUTPUT_DIR) src=$(shell pwd) modules EXTRA_CFLAGS="$(EXTRA_CFLAGS)" KBUILD_EXTRA_SYMBOLS=$(KBUILD_EXTRA_SYMBOLS) + +install:: + $(TEST_PATH) $(MODULE_OUTPUT_DIR) || $(MKDIR) $(MODULE_OUTPUT_DIR) + $(MV) $(BUILD_OUTPUT_DIR)/$(DEV_MODULE_NAME).ko $(MODULE_OUTPUT_DIR)/$(DEV_MODULE_NAME).ko + $(MV) $(BUILD_OUTPUT_DIR)/$(NETIF_MODULE_NAME).ko $(MODULE_OUTPUT_DIR)/$(NETIF_MODULE_NAME).ko + +clean:: + $(RM) $(BUILD_OUTPUT_DIR) + +.PHONY: all compile install clean +.NOTPARALLEL: all compile install clean + diff --git a/platform/clounix/clounix-modules/modules/README b/platform/clounix/clounix-modules/modules/README new file mode 100644 index 000000000000..796fe7de82e1 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/README @@ -0,0 +1,32 @@ +################################################################################ +# Copyright (C) 2021 Clounix, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of version 2 of the GNU General Public +# License as published by the Free Software Foundation. +# +# 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 +# version 2 along with this program. +################################################################################ +Step 1~4 show how to build and execute CLX kernel modules. + +1. Modify clounix-modules/Makefile to specify the output directory to BUILD_OUTPUT_DIR. + The default output path is clounix-modules/build. + +2. Compile: + cd clounix-modules/ && make + +3. The output kernel modules will be found in $(BUILD_OUTPUT_DIR)/modules/ + - clx_dev.ko + - clx_netif.ko + +4. Load modules: + (1) insmod clx_dev.ko + (2) insmod clx_netif.ko + + Note that the module inserting sequence cannot be changed. diff --git a/platform/clounix/clounix-modules/modules/init.d/clx-modules b/platform/clounix/clounix-modules/modules/init.d/clx-modules new file mode 100755 index 000000000000..d78678b7b469 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/init.d/clx-modules @@ -0,0 +1,62 @@ +#!/bin/bash +# This script load/unload clx kernel modules + +### BEGIN INIT INFO +# Provides: load-clx-modules +# Required-Start: +# Required-Stop: +# Should-Start: +# Should-Stop: +# Default-Start: S +# Default-Stop: 0 6 +# Short-Description: Load clx kernel modules +### END INIT INFO + +case "$1" in +start) + echo -n "Load clx kernel modules... " + + RMEM_SIZE=`cat /proc/sys/net/core/rmem_max` + if [ $RMEM_SIZE -lt 8388608 ]; then + echo "8388608" > /proc/sys/net/core/rmem_max + fi + WMEM_SIZE=`cat /proc/sys/net/core/wmem_max` + if [ $WMEM_SIZE -lt 25165824 ]; then + echo "25165824" > /proc/sys/net/core/wmem_max + fi + + if ! modprobe clx_dev ; then + modprobe nps_dev + fi + if ! modprobe clx_netif ; then + modprobe nps_netif + fi + + echo "done." + ;; + +stop) + echo -n "Unload clx kernel modules... " + + if ! rmmod clx_netif ; then + rmmod nps_netif + fi + if ! rmmod clx_dev ; then + rmmod nps_dev + fi + + echo "done." + ;; + +force-reload|restart) + echo "Not supported" + ;; + +*) + echo "Usage: /etc/init.d/clx-modules {start|stop}" + exit 1 + ;; +esac + +exit 0 + diff --git a/platform/clounix/clounix-modules/modules/service/clx-modules.service b/platform/clounix/clounix-modules/modules/service/clx-modules.service new file mode 100644 index 000000000000..5adb42bfece1 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/service/clx-modules.service @@ -0,0 +1,13 @@ +[Unit] +Description=Clounix kernel modules init +After=local-fs.target +Before=syncd.service + +[Service] +Type=oneshot +ExecStart=-/etc/init.d/clx-modules start +ExecStop=-/etc/init.d/clx-modules stop +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/clounix/clounix-modules/modules/src/clx_dev/osal_isymbol.c b/platform/clounix/clounix-modules/modules/src/clx_dev/osal_isymbol.c new file mode 100644 index 000000000000..f9036ad243c8 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_dev/osal_isymbol.c @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: osal_isymbol.c +* PURPOSE: +* It provide global OSAL symbol export for linux kernel module +* NOTES: +*/ +#include +#include + +/* ----------------------------------------------------- */ +#include +/* dma */ +extern struct pci_dev *_ptr_ext_pci_dev; +EXPORT_SYMBOL(_ptr_ext_pci_dev); + +#if defined(CLX_LINUX_KERNEL_MODE) +#include +extern CLX_INIT_WRITE_FUNC_T _ext_dsh_write_func; +EXPORT_SYMBOL(_ext_dsh_write_func); +#endif + +#if defined(CLX_LINUX_USER_MODE) +EXPORT_SYMBOL(osal_mdc_readPciReg); +EXPORT_SYMBOL(osal_mdc_writePciReg); +#if defined(CLX_EN_NETIF) +/* intr */ +/* for kernel module, this API will be exported by script with other OSAL functions in osal_symbol.c */ +EXPORT_SYMBOL(osal_mdc_registerIsr); +#endif +#endif diff --git a/platform/clounix/clounix-modules/modules/src/clx_dev/osal_mdc.c b/platform/clounix/clounix-modules/modules/src/clx_dev/osal_mdc.c new file mode 100644 index 000000000000..2bc0246a6e6a --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_dev/osal_mdc.c @@ -0,0 +1,2587 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: osal_mdc.c + * PURPOSE: + * 1. Provide device operate from AML interface + * NOTES: + * + */ + +/* INCLUDE FILE DECLARATIONS + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if defined(CLX_LINUX_USER_MODE) +#include + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0) +#include +#else +#include +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +#if defined(OSAL_MDC_DMA_RESERVED_MEM_CACHEABLE) + #define IOREMAP_API(a, b) ioremap(a, b) +#else + #define IOREMAP_API(a, b) ioremap_nocache(a, b) +#endif +#else + #define IOREMAP_API(a, b) ioremap(a, b) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#endif + +/* #define OSAL_MDC_EN_MSI */ +/* #define OSAL_MDC_DMA_RESERVED_MEM_CACHEABLE */ +/* #define OSAL_MDC_EN_TEST */ + +/* NAMING CONSTANT DECLARATIONS + */ +#define OSAL_MDC_PCI_BAR0_OFFSET (0x0) +#define OSAL_MDC_ERR printk + +/* MACRO FUNCTION DECLARATIONS + */ + +/* DATA TYPE DECLARATIONS + */ +typedef struct +{ + UI32_T unit; + struct pci_dev *ptr_pci_dev; + UI32_T *ptr_mmio_virt_addr; + int irq; + AML_DEV_ISR_FUNC_T isr_callback; + void *ptr_isr_data; + +} OSAL_MDC_DEV_T; + +typedef struct +{ + OSAL_MDC_DEV_T dev[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; + UI32_T dev_num; + OSAL_MDC_DMA_INFO_T dma_info; + +} OSAL_MDC_CB_T; + +#if defined(CLX_LINUX_USER_MODE) + +typedef struct +{ + OSAL_MDC_IOCTL_CALLBACK_FUNC_T callback[OSAL_MDC_IOCTL_TYPE_LAST]; + +} OSAL_MDC_IOCTL_CB_T; + +#if !defined(CLX_EN_DMA_RESERVED) +typedef struct +{ + CLX_ADDR_T phy_addr; + UI32_T size; + struct list_head list; + +} OSAL_MDC_USER_MODE_DMA_NODE_T; +#endif + +#endif + + +#if defined(CLX_LINUX_KERNEL_MODE) + +/* re-define the interface to align OSAL_MDC's implementation with the prototype of CMLIB */ +#define osal_mdc_list_create(__capa__, __type__, __name__, __list__) _osal_mdc_list_create(__capa__, __list__) +#define osal_mdc_list_destroy(__list__, __callback__) _osal_mdc_list_destroy(__list__) +#define osal_mdc_list_getNodeData(__list__, __node__, __data__) _osal_mdc_list_getNodeData(__list__, __node__, __data__) +#define osal_mdc_list_next(__list__, __node__, __next__) _osal_mdc_list_next(__list__, __node__, __next__) +#define osal_mdc_list_locateHead(__list__, __node__) _osal_mdc_list_locateHead(__list__, __node__) +#define osal_mdc_list_insertToHead(__list__, __data__) _osal_mdc_list_insertToHead(__list__, __data__) +#define osal_mdc_list_deleteByData(__list__, __data__) _osal_mdc_list_deleteByData(__list__, __data__) + +#if defined(CLX_EN_DMA_RESERVED) +#define osal_mdc_list_insertBefore(__list__, __node__, __data__) _osal_mdc_list_insertBefore(__list__, __node__, __data__) +#define osal_mdc_list_prev(__list__, __node__, __prev__) _osal_mdc_list_prev(__list__, __node__, __prev__) +#endif + +#define OSAL_MDC_LIST_TYPE_DOUBLE (1) /* don't care the type, always be double */ +#define OSAL_MDC_LIST_TYPE_SINGLE (0) /* don't care the type, always be double */ + +static CLX_ERROR_NO_T +_osal_mdc_list_create( + const UI32_T capacity, + OSAL_MDC_LIST_T **pptr_list ) +{ + CLX_ERROR_NO_T rc = CLX_E_NO_MEMORY; + + *pptr_list = NULL; + + *pptr_list = osal_alloc(sizeof(OSAL_MDC_LIST_T)); + if (NULL != *pptr_list) + { + (*pptr_list)->capacity = capacity; + (*pptr_list)->node_cnt = 0; + (*pptr_list)->ptr_head_node = NULL; + (*pptr_list)->ptr_tail_node = NULL; + rc = CLX_E_OK; + } + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_list_destroy( + OSAL_MDC_LIST_T *ptr_list ) +{ + OSAL_MDC_LIST_NODE_T *ptr_cur_node, *ptr_next_node; + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + if (ptr_list->node_cnt != 0) + { + OSAL_MDC_ERR("dma list not empty, node num=%d\n", + ptr_list->node_cnt); + ptr_cur_node = ptr_list->ptr_head_node; + while(NULL != ptr_cur_node) + { + ptr_next_node = ptr_cur_node->ptr_next; + osal_free(ptr_cur_node); + ptr_list->node_cnt--; + ptr_cur_node = ptr_next_node; + } + } + + osal_free(ptr_list); + rc = CLX_E_OK; + } + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_list_getNodeData( + OSAL_MDC_LIST_T *ptr_list, + OSAL_MDC_LIST_NODE_T *ptr_node, + void **pptr_node_data ) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + if (NULL != ptr_node) + { + *pptr_node_data = ptr_node->ptr_data; + rc = CLX_E_OK; + } + } + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_list_insertToHead( + OSAL_MDC_LIST_T *ptr_list, + void *ptr_data ) +{ + OSAL_MDC_LIST_NODE_T *ptr_new_node = NULL; + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + ptr_new_node = osal_alloc(sizeof(OSAL_MDC_LIST_NODE_T)); + if (NULL != ptr_new_node) + { + ptr_new_node->ptr_data = ptr_data; + + /* no former node */ + ptr_new_node->ptr_prev = NULL; + + if (NULL != ptr_list->ptr_head_node) + { + ptr_list->ptr_head_node->ptr_prev = ptr_new_node; + ptr_new_node->ptr_next = ptr_list->ptr_head_node; + } + else + { + /* 1st node insertion */ + ptr_list->ptr_tail_node = ptr_new_node; + ptr_new_node->ptr_next = NULL; + } + + ptr_list->ptr_head_node = ptr_new_node; + ptr_list->node_cnt++; + rc = CLX_E_OK; + } + } + + return (rc); +} + +#if defined(CLX_EN_DMA_RESERVED) +static CLX_ERROR_NO_T +_osal_mdc_list_insertBefore( + OSAL_MDC_LIST_T *ptr_list, + OSAL_MDC_LIST_NODE_T *ptr_node, + void *ptr_data ) +{ + OSAL_MDC_LIST_NODE_T *ptr_new_node = NULL; + OSAL_MDC_LIST_NODE_T *ptr_prev_node = ptr_node->ptr_prev; + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + if (NULL != ptr_node) + { + ptr_new_node = osal_alloc(sizeof(OSAL_MDC_LIST_NODE_T)); + if (NULL != ptr_new_node) + { + ptr_new_node->ptr_data = ptr_data; + + /* location */ + if (NULL != ptr_prev_node) + { + ptr_prev_node->ptr_next = ptr_new_node; + } + ptr_new_node->ptr_prev = ptr_prev_node; + ptr_new_node->ptr_next = ptr_node; + ptr_node->ptr_prev = ptr_new_node; + + /* update head if necessary */ + if (ptr_list->ptr_head_node == ptr_node) + { + ptr_list->ptr_head_node = ptr_new_node; + } + + ptr_list->node_cnt++; + rc = CLX_E_OK; + } + } + } + + return (rc); +} +#endif + +static CLX_ERROR_NO_T +_osal_mdc_list_deleteTargetNode( + OSAL_MDC_LIST_T *ptr_list, + OSAL_MDC_LIST_NODE_T *ptr_target_node) +{ + OSAL_MDC_LIST_NODE_T *ptr_prev_node = ptr_target_node->ptr_prev; + OSAL_MDC_LIST_NODE_T *ptr_next_node = ptr_target_node->ptr_next; + + if (ptr_target_node == ptr_list->ptr_head_node) + { + ptr_list->ptr_head_node = ptr_next_node; + if (NULL != ptr_next_node) + { + ptr_next_node->ptr_prev = NULL; + } + else + { + /* there's only 1 node in the list, and it gets removed */ + ptr_list->ptr_tail_node = NULL; + } + } + else if (ptr_target_node == ptr_list->ptr_tail_node) + { + /* at least 2 nodes in the list, and the target node locates tail */ + ptr_list->ptr_tail_node = ptr_prev_node; + ptr_prev_node->ptr_next = NULL; + } + else + { + /* intermediate node */ + ptr_prev_node->ptr_next = ptr_next_node; + ptr_next_node->ptr_prev = ptr_prev_node; + } + + osal_free(ptr_target_node); + ptr_list->node_cnt--; + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_list_deleteByData( + OSAL_MDC_LIST_T *ptr_list, + void *ptr_delete_data) +{ + OSAL_MDC_LIST_NODE_T *ptr_tmp_node; + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + ptr_tmp_node = ptr_list->ptr_head_node; + while (NULL != ptr_tmp_node) + { + if (ptr_tmp_node->ptr_data == ptr_delete_data) + { + rc = _osal_mdc_list_deleteTargetNode(ptr_list, ptr_tmp_node); + break; + } + else + { + ptr_tmp_node = ptr_tmp_node->ptr_next; + } + } + } + + return (rc); +} + + +static CLX_ERROR_NO_T +_osal_mdc_list_locateHead( + OSAL_MDC_LIST_T *ptr_list, + OSAL_MDC_LIST_NODE_T **pptr_node ) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + *pptr_node = ptr_list->ptr_head_node; + if (NULL != *pptr_node) + { + rc = CLX_E_OK; + } + } + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_list_next( + OSAL_MDC_LIST_T *ptr_list, + OSAL_MDC_LIST_NODE_T *ptr_node, + OSAL_MDC_LIST_NODE_T **pptr_next_node ) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + if (NULL != ptr_node) + { + *pptr_next_node = ptr_node->ptr_next; + if (NULL != *pptr_next_node) + { + rc = CLX_E_OK; + } + } + } + + return (rc); +} + +#if defined(CLX_EN_DMA_RESERVED) +static CLX_ERROR_NO_T +_osal_mdc_list_prev( + OSAL_MDC_LIST_T *ptr_list, + OSAL_MDC_LIST_NODE_T *ptr_node, + OSAL_MDC_LIST_NODE_T **pptr_prev_node ) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (NULL != ptr_list) + { + if (NULL != ptr_node) + { + *pptr_prev_node = ptr_node->ptr_prev; + if (NULL != *pptr_prev_node) + { + rc = CLX_E_OK; + } + } + } + + return (rc); +} +#endif /* End of defined(CLX_EN_DMA_RESERVED) */ + +#endif /* End if defined(CLX_LINUX_KERNEL_MODE) */ + +/* GLOBAL VARIABLE DECLARATIONS + */ +static OSAL_MDC_CB_T _osal_mdc_cb; + +/* To let system callback function to access AML database */ +static AML_DEV_T *_ptr_osal_mdc_dev; + +/* Interface */ +struct pci_dev *_ptr_ext_pci_dev; + + +/* STATIC VARIABLE DECLARATIONS + */ +/* --------------------------------------------------------------------------- I2C interface */ +#if defined(AML_EN_I2C) +extern CLX_ERROR_NO_T +dev_switch_readBuffer( + const UI32_T addr, + const UI32_T addr_len, + UI8_T *ptr_buf, + const UI32_T buf_len); + +extern CLX_ERROR_NO_T +dev_switch_writeBuffer( + const UI32_T addr, + const UI32_T addr_len, + const UI8_T *ptr_buf, + const UI32_T buf_len); + +static CLX_ERROR_NO_T +_osal_mdc_readI2cReg( + const UI32_T unit, + const UI32_T offset, + UI32_T *ptr_data, + const UI32_T len) +{ + return dev_switch_readBuffer(offset, sizeof(offset), (UI8_T *)ptr_data, len); +} + +static CLX_ERROR_NO_T +_osal_mdc_writeI2cReg( + const UI32_T unit, + const UI32_T offset, + const UI32_T *ptr_data, + const UI32_T len) +{ + return dev_switch_writeBuffer(offset, sizeof(offset), (UI8_T *)ptr_data, len); +} + +static CLX_ERROR_NO_T +_osal_mdc_probeI2cDevice(void) +{ + /* I2C interface will be probed in BSP. */ + _ptr_osal_mdc_dev->if_type = AML_DEV_TYPE_I2C; + _ptr_osal_mdc_dev->access.read_callback = _osal_mdc_readI2cReg; + _ptr_osal_mdc_dev->access.write_callback = _osal_mdc_writeI2cReg; + + _ptr_osal_mdc_dev->id.device = HAL_DEVICE_ID_CL3258; + _ptr_osal_mdc_dev->id.vendor = HAL_CLX_VENDOR_ID; + _ptr_osal_mdc_dev->id.revision = HAL_REVISION_ID_E2; + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_removeI2cDevice(void) +{ + /* I2C interface will be removed in BSP. */ + return (CLX_E_OK); +} + +/* --------------------------------------------------------------------------- PCI interface */ +#else + +static CLX_ERROR_NO_T +_osal_mdc_getPciMmioInfo( + struct pci_dev *pdev, + UI32_T **pptr_base_addr) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + CLX_ADDR_T phy_addr; + UI32_T reg_space_sz; + + phy_addr = pci_resource_start(pdev, OSAL_MDC_PCI_BAR0_OFFSET); + reg_space_sz = pci_resource_len(pdev, OSAL_MDC_PCI_BAR0_OFFSET); + + if (0 == pci_request_region(pdev, OSAL_MDC_PCI_BAR0_OFFSET, OSAL_MDC_DRIVER_NAME)) + { + *pptr_base_addr = IOREMAP_API(phy_addr, reg_space_sz); + if (NULL != *pptr_base_addr) + { + rc = CLX_E_OK; + } + } + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_readPciReg( + const UI32_T unit, + const UI32_T offset, + UI32_T *ptr_data, + const UI32_T len) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T idx; + UI32_T count; + volatile UI32_T *ptr_base_addr = _osal_mdc_cb.dev[unit].ptr_mmio_virt_addr; + + if (NULL != ptr_base_addr) + { + if (OSAL_MDC_PCI_BUS_WIDTH == len) + { + *ptr_data = *((UI32_T *)((CLX_HUGE_T)ptr_base_addr + offset)); + } + else + { + if (0 == (len % OSAL_MDC_PCI_BUS_WIDTH)) + { + count = len / OSAL_MDC_PCI_BUS_WIDTH; + for (idx = 0; idx < count; idx++) + { + *(ptr_data + idx) = *((UI32_T *)((CLX_HUGE_T)ptr_base_addr + offset + idx * 4)); + } + } + else + { + rc = CLX_E_OTHERS; + } + } + } + else + { + rc = CLX_E_NOT_INITED; + } + + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_writePciReg( + const UI32_T unit, + const UI32_T offset, + const UI32_T *ptr_data, + const UI32_T len) +{ + UI32_T idx; + UI32_T count; + volatile UI32_T *ptr_base_addr = _osal_mdc_cb.dev[unit].ptr_mmio_virt_addr; + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (NULL != ptr_base_addr) + { + if (OSAL_MDC_PCI_BUS_WIDTH == len) + { + *((UI32_T *)((CLX_HUGE_T)ptr_base_addr + offset)) = *ptr_data; + } + else + { + if (0 == (len % OSAL_MDC_PCI_BUS_WIDTH)) + { + count = len / OSAL_MDC_PCI_BUS_WIDTH; + for (idx = 0; idx < count; idx++) + { + *((UI32_T *)((CLX_HUGE_T)ptr_base_addr + offset + idx * 4)) = *(ptr_data + idx); + } + } + else + { + rc = CLX_E_OTHERS; + } + } + } + else + { + rc = CLX_E_NOT_INITED; + } + + return (rc); +} + +static int +_osal_mdc_probePciCallback( + struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int linux_rc; + UI16_T device_id; + UI16_T vendor_id; + UI8_T revision_id; + CLX_ERROR_NO_T rc = CLX_E_OK; + + linux_rc = pci_enable_device(pdev); + if (0 == linux_rc) + { + _ptr_osal_mdc_dev->if_type = AML_DEV_TYPE_PCI; + + pci_read_config_word(pdev, PCI_DEVICE_ID, &device_id); + pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); + pci_read_config_byte(pdev, PCI_REVISION_ID, &revision_id); + + _ptr_osal_mdc_dev->id.device = (UI32_T)device_id; + _ptr_osal_mdc_dev->id.vendor = (UI32_T)vendor_id; + _ptr_osal_mdc_dev->id.revision = (UI32_T)revision_id; + +#if defined(CLX_LINUX_KERNEL_MODE) + _ptr_osal_mdc_dev->access.read_callback = osal_mdc_readPciReg; + _ptr_osal_mdc_dev->access.write_callback = osal_mdc_writePciReg; +#endif + + rc = _osal_mdc_getPciMmioInfo(pdev, &_osal_mdc_cb.dev[_osal_mdc_cb.dev_num].ptr_mmio_virt_addr); + if (CLX_E_OK == rc) + { + /* Save the database to pdev structure for system callback to release recource, + * such like disconnecting ISR etc. + */ + _osal_mdc_cb.dev[_osal_mdc_cb.dev_num].irq = pdev->irq; + _osal_mdc_cb.dev[_osal_mdc_cb.dev_num].ptr_pci_dev = pdev; + _osal_mdc_cb.dev[_osal_mdc_cb.dev_num].unit = _osal_mdc_cb.dev_num; + + pci_set_drvdata(pdev, &_osal_mdc_cb.dev[_osal_mdc_cb.dev_num]); + + /* To set the bus master bit on device to enable the DMA transaction from PCIe EP to RC + * The bus master bit gets cleared when pci_disable_device() is called + */ + pci_set_master(pdev); + +#if !defined(CLX_EN_DMA_RESERVED) + if (NULL == _osal_mdc_cb.dma_info.ptr_dma_dev) + { + /* This variable is for dma_alloc_coherent */ + _osal_mdc_cb.dma_info.ptr_dma_dev = &pdev->dev; + } +#endif + _osal_mdc_cb.dev_num++; + _ptr_osal_mdc_dev++; + } + } + else + { + OSAL_MDC_ERR("enable pci dev failed, linux_rc=%d\n", linux_rc); + } + + return (0); +} + +static void +_osal_mdc_removePciCallback( + struct pci_dev *pdev) +{ + OSAL_MDC_DEV_T *ptr_dev = (OSAL_MDC_DEV_T *)pci_get_drvdata(pdev); + + iounmap(ptr_dev->ptr_mmio_virt_addr); + pci_release_region(pdev, OSAL_MDC_PCI_BAR0_OFFSET); + pci_disable_device(pdev); + _osal_mdc_cb.dev_num--; +} + +static struct pci_device_id _osal_mdc_id_table[] = +{ + {PCI_DEVICE(HAL_CLX_VENDOR_ID, PCI_ANY_ID)}, + {PCI_DEVICE(HAL_CL_VENDOR_ID, PCI_ANY_ID)}, +}; + +static struct pci_driver _osal_mdc_pci_driver = +{ + .name = OSAL_MDC_DRIVER_NAME, + .id_table = _osal_mdc_id_table, + .probe = _osal_mdc_probePciCallback, + .remove = _osal_mdc_removePciCallback, +}; + +static CLX_ERROR_NO_T +_osal_mdc_probePciDevice(void) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (pci_register_driver(&_osal_mdc_pci_driver) < 0) + { + OSAL_MDC_ERR("Cannot find PCI device\n"); + rc = CLX_E_OTHERS; + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_removePciDevice(void) +{ + pci_unregister_driver(&_osal_mdc_pci_driver); + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_tunePciPerf( + const UI32_T unit) +{ + struct pci_dev *ptr_ep_dev = _osal_mdc_cb.dev[unit].ptr_pci_dev; + struct pci_dev *ptr_rc_dev = ptr_ep_dev->bus->self; + int ext_cap = 0; + UI32_T data_32 = 0; + UI16_T data_16 = 0; + + ext_cap = pci_find_ext_capability(ptr_rc_dev, 0x19); + if (0 == ext_cap) + { + OSAL_MDC_ERR("Cannot find PCI extended ID 0x19\n"); + return CLX_E_OTHERS; + } + + /* disable response timer */ + osal_mdc_readPciReg(unit, 0x3EE16C, &data_32, sizeof(UI32_T)); +#if defined(CLX_EN_BIG_ENDIAN) + data_32 &= 0x0000FFFF; +#else + data_32 &= 0xFFFF0000; +#endif + osal_mdc_writePciReg(unit, 0x3EE16C, &data_32, sizeof(UI32_T)); + + /* perform */ + pci_read_config_word(ptr_rc_dev, ext_cap + 0x4, &data_16); + data_16 |= 0x1; + pci_write_config_word(ptr_rc_dev, ext_cap + 0x4, data_16); + + /* retrain */ + pci_read_config_word(ptr_rc_dev, ptr_rc_dev->pcie_cap + 0x10, &data_16); + data_16 |= 0x20; + pci_write_config_word(ptr_rc_dev, ptr_rc_dev->pcie_cap + 0x10, data_16); + + msleep(100); + + /* clear */ + pci_read_config_word(ptr_rc_dev, ext_cap + 0x4, &data_16); + data_16 &= ~0x1; + pci_write_config_word(ptr_rc_dev, ext_cap + 0x4, data_16); + + return CLX_E_OK; +} + +static CLX_ERROR_NO_T +_osal_mdc_maskStatus( + const UI32_T unit) +{ + struct pci_dev *ptr_ep_dev = _osal_mdc_cb.dev[unit].ptr_pci_dev; + struct pci_dev *ptr_rc_dev = ptr_ep_dev->bus->self; + int ext_cap = 0; + UI32_T data_32 = 0; + + ext_cap = pci_find_ext_capability(ptr_rc_dev, 0x1); + if (0 != ext_cap) + { + /* Mask */ + pci_read_config_dword(ptr_rc_dev, ext_cap + 0x8, &data_32); + data_32 |= 0x20; + pci_write_config_dword(ptr_rc_dev, ext_cap + 0x8, data_32); + } + + return CLX_E_OK; +} + +static CLX_ERROR_NO_T +_osal_mdc_clearStatus( + const UI32_T unit) +{ + struct pci_dev *ptr_ep_dev = _osal_mdc_cb.dev[unit].ptr_pci_dev; + struct pci_dev *ptr_rc_dev = ptr_ep_dev->bus->self; + int ext_cap = 0; + UI32_T data_32 = 0; + + ext_cap = pci_find_ext_capability(ptr_rc_dev, 0x1); + if (0 != ext_cap) + { + /* Clear */ + pci_write_config_word(ptr_rc_dev, ptr_rc_dev->pcie_cap + 0xa, 0x04); + pci_write_config_word(ptr_rc_dev, ptr_rc_dev->pcie_cap + 0x12, 0x8000); + pci_write_config_dword(ptr_rc_dev, ext_cap + 0x4, 0x20); + + /* UnMask */ + pci_read_config_dword(ptr_rc_dev, ext_cap + 0x8, &data_32); + data_32 &= ~0x20; + pci_write_config_dword(ptr_rc_dev, ext_cap + 0x8, data_32); + } + + return CLX_E_OK; +} + +static CLX_ERROR_NO_T +_osal_mdc_savePciConfig( + const UI32_T unit) +{ + struct pci_dev *ptr_dev = _osal_mdc_cb.dev[unit].ptr_pci_dev; + CLX_ERROR_NO_T rc = CLX_E_OK; + + rc = _osal_mdc_maskStatus(unit); + + if (CLX_E_OK == rc) + { + pci_save_state(ptr_dev); + } + + return rc; +} + +static CLX_ERROR_NO_T +_osal_mdc_restorePciConfig( + const UI32_T unit) +{ +#define OSAL_MDC_PCI_PRESENT_POLL_CNT (100) +#define OSAL_MDC_PCI_PRESENT_POLL_INTERVAL (10) /* ms */ + + struct pci_dev *ptr_dev = _osal_mdc_cb.dev[unit].ptr_pci_dev; + UI32_T poll_cnt = 0; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* standard: at least 100ms for link recovery */ + msleep(100); + + /* make sure pci device is there before restoring the config space */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + while ((0 == pci_device_is_present(ptr_dev)) && +#else + while ((0 == pci_dev_present(_osal_mdc_id_table)) && +#endif + (poll_cnt < OSAL_MDC_PCI_PRESENT_POLL_CNT)) + { + msleep(OSAL_MDC_PCI_PRESENT_POLL_INTERVAL); + poll_cnt++; + } + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) + if (1 == pci_device_is_present(ptr_dev)) +#else + if (1 == pci_dev_present(_osal_mdc_id_table)) +#endif + { + pci_restore_state(ptr_dev); + rc = CLX_E_OK; + } + else + { + OSAL_MDC_ERR("detect pci device failed\n"); + rc = CLX_E_OTHERS; + } + + if (CLX_E_OK == rc) + { + rc = _osal_mdc_clearStatus(unit); + } + + if (CLX_E_OK == rc) + { + if (HAL_DEVICE_ID_CL8500 == (ptr_dev->device & 0xFF00)) + { + rc = _osal_mdc_tunePciPerf(unit); + } + } + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_tunePciDevice( + AML_DEV_T *ptr_dev, + const UI32_T dev_num) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T idx = 0; + + for (idx = 0; (idx < dev_num) && (CLX_E_OK == rc); idx++) + { + if (HAL_DEVICE_ID_CL8500 == (ptr_dev[idx].id.device & 0xFF00)) + { + rc = _osal_mdc_tunePciPerf(idx); + } + } + + return rc; +} + +#endif /* End of AML_EN_I2C */ + +/* --------------------------------------------------------------------------- DMA */ +#if defined(CLX_LINUX_KERNEL_MODE) + +static CLX_ERROR_NO_T +_osal_mdc_searchDmaVirtAddr( + OSAL_MDC_LIST_T *ptr_dma_list, + const void *ptr_virt_addr, + OSAL_MDC_LIST_NODE_T **pptr_node, + OSAL_MDC_DMA_NODE_T **pptr_node_data) +{ + OSAL_MDC_LIST_NODE_T *ptr_curr_node; + OSAL_MDC_DMA_NODE_T *ptr_curr_node_data; + CLX_ERROR_NO_T rc; + + rc = osal_mdc_list_locateHead(ptr_dma_list, &ptr_curr_node); + while (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_curr_node, (void **)&ptr_curr_node_data); + if (CLX_E_OK == rc) + { + if (ptr_curr_node_data->ptr_virt_addr == ptr_virt_addr) + { + *pptr_node = ptr_curr_node; + *pptr_node_data = ptr_curr_node_data; + break; + } + rc = osal_mdc_list_next(ptr_dma_list, ptr_curr_node, &ptr_curr_node); + } + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_destroyDmaNodeList( + OSAL_MDC_DMA_INFO_T *ptr_dma_info) +{ + OSAL_MDC_LIST_T *ptr_dma_list = ptr_dma_info->ptr_dma_list; + OSAL_MDC_LIST_NODE_T *ptr_curr_node = NULL; + OSAL_MDC_DMA_NODE_T *ptr_curr_node_data = NULL; + CLX_ERROR_NO_T rc = CLX_E_NOT_INITED; + + if (NULL != ptr_dma_list) + { + rc = osal_mdc_list_locateHead(ptr_dma_list, &ptr_curr_node); + while (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_curr_node, (void **)&ptr_curr_node_data); + if ((CLX_E_OK == rc) && (NULL != ptr_curr_node_data)) + { + rc = osal_mdc_list_deleteByData(ptr_dma_list, ptr_curr_node_data); + if (CLX_E_OK == rc) + { + kfree(ptr_curr_node_data); + } + } + rc = osal_mdc_list_locateHead(ptr_dma_list, &ptr_curr_node); + } + rc = osal_mdc_list_destroy(ptr_dma_list, NULL); + if (CLX_E_OK == rc) + { + ptr_dma_info->ptr_dma_list = NULL; + } + } + return (rc); +} + +#endif /* End of CLX_LINUX_KERNEL_MODE */ + +#if defined(CLX_EN_DMA_RESERVED) + +#if defined(CLX_LINUX_KERNEL_MODE) + +#if defined(OSAL_MDC_EN_TEST) +static CLX_ERROR_NO_T +_osal_mdc_dumpRsrvDmaList(void) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + OSAL_MDC_LIST_NODE_T *ptr_curr_node; + OSAL_MDC_DMA_NODE_T *ptr_curr_node_data; + UI32_T node = 0; + CLX_ERROR_NO_T rc = CLX_E_OK; + + rc = osal_mdc_list_locateHead(ptr_dma_info->ptr_dma_list, + &ptr_curr_node); + while (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_info->ptr_dma_list, + ptr_curr_node, (void **)&ptr_curr_node_data); + if (CLX_E_OK == rc) + { + OSAL_MDC_ERR( + "node %d. virt addr=%p, phy addr=%p, size=%d, avbl=%d\n", node, + ptr_curr_node_data->ptr_virt_addr, ptr_curr_node_data->phy_addr, + ptr_curr_node_data->size, ptr_curr_node_data->available); + } + rc = osal_mdc_list_next(ptr_dma_info->ptr_dma_list, + ptr_curr_node, &ptr_curr_node); + node++; + } + return (rc); +} +#endif + +static CLX_ERROR_NO_T +_osal_mdc_createRsrvDmaNodeList( + OSAL_MDC_DMA_INFO_T *ptr_dma_info) +{ + OSAL_MDC_DMA_NODE_T *ptr_node_data; + CLX_ERROR_NO_T rc; + + rc = osal_mdc_list_create(OSAL_MDC_DMA_LIST_SZ_UNLIMITED, + OSAL_MDC_LIST_TYPE_DOUBLE, + OSAL_MDC_DMA_LIST_NAME, + &ptr_dma_info->ptr_dma_list); + if (CLX_E_OK == rc) + { + /* The first node, which contains all of the reserved memory */ + ptr_node_data = kmalloc(sizeof(OSAL_MDC_DMA_NODE_T), GFP_KERNEL); + if (NULL != ptr_node_data) + { + ptr_node_data->ptr_virt_addr = ptr_dma_info->ptr_rsrv_virt_addr; + ptr_node_data->phy_addr = ptr_dma_info->rsrv_phy_addr; + ptr_node_data->size = ptr_dma_info->rsrv_size; + ptr_node_data->available = TRUE; + rc = osal_mdc_list_insertToHead(ptr_dma_info->ptr_dma_list, ptr_node_data); + } + else + { + rc = CLX_E_NO_MEMORY; + } + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_searchAvblRsrvDmaNode( + OSAL_MDC_LIST_T *ptr_dma_list, + const UI32_T size, + OSAL_MDC_LIST_NODE_T **pptr_avbl_node) +{ + OSAL_MDC_LIST_NODE_T *ptr_curr_node; + OSAL_MDC_DMA_NODE_T *ptr_curr_node_data; + CLX_ERROR_NO_T rc; + + rc = osal_mdc_list_locateHead(ptr_dma_list, &ptr_curr_node); + while (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_curr_node, (void **)&ptr_curr_node_data); + if (CLX_E_OK == rc) + { + if ((TRUE == ptr_curr_node_data->available) && (ptr_curr_node_data->size >= size)) + { + *pptr_avbl_node = ptr_curr_node; + break; + } + } + rc = osal_mdc_list_next(ptr_dma_list, ptr_curr_node, &ptr_curr_node); + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_splitRsrvDmaNodes( + OSAL_MDC_LIST_T *ptr_dma_list, + OSAL_MDC_LIST_NODE_T *ptr_ori_node, + const UI32_T size, + OSAL_MDC_DMA_NODE_T **pptr_new_node_data) +{ + OSAL_MDC_DMA_NODE_T *ptr_ori_node_data; + CLX_ERROR_NO_T rc; + + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_ori_node, (void **)&ptr_ori_node_data); + + if (CLX_E_OK == rc) + { + *pptr_new_node_data = kmalloc(sizeof(OSAL_MDC_DMA_NODE_T), GFP_KERNEL); + + /* Create a new node */ + (*pptr_new_node_data)->size = size; + (*pptr_new_node_data)->phy_addr = ptr_ori_node_data->phy_addr; + (*pptr_new_node_data)->ptr_virt_addr = ptr_ori_node_data->ptr_virt_addr; + (*pptr_new_node_data)->available = TRUE; + + /* Update the original node */ + ptr_ori_node_data->size -= size; + ptr_ori_node_data->phy_addr += size; + ptr_ori_node_data->ptr_virt_addr = + (void *)((CLX_HUGE_T)ptr_ori_node_data->ptr_virt_addr + (CLX_HUGE_T)size); + + rc = osal_mdc_list_insertBefore(ptr_dma_list, ptr_ori_node, (void *)*pptr_new_node_data); + if (CLX_E_OK != rc) + { + OSAL_MDC_ERR("insert rsrv dma node to list failed, size=%d, rc=%d\n", size, rc); + /* Recovery */ + ptr_ori_node_data->size += size; + ptr_ori_node_data->phy_addr -= size; + ptr_ori_node_data->ptr_virt_addr = + (void *)((CLX_HUGE_T)ptr_ori_node_data->ptr_virt_addr - (CLX_HUGE_T)size); + kfree(*pptr_new_node_data); + } + } + return (rc); +} + +static void * +_osal_mdc_allocRsrvDmaMem( + OSAL_MDC_DMA_INFO_T *ptr_dma_info, + const UI32_T size) +{ + OSAL_MDC_LIST_T *ptr_dma_list = ptr_dma_info->ptr_dma_list; + OSAL_MDC_LIST_NODE_T *ptr_node = NULL; + OSAL_MDC_DMA_NODE_T *ptr_node_data; + OSAL_MDC_DMA_NODE_T *ptr_new_node_data; + void *ptr_virt_addr = NULL; + CLX_ERROR_NO_T rc; + + rc = _osal_mdc_searchAvblRsrvDmaNode(ptr_dma_list, size, &ptr_node); + if (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_node, (void **)&ptr_node_data); + if (CLX_E_OK == rc) + { + /* If the node size just fit the user's requirement, just give it to user */ + if (ptr_node_data->size == size) + { + ptr_node_data->available = FALSE; + ptr_virt_addr = ptr_node_data->ptr_virt_addr; + } + /* or split a new node with user required size. */ + else + { + rc = _osal_mdc_splitRsrvDmaNodes(ptr_dma_list, ptr_node, size, &ptr_new_node_data); + if (CLX_E_OK == rc) + { + ptr_new_node_data->available = FALSE; + ptr_virt_addr = ptr_new_node_data->ptr_virt_addr; + } + } + } + } + return (ptr_virt_addr); +} + +static CLX_ERROR_NO_T +_osal_mdc_mergeTwoRsrvDmaNodes( + OSAL_MDC_LIST_T *ptr_dma_list, + OSAL_MDC_DMA_NODE_T *ptr_first_node_data, + OSAL_MDC_DMA_NODE_T *ptr_second_node_data) +{ + ptr_first_node_data->size += ptr_second_node_data->size; + + osal_mdc_list_deleteByData(ptr_dma_list, ptr_second_node_data); + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_mergeRsrvDmaNodes( + OSAL_MDC_LIST_T *ptr_dma_list, + OSAL_MDC_LIST_NODE_T *ptr_curr_node) +{ + OSAL_MDC_LIST_NODE_T *ptr_prev_node; + OSAL_MDC_LIST_NODE_T *ptr_next_node; + OSAL_MDC_DMA_NODE_T *ptr_curr_node_data; + OSAL_MDC_DMA_NODE_T *ptr_prev_node_data; + OSAL_MDC_DMA_NODE_T *ptr_next_node_data; + CLX_ERROR_NO_T rc; + + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_curr_node, (void **)&ptr_curr_node_data); + if (CLX_E_OK == rc) + { + /* First, check if the previous node is available */ + rc = osal_mdc_list_prev(ptr_dma_list, ptr_curr_node, &ptr_prev_node); + if (CLX_E_OK == rc) + { + osal_mdc_list_getNodeData(ptr_dma_list, ptr_prev_node, (void **)&ptr_prev_node_data); + if (TRUE == ptr_prev_node_data->available) + { + _osal_mdc_mergeTwoRsrvDmaNodes(ptr_dma_list, ptr_prev_node_data, ptr_curr_node_data); + ptr_curr_node = ptr_prev_node; + ptr_curr_node_data = ptr_prev_node_data; + } + } + + /* then, check if the next node is available */ + rc = osal_mdc_list_next(ptr_dma_list, ptr_curr_node, &ptr_next_node); + if (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_list, ptr_next_node, (void **)&ptr_next_node_data); + if (CLX_E_OK == rc) + { + if (TRUE == ptr_next_node_data->available) + { + _osal_mdc_mergeTwoRsrvDmaNodes(ptr_dma_list, ptr_curr_node_data, ptr_next_node_data); + } + } + } + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_freeRsrvDmaMem( + OSAL_MDC_DMA_INFO_T *ptr_dma_info, + void *ptr_virt_addr) +{ + OSAL_MDC_LIST_T *ptr_dma_list = ptr_dma_info->ptr_dma_list; + OSAL_MDC_LIST_NODE_T *ptr_node = NULL; + OSAL_MDC_DMA_NODE_T *ptr_node_data = NULL; + CLX_ERROR_NO_T rc; + + rc = _osal_mdc_searchDmaVirtAddr(ptr_dma_list, ptr_virt_addr, &ptr_node, &ptr_node_data); + if (CLX_E_OK == rc) + { + ptr_node_data->available = TRUE; + _osal_mdc_mergeRsrvDmaNodes(ptr_dma_list, ptr_node); + } + return (rc); +} + +#endif /* End of CLX_LINUX_KERNEL_MODE */ + +static CLX_ERROR_NO_T +_osal_mdc_initRsrvDmaMem( + OSAL_MDC_DMA_INFO_T *ptr_dma_info) +{ + struct resource *ptr_res; + CLX_ERROR_NO_T rc = CLX_E_OK; + + ptr_dma_info->rsrv_size = (CLX_ADDR_T)CLX_DMA_RESERVED_SZ * 1024 * 1024; + ptr_dma_info->rsrv_phy_addr = (CLX_ADDR_T)CLX_OS_MEMORY_SZ * 1024 * 1024; + ptr_res = request_mem_region(ptr_dma_info->rsrv_phy_addr, + ptr_dma_info->rsrv_size, "clx_rsrv_mem"); + if (NULL != ptr_res) + { + ptr_dma_info->ptr_rsrv_virt_addr = IOREMAP_API(ptr_dma_info->rsrv_phy_addr, + ptr_dma_info->rsrv_size); + if (NULL == ptr_dma_info->ptr_rsrv_virt_addr) + { + OSAL_MDC_ERR( + "IOREMAP_API() failed, phy addr=" CLX_ADDR_PRINT ", size=" CLX_ADDR_PRINT "\n", + ptr_dma_info->rsrv_phy_addr, ptr_dma_info->rsrv_size); + + rc = CLX_E_OTHERS; + } + } + else + { + OSAL_MDC_ERR( + "request_mem_region() failed, phy addr=" CLX_ADDR_PRINT ", size=" CLX_ADDR_PRINT "\n", + ptr_dma_info->rsrv_phy_addr, ptr_dma_info->rsrv_size); + + rc = CLX_E_OTHERS; + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_deinitRsrvDmaMem( + OSAL_MDC_DMA_INFO_T *ptr_dma_info) +{ + if (NULL != ptr_dma_info->ptr_rsrv_virt_addr) + { + iounmap(ptr_dma_info->ptr_rsrv_virt_addr); + } + if (0x0 != ptr_dma_info->rsrv_phy_addr) + { + release_mem_region(ptr_dma_info->rsrv_phy_addr, + ptr_dma_info->rsrv_size); + } + return (CLX_E_OK); +} + + +#else /* Else of CLX_EN_DMA_RESERVED */ + + +#if defined(CLX_LINUX_KERNEL_MODE) + +#if defined(OSAL_MDC_EN_TEST) +static CLX_ERROR_NO_T +_osal_mdc_dumpSysDmaList(void) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + OSAL_MDC_LIST_NODE_T *ptr_curr_node; + OSAL_MDC_DMA_NODE_T *ptr_curr_node_data; + UI32_T node = 0; + CLX_ERROR_NO_T rc = CLX_E_OK; + + rc = osal_mdc_list_locateHead(ptr_dma_info->ptr_dma_list, + &ptr_curr_node); + while (CLX_E_OK == rc) + { + rc = osal_mdc_list_getNodeData(ptr_dma_info->ptr_dma_list, + ptr_curr_node, (void **)&ptr_curr_node_data); + if (CLX_E_OK == rc) + { + OSAL_MDC_ERR( + "node %d. virt addr=%p, phy addr=%p, size=%d\n", node, + ptr_curr_node_data->ptr_virt_addr, ptr_curr_node_data->phy_addr, + ptr_curr_node_data->size); + } + + rc = osal_mdc_list_next(ptr_dma_info->ptr_dma_list, + ptr_curr_node, &ptr_curr_node); + node++; + + } + return (rc); +} +#endif + +static CLX_ERROR_NO_T +_osal_mdc_createSysDmaNodeList( + OSAL_MDC_DMA_INFO_T *ptr_dma_info) +{ + CLX_ERROR_NO_T rc; + + rc = osal_mdc_list_create(OSAL_MDC_DMA_LIST_SZ_UNLIMITED, + OSAL_MDC_LIST_TYPE_SINGLY, + OSAL_MDC_DMA_LIST_NAME, + &ptr_dma_info->ptr_dma_list); + return (rc); +} +#if !defined(CLX_LAMP) + +static void * +_osal_mdc_allocSysDmaMem( + OSAL_MDC_DMA_INFO_T *ptr_dma_info, + const UI32_T size) +{ + dma_addr_t phy_addr; + OSAL_MDC_DMA_NODE_T *ptr_node_data; + void *ptr_virt_addr = NULL; + CLX_ERROR_NO_T rc = CLX_E_OK; + + ptr_virt_addr = dma_alloc_coherent(ptr_dma_info->ptr_dma_dev, size, &phy_addr, GFP_ATOMIC); + if (NULL != ptr_virt_addr) + { + ptr_node_data = kmalloc(sizeof(OSAL_MDC_DMA_NODE_T), GFP_KERNEL); + ptr_node_data->phy_addr = (CLX_ADDR_T)phy_addr; + ptr_node_data->ptr_virt_addr = ptr_virt_addr; + ptr_node_data->size = size; + + rc = osal_mdc_list_insertToHead(ptr_dma_info->ptr_dma_list, ptr_node_data); + if (CLX_E_OK != rc) + { + kfree(ptr_node_data); + dma_free_coherent(ptr_dma_info->ptr_dma_dev, size, + ptr_virt_addr, phy_addr); + ptr_virt_addr = NULL; + } + } + return (ptr_virt_addr); +} + +static CLX_ERROR_NO_T +_osal_mdc_freeSysDmaMem( + OSAL_MDC_DMA_INFO_T *ptr_dma_info, + void *ptr_virt_addr) +{ + OSAL_MDC_LIST_NODE_T *ptr_node = NULL; + OSAL_MDC_DMA_NODE_T *ptr_node_data = NULL; + CLX_ERROR_NO_T rc; + + rc = _osal_mdc_searchDmaVirtAddr(ptr_dma_info->ptr_dma_list, ptr_virt_addr, &ptr_node, &ptr_node_data); + if (CLX_E_OK == rc) + { + dma_free_coherent(ptr_dma_info->ptr_dma_dev, ptr_node_data->size, + ptr_virt_addr, ptr_node_data->phy_addr); + + osal_mdc_list_deleteByData(ptr_dma_info->ptr_dma_list, ptr_node_data); + kfree(ptr_node_data); + } + return (rc); +} +#endif +#endif /* End of CLX_LINUX_KERNEL_MODE */ + +#endif /* End of CLX_EN_DMA_RESERVED */ + +#if defined(CLX_LINUX_KERNEL_MODE) + +void * +osal_mdc_allocDmaMem( + const UI32_T size) +{ + void *ptr_virt_addr = NULL; + +#if defined(CLX_LAMP) + ptr_virt_addr = osal_alloc(size); +#else + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + osal_takeSemaphore(&ptr_dma_info->sema, CLX_SEMAPHORE_WAIT_FOREVER); + +#if defined(CLX_EN_DMA_RESERVED) + ptr_virt_addr = _osal_mdc_allocRsrvDmaMem(ptr_dma_info, size); +#else + ptr_virt_addr = _osal_mdc_allocSysDmaMem(ptr_dma_info, size); +#endif + + osal_giveSemaphore(&ptr_dma_info->sema); +#endif + + return ptr_virt_addr; +} + +CLX_ERROR_NO_T +osal_mdc_freeDmaMem( + void *ptr_virt_addr) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + +#if defined(CLX_LAMP) + osal_free(ptr_virt_addr); +#else + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + + osal_takeSemaphore(&ptr_dma_info->sema, CLX_SEMAPHORE_WAIT_FOREVER); + +#if defined(CLX_EN_DMA_RESERVED) + rc = _osal_mdc_freeRsrvDmaMem(ptr_dma_info, ptr_virt_addr); +#else + + rc = _osal_mdc_freeSysDmaMem(ptr_dma_info, ptr_virt_addr); +#endif + osal_giveSemaphore(&ptr_dma_info->sema); + + if (CLX_E_OK != rc) + { + OSAL_MDC_ERR("free dma mem failed, virt addr=%p\n", ptr_virt_addr); + } +#endif + + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_convertPhyToVirt( + const CLX_ADDR_T phy_addr, + void **pptr_virt_addr) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + +#if defined(CLX_EN_DMA_RESERVED) + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + CLX_HUGE_T rsrv_virt_base = (CLX_HUGE_T)ptr_dma_info->ptr_rsrv_virt_addr; + CLX_ADDR_T rsrv_phy_base = ptr_dma_info->rsrv_phy_addr; +#endif + +#if defined(CLX_EN_DMA_RESERVED) + *pptr_virt_addr = (void *)(rsrv_virt_base + (CLX_HUGE_T)(phy_addr - rsrv_phy_base)); +#else + *pptr_virt_addr = NULL; + *pptr_virt_addr = phys_to_virt(phy_addr); + rc = (NULL == *pptr_virt_addr) ? (CLX_E_ENTRY_NOT_FOUND) : (CLX_E_OK); +#endif + +#if defined(AML_EN_CUSTOM_DMA_ADDR) + if (CLX_E_OK != rc) + { + /* Here the user may invoke the API for their private DMA + * address conversion. + */ + } +#endif + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_convertVirtToPhy( + void *ptr_virt_addr, + CLX_ADDR_T *ptr_phy_addr) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + +#if defined(CLX_EN_DMA_RESERVED) + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + CLX_HUGE_T rsrv_virt_base = (CLX_HUGE_T)ptr_dma_info->ptr_rsrv_virt_addr; + CLX_ADDR_T rsrv_phy_base = ptr_dma_info->rsrv_phy_addr; +#endif + +#if defined(CLX_EN_DMA_RESERVED) + *ptr_phy_addr = (CLX_ADDR_T)((CLX_HUGE_T)rsrv_phy_base + + (CLX_HUGE_T)ptr_virt_addr - rsrv_virt_base); +#else + *ptr_phy_addr = 0x0; + *ptr_phy_addr = virt_to_phys(ptr_virt_addr); + rc = (0x0 == *ptr_phy_addr) ? (CLX_E_ENTRY_NOT_FOUND) : (CLX_E_OK); +#endif + +#if defined(AML_EN_CUSTOM_DMA_ADDR) + if (CLX_E_OK != rc) + { + /* Here the user may invoke the API for their private DMA + * address conversion. + */ + } +#endif + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_initDmaMem(void) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + CLX_ERROR_NO_T rc = CLX_E_OK; + + rc = osal_createSemaphore(OSAL_MDC_DMA_SEMAPHORE_NAME, + CLX_SEMAPHORE_BINARY, &ptr_dma_info->sema); + if (CLX_E_OK == rc) + { +#if defined(CLX_EN_DMA_RESERVED) + rc = _osal_mdc_initRsrvDmaMem(ptr_dma_info); + if (CLX_E_OK == rc) + { + rc = _osal_mdc_createRsrvDmaNodeList(ptr_dma_info); + } +#else + rc = _osal_mdc_createSysDmaNodeList(ptr_dma_info); +#endif + } + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_deinitDmaMem(void) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + + /* Common function for both reserved/system memory. */ + _osal_mdc_destroyDmaNodeList(ptr_dma_info); + +#if defined(CLX_EN_DMA_RESERVED) + _osal_mdc_deinitRsrvDmaMem(ptr_dma_info); +#endif + + osal_destroySemaphore(&ptr_dma_info->sema); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_mdc_flushCache( + void *ptr_virt_addr, + const UI32_T size) +{ +#if defined(CONFIG_NOT_COHERENT_CACHE) || defined(CONFIG_DMA_NONCOHERENT) + +#if defined(dma_cache_wback_inv) + dma_cache_wback_inv((CLX_HUGE_T)ptr_virt_addr, size); +#else + dma_cache_sync(NULL, ptr_virt_addr, size, DMA_TO_DEVICE); +#endif + +#endif + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_mdc_invalidateCache( + void *ptr_virt_addr, + const UI32_T size) +{ +#if defined(CONFIG_NOT_COHERENT_CACHE) || defined(CONFIG_DMA_NONCOHERENT) + +#if defined(dma_cache_wback_inv) + dma_cache_wback_inv((CLX_HUGE_T)ptr_virt_addr, size); +#else + dma_cache_sync(NULL, ptr_virt_addr, size, DMA_FROM_DEVICE); +#endif + +#endif + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_mdc_savePciConfig( + const UI32_T unit) +{ + return _osal_mdc_savePciConfig(unit); +} + +CLX_ERROR_NO_T +osal_mdc_restorePciConfig( + const UI32_T unit) +{ + return _osal_mdc_restorePciConfig(unit); +} + +#endif /* End of CLX_LINUX_KERNEL_MODE */ + +/* --------------------------------------------------------------------------- Interrupt */ +#if defined(CLX_LINUX_USER_MODE) +static UI32_T _osal_mdc_isr_init_bitmap = 0; /* To record the dev request_irq */ +static UI32_T _osal_mdc_isr_dev_bitmap; /* To record the dev bitmap */ +static spinlock_t _osal_mdc_isr_dev_bitmap_lock; +static wait_queue_head_t _osal_mdc_isr_wait; +static UI32_T _osal_mdc_isr_mask_addr; +static UI32_T _osal_mdc_isr_mask_val; + + +static inline CLX_ERROR_NO_T +_osal_mdc_initInterrupt(void) +{ + /* init top and bottom halves */ + init_waitqueue_head(&_osal_mdc_isr_wait); + + /* init lock and clear device bitmap */ + spin_lock_init(&_osal_mdc_isr_dev_bitmap_lock); + _osal_mdc_isr_dev_bitmap = 0; + _osal_mdc_isr_init_bitmap = 0; + + /* clear chip interrupt mask address and value */ + _osal_mdc_isr_mask_addr = 0; + _osal_mdc_isr_mask_val = 0; + + return (CLX_E_OK); +} + +/* top half */ +static inline CLX_ERROR_NO_T +_osal_mdc_notifyUserProcess( + const UI32_T unit) +{ + unsigned long flags = 0; + + /* mask chip interrupt */ + osal_mdc_writePciReg(unit, _osal_mdc_isr_mask_addr, + &_osal_mdc_isr_mask_val, sizeof(UI32_T)); + + /* set the device bitmap. */ + spin_lock_irqsave(&_osal_mdc_isr_dev_bitmap_lock, flags); + _osal_mdc_isr_dev_bitmap |= (1U << unit); + spin_unlock_irqrestore(&_osal_mdc_isr_dev_bitmap_lock, flags); + + /* notify user process. */ + wake_up_interruptible(&_osal_mdc_isr_wait); + + return (CLX_E_OK); +} + +static inline CLX_ERROR_NO_T +_osal_mdc_waitEvent( + UI32_T *ptr_dev_bitmap) +{ + unsigned long flags = 0; + + wait_event_interruptible(_osal_mdc_isr_wait, (0 != _osal_mdc_isr_dev_bitmap)); + + /* save and clear the device bitmap. */ + spin_lock_irqsave(&_osal_mdc_isr_dev_bitmap_lock, flags); + *ptr_dev_bitmap = _osal_mdc_isr_dev_bitmap; + _osal_mdc_isr_dev_bitmap = 0; + spin_unlock_irqrestore(&_osal_mdc_isr_dev_bitmap_lock, flags); + + return (CLX_E_OK); +} + +static ssize_t +_osal_mdc_read( + struct file *filep, + char __user *buf, + size_t count, + loff_t *ppos) +{ + ssize_t ret; + UI32_T dev_bitmap = 0; + + if (count != sizeof(UI32_T)) + { + return -EINVAL; + } + + /* check if request_irq is inited. */ + if (0 != _osal_mdc_isr_init_bitmap) + { + _osal_mdc_waitEvent(&dev_bitmap); + } + + /* copy the device bitmap to user process. */ + if (0 != copy_to_user(buf, &dev_bitmap, count)) + { + ret = -EFAULT; + } + else + { + ret = count; + } + + return ret; +} +#endif /* End of CLX_LINUX_USER_MODE */ + +static irqreturn_t +_osal_mdc_systemIntrCallback( + int irq, + void *ptr_cookie) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + int linux_rc = IRQ_HANDLED; + OSAL_MDC_DEV_T *ptr_dev = (OSAL_MDC_DEV_T *)ptr_cookie; + + /* Invoke kernel callback, the callback function exist only in below cases: + * 1. SDK built in kernel mode + * 2. SDK built in user mode, NetIF kernel module is enabled + */ + if (NULL != ptr_dev->isr_callback) + { + rc = ptr_dev->isr_callback(ptr_dev->ptr_isr_data); + if (CLX_E_OK != rc) + { + OSAL_MDC_ERR("handle irq failed, rc=%d\n", rc); + linux_rc = IRQ_NONE; + } + } + +#if defined(CLX_LINUX_USER_MODE) + /* Notify user process */ + rc = _osal_mdc_notifyUserProcess(ptr_dev->unit); + if (CLX_E_OK != rc) + { + OSAL_MDC_ERR("notify intr to usr failed, rc=%d\n", rc); + linux_rc = IRQ_NONE; + } +#endif + + return (linux_rc); +} + +CLX_ERROR_NO_T +osal_mdc_registerIsr( + const UI32_T unit, + AML_DEV_ISR_FUNC_T handler, + void *ptr_cookie) +{ + OSAL_MDC_DEV_T *ptr_dev = &_osal_mdc_cb.dev[unit]; + + ptr_dev->isr_callback = handler; + ptr_dev->ptr_isr_data = (void *)((CLX_HUGE_T)unit); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_mdc_connectIsr( + const UI32_T unit, + AML_DEV_ISR_FUNC_T handler, + AML_DEV_ISR_DATA_T *ptr_cookie) +{ + OSAL_MDC_DEV_T *ptr_dev = &_osal_mdc_cb.dev[unit]; + int linux_rc = 0; + CLX_ERROR_NO_T rc = CLX_E_OK; + +#if defined(CLX_LINUX_USER_MODE) + if (NULL != ptr_cookie) + { + _osal_mdc_isr_mask_addr = ptr_cookie->mask_addr; + _osal_mdc_isr_mask_val = ptr_cookie->mask_val; + } +#endif + + if (NULL == ptr_dev->isr_callback) + { +#if defined(CLX_LINUX_KERNEL_MODE) + /* In user mode, the following database is created in user space. */ + ptr_dev->isr_callback = handler; + ptr_dev->ptr_isr_data = (void *)((CLX_HUGE_T)unit); +#endif + +#if defined(OSAL_MDC_EN_MSI) + /* If "no_msi" flag is set, it means the device doesn't support MSI. */ + if (1 != ptr_dev->ptr_pci_dev->no_msi) + { + linux_rc = pci_enable_msi(ptr_dev->ptr_pci_dev); + if (0 == linux_rc) + { + /* The system gives a new irq number if MSI is enabled sucessfully. */ + ptr_dev->irq = ptr_dev->ptr_pci_dev->irq; + } + else + { + OSAL_MDC_ERR("pci_enable_msi() failed, rc=%d\n", linux_rc); + rc = CLX_E_OTHERS; + } + } +#endif + + linux_rc = request_irq(ptr_dev->irq, _osal_mdc_systemIntrCallback, + 0, OSAL_MDC_DRIVER_NAME, (void *)ptr_dev); + + if (0 != linux_rc) + { + OSAL_MDC_ERR("request_irq() failed, rc=%d\n", linux_rc); + rc = CLX_E_OTHERS; + } + } + else + { + OSAL_MDC_ERR("double req isr err\n"); + rc = CLX_E_OTHERS; + } + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_disconnectIsr( + const UI32_T unit) +{ + OSAL_MDC_DEV_T *ptr_dev = &_osal_mdc_cb.dev[unit]; + + free_irq(ptr_dev->irq, (void *)ptr_dev); + +#if defined(OSAL_MDC_EN_MSI) + /* Must free the irq before disabling MSI */ + pci_disable_msi(ptr_dev->ptr_pci_dev); +#endif + +#if defined(CLX_LINUX_KERNEL_MODE) + ptr_dev->isr_callback = NULL; + ptr_dev->ptr_isr_data = NULL; +#endif + +#if defined(CLX_LINUX_USER_MODE) + _osal_mdc_isr_mask_addr = 0x0; + _osal_mdc_isr_mask_val = 0x0; +#endif + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_mdc_initDevice( + AML_DEV_T *ptr_dev_list, + UI32_T *ptr_dev_num) +{ + OSAL_MDC_CB_T *ptr_cb = &_osal_mdc_cb; + CLX_ERROR_NO_T rc = CLX_E_OK; + + _ptr_osal_mdc_dev = ptr_dev_list; + + memset(ptr_cb, 0x0, sizeof(OSAL_MDC_CB_T)); + +#if defined(AML_EN_I2C) + rc = _osal_mdc_probeI2cDevice(); + *ptr_dev_num = 1; +#else + rc = _osal_mdc_probePciDevice(); + *ptr_dev_num = ptr_cb->dev_num; + + if (CLX_E_OK == rc) + { + rc = _osal_mdc_tunePciDevice(ptr_dev_list, *ptr_dev_num); + } + + _ptr_ext_pci_dev = _osal_mdc_cb.dev[0].ptr_pci_dev; +#endif /* End of AML_EN_I2C */ + + return (rc); +} + +CLX_ERROR_NO_T +osal_mdc_deinitDevice(void) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + +#if defined(AML_EN_I2C) + rc = _osal_mdc_removeI2cDevice(); +#else + if (NULL != _ptr_ext_pci_dev) + { + rc = _osal_mdc_removePciDevice(); + _ptr_ext_pci_dev = NULL; + } +#endif + + return (rc); +} + +/*****************************************************************************/ +#if defined(CLX_LINUX_USER_MODE) +/* Interface */ +static UI32_T _osal_mdc_devInited = 0; + +/* DMA */ +#if defined(CLX_EN_DMA_RESERVED) +static UI32_T _osal_mdc_rsvDmaInited = 0; +#else +static struct list_head _osal_mdc_sysDmaList[2]; /* To avoid memory corruption when cold-boot */ +static UI32_T _osal_mdc_sysCurDmaListIdx = 0; +#endif + +/* IOCTL */ +static OSAL_MDC_IOCTL_CB_T _osal_mdc_ioctl_cb; +static AML_DEV_T _osal_mdc_ioctl_dev[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM] = {}; + +static int +_osal_mdc_open( + struct inode *ptr_inode, + struct file *ptr_file) +{ + return (0); +} + +static int +_osal_mdc_release( + struct inode *ptr_inode, + struct file *ptr_file) +{ + return (0); +} + +static struct vm_operations_struct _osal_mdc_remap_vm_ops = +{ + .open = NULL, + .close = NULL, +}; + +static int +_osal_mdc_mmap( + struct file *filp, + struct vm_area_struct *vma) +{ + size_t size = vma->vm_end - vma->vm_start; + int linux_rc = 0; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(3,0,48) + pgprot_val(vma->vm_page_prot) |= (_PAGE_NO_CACHE | _PAGE_GUARDED); +#else + UI32_T dev_idx; + OSAL_MDC_DEV_T *ptr_dev; + CLX_ADDR_T phy_addr = vma->vm_pgoff << PAGE_SHIFT; + + /* check mmio base phy addr */ + for (dev_idx = 0, ptr_dev = &_osal_mdc_cb.dev[0]; + dev_idx < _osal_mdc_cb.dev_num; + dev_idx++, ptr_dev++) + { + if ((NULL != ptr_dev->ptr_pci_dev) && + (phy_addr == pci_resource_start(ptr_dev->ptr_pci_dev, OSAL_MDC_PCI_BAR0_OFFSET))) + { + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + break; + } + } +#endif + + vma->vm_flags |= VM_IO; + if (io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff, + size, vma->vm_page_prot)) + { + linux_rc = -EAGAIN; + } + vma->vm_ops = &_osal_mdc_remap_vm_ops; + return (linux_rc); +} + +#if defined(CLX_EN_DMA_RESERVED) + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_initRsrvDmaMemCallback( + const UI32_T unit, + void *ptr_data) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + OSAL_MDC_IOCTL_DMA_DATA_T *ptr_ioctl_data = (OSAL_MDC_IOCTL_DMA_DATA_T *)ptr_data; + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (0 == _osal_mdc_rsvDmaInited) + { + rc = _osal_mdc_initRsrvDmaMem(ptr_dma_info); + _osal_mdc_rsvDmaInited = 1; + } + ptr_ioctl_data->rsrv_dma_phy_addr = ptr_dma_info->rsrv_phy_addr; + ptr_ioctl_data->rsrv_dma_size = ptr_dma_info->rsrv_size; + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_deinitRsrvDmaMemCallback( + const UI32_T unit, + void *ptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + rc = _osal_mdc_deinitRsrvDmaMem(&_osal_mdc_cb.dma_info); + _osal_mdc_rsvDmaInited = 0; + + return (rc); +} + +#else + +static CLX_ERROR_NO_T +_osal_mdc_clearSysDmaList( + UI32_T dmaListIdx) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + OSAL_MDC_USER_MODE_DMA_NODE_T *ptr_curr_node_data = NULL; + OSAL_MDC_USER_MODE_DMA_NODE_T *ptr_next_node_data = NULL; + + list_for_each_entry_safe(ptr_curr_node_data, ptr_next_node_data, + &_osal_mdc_sysDmaList[dmaListIdx], list) + { + list_del(&(ptr_curr_node_data->list)); + dma_free_coherent(ptr_dma_info->ptr_dma_dev, + ptr_curr_node_data->size, + phys_to_virt(ptr_curr_node_data->phy_addr), + ptr_curr_node_data->phy_addr); + kfree(ptr_curr_node_data); + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_allocSysDmaMemCallback( + const UI32_T unit, + void *ptr_data) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + OSAL_MDC_IOCTL_DMA_DATA_T *ptr_ioctl_data = (OSAL_MDC_IOCTL_DMA_DATA_T *)ptr_data; + OSAL_MDC_USER_MODE_DMA_NODE_T *ptr_node_data = NULL; + void *virt_addr; + +/* To defense the compatible data type of 32bit and 64bit are not synchronized */ +#if defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) /* Bus addressing is 64-bit */\ +&& !defined(CLX_EN_64BIT_ADDR) /* SDK follows HOST with 32-bit addr*/\ +&& (defined(CLX_EN_HOST_32_BIT_LITTLE_ENDIAN) || defined(CLX_EN_HOST_32_BIT_BIG_ENDIAN))/* HOST is 32-bit */ +#error "The DMA address of OS is 64bit. Please enable CLX_EN_64BIT_ADDR in SDK." +#endif + +#if !defined(CONFIG_ARCH_DMA_ADDR_T_64BIT) && defined(CLX_EN_64BIT_ADDR) +#error "The DMA address of OS is not 64bit. Please disable CLX_EN_64BIT_ADDR in SDK." +#endif + + if (dma_set_mask_and_coherent(ptr_dma_info->ptr_dma_dev, DMA_BIT_MASK(32))) { + dev_err(ptr_dma_info->ptr_dma_dev, "dma_set_mask_and_coherent failed\n"); + } + + ptr_ioctl_data->size = round_up(ptr_ioctl_data->size, PAGE_SIZE); + virt_addr = dma_alloc_coherent(ptr_dma_info->ptr_dma_dev, ptr_ioctl_data->size, + (dma_addr_t *)&ptr_ioctl_data->phy_addr, GFP_KERNEL | GFP_DMA32); + if (virt_addr == NULL) + { + return (CLX_E_NO_MEMORY); + } + + ptr_node_data = kmalloc(sizeof(OSAL_MDC_USER_MODE_DMA_NODE_T), GFP_KERNEL); + if (NULL != ptr_node_data) + { + memset(ptr_node_data, 0, sizeof(OSAL_MDC_USER_MODE_DMA_NODE_T)); + ptr_node_data->phy_addr = ptr_ioctl_data->phy_addr; + ptr_node_data->size = ptr_ioctl_data->size; + list_add(&(ptr_node_data->list), &_osal_mdc_sysDmaList[_osal_mdc_sysCurDmaListIdx]); + ptr_ioctl_data->phy_addr = virt_to_phys(virt_addr); + } + else + { + dma_free_coherent(ptr_dma_info->ptr_dma_dev, ptr_ioctl_data->size, + virt_addr, ptr_ioctl_data->phy_addr); + + return (CLX_E_NO_MEMORY); + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_freeSysDmaMemCallback( + const UI32_T unit, + void *ptr_data) +{ + OSAL_MDC_DMA_INFO_T *ptr_dma_info = &_osal_mdc_cb.dma_info; + OSAL_MDC_IOCTL_DMA_DATA_T *ptr_ioctl_data = (OSAL_MDC_IOCTL_DMA_DATA_T *)ptr_data; + + OSAL_MDC_USER_MODE_DMA_NODE_T *ptr_curr_node_data = NULL; + OSAL_MDC_USER_MODE_DMA_NODE_T *ptr_next_node_data = NULL; + + + list_for_each_entry_safe(ptr_curr_node_data, ptr_next_node_data, + &_osal_mdc_sysDmaList[_osal_mdc_sysCurDmaListIdx], list) + { + if (ptr_curr_node_data->phy_addr == ptr_ioctl_data->phy_addr) + { + list_del(&(ptr_curr_node_data->list)); + kfree(ptr_curr_node_data); + break; + } + } + + dma_free_coherent(ptr_dma_info->ptr_dma_dev, ptr_ioctl_data->size, + phys_to_virt(ptr_ioctl_data->phy_addr), ptr_ioctl_data->phy_addr); + + return (CLX_E_OK); +} + +#endif + +static CLX_ERROR_NO_T +_osal_mdc_getPciInfoToIoctlData( + const OSAL_MDC_DEV_T *ptr_dev_list, + OSAL_MDC_IOCTL_DEV_DATA_T *ptr_dev_data) +{ + UI32_T idx; + + /* Search for PCIe device and get the MMIO base address. */ + for (idx = 0; idx < _osal_mdc_cb.dev_num; idx++) + { + if (NULL != ptr_dev_list[idx].ptr_pci_dev) + { + ptr_dev_data->pci_mmio_phy_start[idx] = + pci_resource_start(ptr_dev_list[idx].ptr_pci_dev, OSAL_MDC_PCI_BAR0_OFFSET); + + ptr_dev_data->pci_mmio_size[idx] = + pci_resource_len(ptr_dev_list[idx].ptr_pci_dev, OSAL_MDC_PCI_BAR0_OFFSET); + } + } + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_getDeviceIdToIoctlData( + AML_DEV_T *ptr_dev, + OSAL_MDC_IOCTL_DEV_DATA_T *ptr_dev_data, + const UI32_T dev_num) +{ + UI32_T idx; + + for (idx = 0; idx < ptr_dev_data->dev_num; idx++) + { + ptr_dev_data->id[idx].device = ptr_dev[idx].id.device; + ptr_dev_data->id[idx].vendor = ptr_dev[idx].id.vendor; + ptr_dev_data->id[idx].revision = ptr_dev[idx].id.revision; + } + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_initDeviceCallback( + const UI32_T unit, + void *ptr_data) +{ + OSAL_MDC_CB_T *ptr_cb = &_osal_mdc_cb; + OSAL_MDC_DEV_T *ptr_dev_list = _osal_mdc_cb.dev; + OSAL_MDC_IOCTL_DEV_DATA_T *ptr_ioctl_data = (OSAL_MDC_IOCTL_DEV_DATA_T *)ptr_data; + + /* "dev" is just created for invoking osal_mdc_initDevice, + * it is no use once the device IDs are copy to ptr_ioctl_data. + */ + + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (0 == _osal_mdc_devInited) + { + rc = osal_mdc_initDevice(_osal_mdc_ioctl_dev, &ptr_ioctl_data->dev_num); + } + else + { + /* ptr_cb->dev_num was initialized in osal_mdc_initDevice(); */ + ptr_ioctl_data->dev_num = ptr_cb->dev_num; + } + + if (ptr_cb->dev_num >= CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM) + { + OSAL_MDC_ERR("dev num=%d > max support num=%d\n", + ptr_ioctl_data->dev_num, CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM); + } + +#if !defined(CLX_EN_DMA_RESERVED) + if (0 == _osal_mdc_devInited) + { + /* Create two DMA memory lists and use 1st. */ + INIT_LIST_HEAD(&_osal_mdc_sysDmaList[0]); + INIT_LIST_HEAD(&_osal_mdc_sysDmaList[1]); + _osal_mdc_sysCurDmaListIdx = 0; + } + else + { + /* Delay free the old list until the chip is reset. + * When we kill the process, the chip continues to write to the DMA memory. + * If we free the old DMA memory before stopping the chip, there could be memory corruption. + */ + _osal_mdc_sysCurDmaListIdx = ((_osal_mdc_sysCurDmaListIdx + 1) & 0x1); + rc = _osal_mdc_clearSysDmaList(_osal_mdc_sysCurDmaListIdx); + } +#endif + + if (CLX_E_OK == rc) + { + rc = _osal_mdc_getDeviceIdToIoctlData(_osal_mdc_ioctl_dev, ptr_ioctl_data, ptr_ioctl_data->dev_num); + } + if (CLX_E_OK == rc) + { + rc = _osal_mdc_getPciInfoToIoctlData(ptr_dev_list, ptr_ioctl_data); + } + + _osal_mdc_devInited = 1; + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_deinitDeviceCallback( + const UI32_T unit, + void *ptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + +#if !defined(CLX_EN_DMA_RESERVED) + _osal_mdc_clearSysDmaList(0); + _osal_mdc_clearSysDmaList(1); +#endif + + if (0 != _osal_mdc_devInited) + { + rc = osal_mdc_deinitDevice(); + _osal_mdc_devInited = 0; + } + + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_connectIsrCallback( + const UI32_T unit, + void *ptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (0 == (_osal_mdc_isr_init_bitmap & (1U << unit))) + { + rc = osal_mdc_connectIsr(unit, NULL, ptr_data); + if (CLX_E_OK == rc) + { + _osal_mdc_isr_init_bitmap |= (1U << unit); + } + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_disconnectIsrCallback( + const UI32_T unit, + void *ptr_data) +{ + /* To make the user-space polling task return from read. */ + _osal_mdc_notifyUserProcess(unit); + + osal_mdc_disconnectIsr(unit); + _osal_mdc_isr_init_bitmap &= ~(1U << unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_savePciConfigCallback( + const UI32_T unit, + void *ptr_data) +{ + return _osal_mdc_savePciConfig(unit); +} + +static CLX_ERROR_NO_T +_osal_mdc_ioctl_restorePciConfigCallback( + const UI32_T unit, + void *ptr_data) +{ + return _osal_mdc_restorePciConfig(unit); +} + +static CLX_ERROR_NO_T +_osal_mdc_registerIoctlCallback( + const OSAL_MDC_IOCTL_TYPE_T type, + const OSAL_MDC_IOCTL_CALLBACK_FUNC_T func) +{ + OSAL_MDC_IOCTL_CB_T *ptr_cb = &_osal_mdc_ioctl_cb; + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + + if (type < OSAL_MDC_IOCTL_TYPE_LAST) + { + if (NULL == ptr_cb->callback[type]) + { + ptr_cb->callback[type] = func; + rc = CLX_E_OK; + } + else + { + OSAL_MDC_ERR("register ioctl callback failed, type=%d exist\n", type); + } + } + else + { + OSAL_MDC_ERR("register ioctl callback failed, type=%d >= max=%d\n", + type, OSAL_MDC_IOCTL_TYPE_LAST); + } + return (rc); +} + +static CLX_ERROR_NO_T +_osal_mdc_initIoctl(void) +{ + memset(&_osal_mdc_ioctl_cb, 0x0, sizeof(OSAL_MDC_IOCTL_CB_T)); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_INIT_DEV, + _osal_mdc_ioctl_initDeviceCallback); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_DEINIT_DEV, + _osal_mdc_ioctl_deinitDeviceCallback); +#if defined(CLX_EN_DMA_RESERVED) + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_INIT_RSRV_DMA_MEM, + _osal_mdc_ioctl_initRsrvDmaMemCallback); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_DEINIT_RSRV_DMA_MEM, + _osal_mdc_ioctl_deinitRsrvDmaMemCallback); +#else + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_ALLOC_SYS_DMA_MEM, + _osal_mdc_ioctl_allocSysDmaMemCallback); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_FREE_SYS_DMA_MEM, + _osal_mdc_ioctl_freeSysDmaMemCallback); +#endif + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_CONNECT_ISR, + _osal_mdc_ioctl_connectIsrCallback); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_DISCONNECT_ISR, + _osal_mdc_ioctl_disconnectIsrCallback); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_SAVE_PCI_CONFIG, + _osal_mdc_ioctl_savePciConfigCallback); + + _osal_mdc_registerIoctlCallback(OSAL_MDC_IOCTL_TYPE_MDC_RESTORE_PCI_CONFIG, + _osal_mdc_ioctl_restorePciConfigCallback); + return (CLX_E_OK); +} + +static long +_osal_mdc_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ +#define OSAL_MDC_IOCTL_LOCAL_BUF_SIZE (128) + + OSAL_MDC_IOCTL_CB_T *ptr_cb = &_osal_mdc_ioctl_cb; + OSAL_MDC_IOCTL_CMD_T *ptr_cmd = (OSAL_MDC_IOCTL_CMD_T *)&cmd; + UI32_T unit = ptr_cmd->field.unit; + OSAL_MDC_IOCTL_TYPE_T type = ptr_cmd->field.type; + OSAL_MDC_IOCTL_ACCESS_T access = ptr_cmd->field.access; + UI32_T data_size = ptr_cmd->field.size; + UI8_T temp_buf[OSAL_MDC_IOCTL_LOCAL_BUF_SIZE]; + UI8_T *ptr_temp_buf; + int linux_rc = 0; + + if (NULL != ptr_cb->callback[type]) + { + if (data_size > OSAL_MDC_IOCTL_LOCAL_BUF_SIZE) + { + ptr_temp_buf = kmalloc(data_size, GFP_KERNEL); + } + else + { + ptr_temp_buf = temp_buf; + } + + /*************************************************************/ + if (OSAL_MDC_IOCTL_ACCESS_WRITE == access) + { + /* type: FREE_SYS_DMA_MEM : DMA physical address + * CONNECT_ISR : Chip interrupt mask address and value + */ + if (copy_from_user(ptr_temp_buf, (int __user *)arg, data_size)) + { + linux_rc = -EFAULT; + } + else + { + if (CLX_E_OK != ptr_cb->callback[type](unit, (void *)ptr_temp_buf)) + { + linux_rc = -EFAULT; + } + } + } + else if (OSAL_MDC_IOCTL_ACCESS_READ == access) + { + /* type: INIT_DEV : PCIe device and vendor ID, mmio address and size + * INIT_RSRV_DMA_MEM : Reserved DMA physical address and size + */ + if (CLX_E_OK != ptr_cb->callback[type](unit, (void *)ptr_temp_buf)) + { + linux_rc = -EFAULT; + } + else + { + if (copy_to_user((int __user *)arg, ptr_temp_buf, data_size)) + { + linux_rc = -EFAULT; + } + } + } + else if (OSAL_MDC_IOCTL_ACCESS_READ_WRITE == access) + { + /* type: ALLOC_SYS_DMA_MEM : DMA physical address + */ + if (copy_from_user(ptr_temp_buf, (int __user *)arg, data_size)) + { + linux_rc = -EFAULT; + } + else + { + if (CLX_E_OK != ptr_cb->callback[type](unit, (void *)ptr_temp_buf)) + { + linux_rc = -EFAULT; + } + else + { + if (copy_to_user((int __user *)arg, ptr_temp_buf, data_size)) + { + linux_rc = -EFAULT; + } + } + } + } + else if (OSAL_MDC_IOCTL_ACCESS_NONE == access) + { + /* type: DEINIT_DEV + * DEINIT_RSRV_DMA_MEM + * DISCONNECT_ISR + * SAVE_PCI_CONFIG + * RESTORE_PCI_CONFIG + */ + if (CLX_E_OK != ptr_cb->callback[type](unit, (void *)ptr_temp_buf)) + { + linux_rc = -EFAULT; + } + } + /*************************************************************/ + + if (data_size > OSAL_MDC_IOCTL_LOCAL_BUF_SIZE) + { + kfree(ptr_temp_buf); + } + } + else + { + OSAL_MDC_ERR("invalid ioctl, cmd=%u, arg=%lu, type=%d\n", cmd, arg, type); + } + return (linux_rc); +} + +#ifdef CONFIG_COMPAT +static long +_osal_mdc_compat_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + return _osal_mdc_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static struct file_operations _osal_mdc_fops = +{ + .owner = THIS_MODULE, + .open = _osal_mdc_open, + .read = _osal_mdc_read, + .release = _osal_mdc_release, + .unlocked_ioctl = _osal_mdc_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = _osal_mdc_compat_ioctl, +#endif + .mmap = _osal_mdc_mmap, +}; + +static struct miscdevice _osal_mdc_misc = +{ + .minor = OSAL_MDC_DRIVER_MISC_MINOR_NUM, + .name = OSAL_MDC_DRIVER_NAME, + .fops = & _osal_mdc_fops, +}; + +static int __init +osal_mdc_module_init(void) +{ + int linux_rc; + + _osal_mdc_initIoctl(); /* To register IOCTL callback functions. */ + _osal_mdc_initInterrupt(); /* To init structs for top and bottom halves */ + + linux_rc = misc_register(&_osal_mdc_misc); + if (0 != linux_rc) + { + OSAL_MDC_ERR("register dev %s failed, linux_rc=%d\n", OSAL_MDC_DRIVER_NAME, linux_rc); + } + return (linux_rc); +} + +static void __exit +osal_mdc_module_exit(void) +{ + int unit = 0; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,2,8) + int linux_rc; + + linux_rc = misc_deregister(&_osal_mdc_misc); + if (0 != linux_rc) + { + OSAL_MDC_ERR("de-register dev %s failed, linux_rc=%d\n", OSAL_MDC_DRIVER_NAME, linux_rc); + } +#else + misc_deregister(&_osal_mdc_misc); +#endif + + /* ref: _osal_mdc_ioctl_disconnectIsrCallback */ + for (unit = 0; unit < CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM; unit++) + { + if (0 != (_osal_mdc_isr_init_bitmap & (1U << unit))) + { + osal_mdc_disconnectIsr(unit); + _osal_mdc_isr_init_bitmap &= ~(1U << unit); + } + } + + /* ref: _osal_mdc_ioctl_deinitRsrvDmaMemCallback */ +#if defined(CLX_EN_DMA_RESERVED) + if (1 == _osal_mdc_rsvDmaInited) + { + _osal_mdc_deinitRsrvDmaMem(&_osal_mdc_cb.dma_info); + _osal_mdc_rsvDmaInited = 0; + } +#endif + + /* ref: _osal_mdc_ioctl_deinitDeviceCallback */ + if (1 == _osal_mdc_devInited) + { +#if !defined(CLX_EN_DMA_RESERVED) + _osal_mdc_clearSysDmaList(0); + _osal_mdc_clearSysDmaList(1); +#endif + osal_mdc_deinitDevice(); + _osal_mdc_devInited = 0; + } +} + +#else + +static int __init +osal_mdc_module_init(void) +{ + return (0); +} + +static void __exit +osal_mdc_module_exit(void) +{ +} + +#endif /* End of CLX_LINUX_USER_MODE */ + +module_init(osal_mdc_module_init); +module_exit(osal_mdc_module_exit); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Clounix"); +MODULE_DESCRIPTION("SDK Kernel Module"); diff --git a/platform/clounix/clounix-modules/modules/src/clx_netif/hal_dawn_pkt_knl.c b/platform/clounix/clounix-modules/modules/src/clx_netif/hal_dawn_pkt_knl.c new file mode 100755 index 000000000000..4a4267ddc257 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_netif/hal_dawn_pkt_knl.c @@ -0,0 +1,6356 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: hal_dawn_pkt_knl.c + * PURPOSE: + * To provide Linux kernel for PDMA TX/RX control. + * + * NOTES: + * + */ + +/***************************************************************************** + * INCLUDE FILE DECLARATIONS + ***************************************************************************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* netif */ +#include +#include +#include + +#include + +/* clx_sdk */ +#include +#include + +/***************************************************************************** + * CHIP DEPENDENT VARIABLES + ***************************************************************************** + */ +/* Interrupt */ +#define HAL_DAWN_PKT_ERR_REG(__unit__) (_hal_dawn_pkt_intr_vec[0].intr_reg) +#define HAL_DAWN_PKT_TCH_REG(__unit__, __channel__) (_hal_dawn_pkt_intr_vec[1 + (__channel__)].intr_reg) +#define HAL_DAWN_PKT_RCH_REG(__unit__, __channel__) (_hal_dawn_pkt_intr_vec[5 + (__channel__)].intr_reg) + +#define HAL_DAWN_PKT_ERR_EVENT(__unit__) (&_hal_dawn_pkt_intr_vec[0].intr_event) +#define HAL_DAWN_PKT_TCH_EVENT(__unit__, __channel__) (&_hal_dawn_pkt_intr_vec[1 + (__channel__)].intr_event) +#define HAL_DAWN_PKT_RCH_EVENT(__unit__, __channel__) (&_hal_dawn_pkt_intr_vec[5 + (__channel__)].intr_event) + +#define HAL_DAWN_PKT_ERR_CNT(__unit__) (_hal_dawn_pkt_intr_vec[0].intr_cnt) +#define HAL_DAWN_PKT_TCH_CNT(__unit__, __channel__) (_hal_dawn_pkt_intr_vec[1 + (__channel__)].intr_cnt) +#define HAL_DAWN_PKT_RCH_CNT(__unit__, __channel__) (_hal_dawn_pkt_intr_vec[5 + (__channel__)].intr_cnt) + + +/* This flag value will be specified when user inserts kernel module. */ +#define HAL_DAWN_PKT_DBG_ERR (0x1UL << 0) +#define HAL_DAWN_PKT_DBG_TX (0x1UL << 1) +#define HAL_DAWN_PKT_DBG_RX (0x1UL << 2) +#define HAL_DAWN_PKT_DBG_INTF (0x1UL << 3) +#define HAL_DAWN_PKT_DBG_PROFILE (0x1UL << 4) +#define HAL_DAWN_PKT_DBG_COMMON (0x1UL << 5) +#define HAL_DAWN_PKT_DBG_NETLINK (0x1UL << 6) + +extern UI32_T ext_dbg_flag; + + +#define HAL_DAWN_PKT_DBG(__flag__, ...) do \ +{ \ + if (0 != ((__flag__) & (ext_dbg_flag))) \ + { \ + osal_printf(__VA_ARGS__); \ + } \ +}while (0) + +typedef struct +{ + UI32_T intr_reg; + CLX_SEMAPHORE_ID_T intr_event; + UI32_T intr_cnt; + +} HAL_DAWN_PKT_INTR_VEC_T; + +typedef struct HAL_DAWN_PKT_PROFILE_NODE_S +{ + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile; + struct HAL_DAWN_PKT_PROFILE_NODE_S *ptr_next_node; + +} HAL_DAWN_PKT_PROFILE_NODE_T; + +typedef struct +{ + HAL_DAWN_PKT_NETIF_INTF_T meta; + struct net_device *ptr_net_dev; + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_profile_list; /* the profiles binding to this interface */ + +} HAL_DAWN_PKT_NETIF_PORT_DB_T; + + +static HAL_DAWN_PKT_INTR_VEC_T _hal_dawn_pkt_intr_vec[] = +{ + { /* 0: PDMA_ERR */ 1UL << 0, 0x0, 0 }, + { /* 1: TX_CH0 */ 1UL << 28, 0x0, 0 }, + { /* 2: TX_CH1 */ 1UL << 29, 0x0, 0 }, + { /* 3: TX_CH2 */ 1UL << 30, 0x0, 0 }, + { /* 4: TX_CH3 */ 1UL << 31, 0x0, 0 }, + { /* 5: RX_CH0 */ 1UL << 12, 0x0, 0 }, + { /* 6: RX_CH1 */ 1UL << 13, 0x0, 0 }, + { /* 7: RX_CH2 */ 1UL << 14, 0x0, 0 }, + { /* 8: RX_CH3 */ 1UL << 15, 0x0, 0 }, +}; + +/***************************************************************************** + * NAMING CONSTANT DECLARATIONS + ***************************************************************************** + */ +/* Sleep Time Definitions */ +#define HAL_DAWN_PKT_TX_DEQUE_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_DAWN_PKT_RX_DEQUE_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_DAWN_PKT_TX_ENQUE_RETRY_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_DAWN_PKT_RX_ENQUE_RETRY_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_DAWN_PKT_ALLOC_MEM_RETRY_SLEEP() osal_sleepThread(1000) /* us */ + +/* Network Device Definitions */ +/* In case that the watchdog alarm during warm-boot if intf isn't killed */ +#define HAL_DAWN_PKT_PORT_NUM (128) + +#define HAL_DAWN_PKT_TX_TIMEOUT (30*HZ) +#define HAL_DAWN_PKT_MAX_ETH_FRAME_SIZE (HAL_DAWN_PKT_RX_MAX_LEN) +#define HAL_DAWN_PKT_MAX_PORT_NUM (HAL_DAWN_PKT_PORT_NUM + 1) /* CPU port */ + +#define HAL_DAWN_PKT_NET_PROFILE_NUM_MAX (256) + +static HAL_DAWN_PKT_NETIF_PROFILE_T *_ptr_hal_dawn_pkt_profile_entry[HAL_DAWN_PKT_NET_PROFILE_NUM_MAX] = {0}; +static HAL_DAWN_PKT_NETIF_PORT_DB_T _hal_dawn_pkt_port_db[HAL_DAWN_PKT_MAX_PORT_NUM]; + +/***************************************************************************** + * MACRO VLAUE DECLARATIONS + ***************************************************************************** + */ + +/***************************************************************************** + * MACRO FUNCTION DECLARATIONS + ***************************************************************************** + */ +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_GET_DRV_CB_PTR(unit) (&_hal_dawn_pkt_drv_cb[unit]) +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_GET_TX_CB_PTR(unit) (&_hal_dawn_pkt_tx_cb[unit]) +#define HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel) (&_hal_dawn_pkt_tx_cb[unit].pdma[channel]) +#define HAL_DAWN_PKT_GET_TX_GPD_PTR(unit, channel, gpd) (&_hal_dawn_pkt_tx_cb[unit].pdma[channel].ptr_gpd_align_start_addr[gpd]) +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_GET_RX_CB_PTR(unit) (&_hal_dawn_pkt_rx_cb[unit]) +#define HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel) (&_hal_dawn_pkt_rx_cb[unit].pdma[channel]) +#define HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, gpd) (&_hal_dawn_pkt_rx_cb[unit].pdma[channel].ptr_gpd_align_start_addr[gpd]) +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_GET_PORT_DB(port) (&_hal_dawn_pkt_port_db[port]) +#define HAL_DAWN_PKT_GET_PORT_PROFILE_LIST(port) (_hal_dawn_pkt_port_db[port].ptr_profile_list) +#define HAL_DAWN_PKT_GET_PORT_NETDEV(port) _hal_dawn_pkt_port_db[port].ptr_net_dev + +/***************************************************************************** + * DATA TYPE DECLARATIONS + ***************************************************************************** + */ +/* ----------------------------------------------------------------------------------- General structure */ +typedef struct +{ + UI32_T unit; + UI32_T channel; + +} HAL_DAWN_PKT_ISR_COOKIE_T; + +typedef struct +{ + CLX_HUGE_T que_id; + CLX_SEMAPHORE_ID_T sema; + UI32_T len; /* Software CPU queue maximum length. */ + UI32_T weight; /* The weight for thread de-queue algorithm. */ + +} HAL_DAWN_PKT_SW_QUEUE_T; + +typedef struct +{ + /* handleErrorTask */ + CLX_THREAD_ID_T err_task_id; + + /* INTR dispatcher */ + CLX_ISRLOCK_ID_T intr_lock; + UI32_T intr_bitmap; + +#define HAL_DAWN_PKT_INIT_DRV (1UL << 0) +#define HAL_DAWN_PKT_INIT_TASK (1UL << 1) +#define HAL_DAWN_PKT_INIT_INTR (1UL << 2) +#define HAL_DAWN_PKT_INIT_RX_START (1UL << 3) + /* a bitmap to record the init status */ + UI32_T init_flag; + +} HAL_DAWN_PKT_DRV_CB_T; + +/* ----------------------------------------------------------------------------------- TX structure */ +typedef struct +{ + /* CLX_SEMAPHORE_ID_T sema; */ + + /* since the Tx GPD ring may be accessed by multiple process including + * ndo_start_xmit (SW IRQ), it must be protected with an ISRLOCK + * instead of the original semaphore + */ + CLX_ISRLOCK_ID_T ring_lock; + + UI32_T used_idx; /* SW send index = LAMP simulate the Tx HW index */ + UI32_T free_idx; /* SW free index */ + UI32_T used_gpd_num; + UI32_T free_gpd_num; + UI32_T gpd_num; + + HAL_DAWN_PKT_TX_GPD_T *ptr_gpd_start_addr; + HAL_DAWN_PKT_TX_GPD_T *ptr_gpd_align_start_addr; + BOOL_T err_flag; + + /* ASYNC */ + HAL_DAWN_PKT_TX_SW_GPD_T **pptr_sw_gpd_ring; + HAL_DAWN_PKT_TX_SW_GPD_T **pptr_sw_gpd_bulk; /* temporary store packets to be enque */ + + /* SYNC_INTR */ + CLX_SEMAPHORE_ID_T sync_intr_sema; + +} HAL_DAWN_PKT_TX_PDMA_T; + +typedef struct +{ + HAL_DAWN_PKT_TX_WAIT_T wait_mode; + HAL_DAWN_PKT_TX_PDMA_T pdma[HAL_DAWN_PKT_TX_CHANNEL_LAST]; + HAL_DAWN_PKT_TX_CNT_T cnt; + + /* handleTxDoneTask */ + CLX_THREAD_ID_T isr_task_id[HAL_DAWN_PKT_TX_CHANNEL_LAST]; + HAL_DAWN_PKT_ISR_COOKIE_T isr_task_cookie[HAL_DAWN_PKT_TX_CHANNEL_LAST]; + + /* txTask */ + HAL_DAWN_PKT_SW_QUEUE_T sw_queue; + CLX_SEMAPHORE_ID_T sync_sema; + CLX_THREAD_ID_T task_id; + BOOL_T running; /* TRUE when Init txTask + * FALSE when Destroy txTask + */ + /* to block net intf Tx in driver level since netif_tx_disable() + * cannot always prevent intf from Tx in time + */ + BOOL_T net_tx_allowed; + +} HAL_DAWN_PKT_TX_CB_T; + +/* ----------------------------------------------------------------------------------- RX structure */ +typedef struct +{ + CLX_SEMAPHORE_ID_T sema; + UI32_T cur_idx; /* SW free index */ + UI32_T gpd_num; + + HAL_DAWN_PKT_RX_GPD_T *ptr_gpd_start_addr; + HAL_DAWN_PKT_RX_GPD_T *ptr_gpd_align_start_addr; + BOOL_T err_flag; + struct sk_buff **pptr_skb_ring; +} HAL_DAWN_PKT_RX_PDMA_T; + +typedef struct +{ + /* Rx system configuration */ + UI32_T buf_len; + + HAL_DAWN_PKT_RX_SCHED_T sched_mode; + HAL_DAWN_PKT_RX_PDMA_T pdma[HAL_DAWN_PKT_RX_CHANNEL_LAST]; + HAL_DAWN_PKT_RX_CNT_T cnt; + + /* handleRxDoneTask */ + CLX_THREAD_ID_T isr_task_id[HAL_DAWN_PKT_RX_CHANNEL_LAST]; + HAL_DAWN_PKT_ISR_COOKIE_T isr_task_cookie[HAL_DAWN_PKT_RX_CHANNEL_LAST]; + + /* rxTask */ + HAL_DAWN_PKT_SW_QUEUE_T sw_queue[HAL_DAWN_PKT_RX_QUEUE_NUM]; + UI32_T deque_idx; + CLX_SEMAPHORE_ID_T sync_sema; + CLX_THREAD_ID_T task_id; + CLX_SEMAPHORE_ID_T deinit_sema; /* To sync-up the Rx-stop and thread flush queues */ + BOOL_T running; /* TRUE when rxStart + * FALSE when rxStop + */ + +} HAL_DAWN_PKT_RX_CB_T; + +/* ----------------------------------------------------------------------------------- Network Device */ +struct net_device_priv +{ + struct net_device *ptr_net_dev; + struct net_device_stats stats; + UI32_T unit; + UI32_T id; + UI32_T port; + UI16_T vlan; + UI32_T speed; +}; + +typedef enum +{ + HAL_DAWN_PKT_DEST_NETDEV = 0, + HAL_DAWN_PKT_DEST_SDK, +#if defined(NETIF_EN_NETLINK) + HAL_DAWN_PKT_DEST_NETLINK, +#endif + HAL_DAWN_PKT_DEST_DROP, + HAL_DAWN_PKT_DEST_LAST +} HAL_DAWN_PKT_DEST_T; + +/***************************************************************************** + * GLOBAL VARIABLE DECLARATIONS + ***************************************************************************** + */ + +/***************************************************************************** + * STATIC VARIABLE DECLARATIONS + ***************************************************************************** + */ +/*---------------------------------------------------------------------------*/ +static HAL_DAWN_PKT_DRV_CB_T _hal_dawn_pkt_drv_cb[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; +static HAL_DAWN_PKT_TX_CB_T _hal_dawn_pkt_tx_cb[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; +static HAL_DAWN_PKT_RX_CB_T _hal_dawn_pkt_rx_cb[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; +/*---------------------------------------------------------------------------*/ + +/***************************************************************************** + * LOCAL SUBPROGRAM DECLARATIONS + ***************************************************************************** + */ +/* ----------------------------------------------------------------------------------- Interrupt */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_enableIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + UI32_T intr_en = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_readPciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + intr_en |= intr_bitmap; + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_disableIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + UI32_T intr_en = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_readPciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + intr_en &= ~intr_bitmap; + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_maskIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_MASK_CLR_HI), &intr_bitmap, sizeof(intr_bitmap)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_unmaskIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_MASK_SET_HI), &intr_bitmap, sizeof(intr_bitmap)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_dispatcher( + void *ptr_cookie) +{ + UI32_T unit = (UI32_T)((CLX_HUGE_T)ptr_cookie); + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + + UI32_T idx = 0, vec = sizeof(_hal_dawn_pkt_intr_vec) / sizeof(HAL_DAWN_PKT_INTR_VEC_T); + UI32_T intr_mask = ptr_cb->intr_bitmap; + UI32_T intr_unmask = 0; + UI32_T intr_status = 0; + + /* MASK, READ and CLEAR PKT IRQs */ + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_MASK_CLR_HI), &intr_mask, sizeof(UI32_T)); + osal_mdc_readPciReg (unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_STAT_HI), &intr_status, sizeof(UI32_T)); + intr_status = intr_status & intr_mask; + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_CLR_HI), &intr_status, sizeof(UI32_T)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + /* Module thread handle and unmask the interrupt */ + intr_unmask = intr_status ^ intr_mask; + if (0x0 != intr_status) + { + for (idx = 0; idx < vec; idx++) + { + if (_hal_dawn_pkt_intr_vec[idx].intr_reg & intr_status) + { + osal_triggerEvent(&_hal_dawn_pkt_intr_vec[idx].intr_event); + _hal_dawn_pkt_intr_vec[idx].intr_cnt++; + } + } + } + + /* UNMASK other PKT IRQs */ + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_CP_COMMON_INT_MASK_SET_HI), &intr_unmask, sizeof(UI32_T)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- RW HW Regs */ +/* FUNCTION NAME: _hal_dawn_pkt_startTxChannelReg + * PURPOSE: + * To issue "START" command to the target TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None. + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_startTxChannelReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_DAWN_PKT_TCH_CMD_REG_T tch_cmd; + + tch_cmd.reg = 0x0; + tch_cmd.field.tch_start = 0x1; + tch_cmd.field.tch_gpd_add_no_lo = gpd_num & 0xff; + tch_cmd.field.tch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_CMD), channel), + &tch_cmd.reg, sizeof(HAL_DAWN_PKT_TCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_startRxChannelReg + * PURPOSE: + * To issue "START" command to the target RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_startRxChannelReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_DAWN_PKT_RCH_CMD_REG_T rch_cmd; + + rch_cmd.reg = 0x0; + rch_cmd.field.rch_start = 0x1; + rch_cmd.field.rch_gpd_add_no_lo = gpd_num & 0xff; + rch_cmd.field.rch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_CMD), channel), + &rch_cmd.reg, sizeof(HAL_DAWN_PKT_RCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_resumeTxChannelReg + * PURPOSE: + * To issue "RESUME" command to the target TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_resumeTxChannelReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_DAWN_PKT_TCH_CMD_REG_T tch_cmd; + + tch_cmd.reg = 0x0; + tch_cmd.field.tch_resume = 0x1; + tch_cmd.field.tch_gpd_add_no_lo = gpd_num & 0xff; + tch_cmd.field.tch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_CMD), channel), + &tch_cmd.reg, sizeof(HAL_DAWN_PKT_TCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_resumeRxChannelReg + * PURPOSE: + * To issue "RESUME" command to the target RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_resumeRxChannelReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_DAWN_PKT_RCH_CMD_REG_T rch_cmd; + + rch_cmd.reg = 0x0; + rch_cmd.field.rch_resume = 0x1; + rch_cmd.field.rch_gpd_add_no_lo = gpd_num & 0xff; + rch_cmd.field.rch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_CMD), channel), + &rch_cmd.reg, sizeof(HAL_DAWN_PKT_RCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_stopTxChannelReg + * PURPOSE: + * To issue "STOP" command to the target TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_stopTxChannelReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_TCH_CMD_REG_T tch_cmd; + + tch_cmd.reg = 0x0; + tch_cmd.field.tch_stop = 0x1; + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_CMD), channel), + &tch_cmd.reg, sizeof(HAL_DAWN_PKT_TCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_stopRxChannelReg + * PURPOSE: + * To issue "STOP" command to the target RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_stopRxChannelReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_RCH_CMD_REG_T rch_cmd; + + rch_cmd.reg = 0x0; + rch_cmd.field.rch_stop = 0x1; + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_CMD), channel), + &rch_cmd.reg, sizeof(HAL_DAWN_PKT_RCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Init HW Regs */ +/* FUNCTION NAME: _hal_dawn_pkt_setTxGpdStartAddrReg + * PURPOSE: + * To configure the start address and the length of target GPD ring of TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * gpd_start_addr -- The start address of the GPD ring + * gpd_ring_sz -- The size of the GPD ring + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_setTxGpdStartAddrReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + const CLX_ADDR_T gpd_start_addr, + const UI32_T gpd_ring_sz) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T tch_gpd_ring_start_addr_lo = 0; + UI32_T tch_gpd_ring_start_addr_hi = 0; + UI32_T tch_gpd_ring_size = 0; + + /* Configure the low 32-bit address. */ + tch_gpd_ring_start_addr_lo = (UI32_T)CLX_ADDR_64_LOW(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_GPD_RING_START_ADDR_LO), channel), + &tch_gpd_ring_start_addr_lo, sizeof(UI32_T)); + + /* Configure the high 32-bit address. */ + if (CLX_E_OK == rc) + { + tch_gpd_ring_start_addr_hi = (UI32_T)CLX_ADDR_64_HI(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_GPD_RING_START_ADDR_HI), channel), + &tch_gpd_ring_start_addr_hi, sizeof(UI32_T)); + } + + /* Configure the GPD ring size. */ + if (CLX_E_OK == rc) + { + tch_gpd_ring_size = gpd_ring_sz; + + rc = osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_GPD_RING_SIZE), channel), + &tch_gpd_ring_size, sizeof(UI32_T)); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_setRxGpdStartAddrReg + * PURPOSE: + * To configure the start address and the length of target GPD ring of RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_start_addr -- The start address of the GPD ring + * gpd_ring_sz -- The size of the GPD ring + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_setRxGpdStartAddrReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel, + const CLX_ADDR_T gpd_start_addr, + const UI32_T gpd_ring_sz) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T rch_gpd_ring_start_addr_lo = 0; + UI32_T rch_gpd_ring_start_addr_hi = 0; + UI32_T rch_gpd_ring_size = 0; + + /* Configure the low 32-bit address. */ + rch_gpd_ring_start_addr_lo = (UI32_T)CLX_ADDR_64_LOW(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_GPD_RING_START_ADDR_LO), channel), + &rch_gpd_ring_start_addr_lo, sizeof(UI32_T)); + + /* Configure the high 32-bit address. */ + if (CLX_E_OK == rc) + { + rch_gpd_ring_start_addr_hi = (UI32_T)CLX_ADDR_64_HI(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_GPD_RING_START_ADDR_HI), channel), + &rch_gpd_ring_start_addr_hi, sizeof(UI32_T)); + } + + /* Configure the GPD ring size. */ + if (CLX_E_OK == rc) + { + rch_gpd_ring_size = gpd_ring_sz; + + rc = osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_GPD_RING_SIZE), channel), + &rch_gpd_ring_size, sizeof(UI32_T)); + } + + return (rc); +} + +/* ----------------------------------------------------------------------------------- ISR HW Regs */ +/* FUNCTION NAME: _hal_dawn_pkt_maskAllTxL2IsrReg + * PURPOSE: + * To mask all the TX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully mask all the TX L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_maskAllTxL2IsrReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_DAWN_PKT_CLR_BITMAP(reg, + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_COS_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PFC | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_maskAllRxL2IsrReg + * PURPOSE: + * To mask all the L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully mask all the L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_maskAllRxL2IsrReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_DAWN_PKT_CLR_BITMAP(reg, + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_unmaskAllTxL2IsrReg + * PURPOSE: + * To unmask all the TX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully unmask all the TX L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_unmaskAllTxL2IsrReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_DAWN_PKT_SET_BITMAP(reg, + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_COS_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PFC | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_unmaskAllRxL2IsrReg + * PURPOSE: + * To unmask all the L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully unmask all the L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_unmaskAllRxL2IsrReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_DAWN_PKT_SET_BITMAP(reg, + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP | + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_clearTxL2IsrStatusReg + * PURPOSE: + * To clear the status of TX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * isr_bitmap -- The bitmap used to specify the target ISRs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear L1 ISR status. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_clearTxL2IsrStatusReg( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + const HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_T isr_bitmap) +{ + UI32_T reg = 0; + + HAL_DAWN_PKT_SET_BITMAP(reg, isr_bitmap); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_INT_CLR), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_clearRxL2IsrStatusReg + * PURPOSE: + * To clear the status of RX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * isr_bitmap -- The bitmap used to specify the target ISRs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear RX L2 ISR status. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_clearRxL2IsrStatusReg( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel, + const HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_T isr_bitmap) +{ + UI32_T reg = 0; + + HAL_DAWN_PKT_SET_BITMAP(reg, isr_bitmap); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_INT_CLR), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_getTxIntrCnt + * PURPOSE: + * To get the PDMA TX interrupt counters of the target channel. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_getTxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt) +{ + *ptr_intr_cnt = HAL_DAWN_PKT_TCH_CNT(unit, channel); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_getRxIntrCnt + * PURPOSE: + * To get the PDMA RX interrupt counters of the target channel. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_getRxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt) +{ + *ptr_intr_cnt = HAL_DAWN_PKT_RCH_CNT(unit, channel); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_getTxKnlCnt + * PURPOSE: + * To get the PDMA TX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the TX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_getTxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + + osal_io_copyToUser(&ptr_cookie->tx_cnt, &ptr_tx_cb->cnt, sizeof(HAL_DAWN_PKT_TX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_getRxKnlCnt + * PURPOSE: + * To get the PDMA RX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_getRxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + + osal_io_copyToUser(&ptr_cookie->rx_cnt, &ptr_rx_cb->cnt, sizeof(HAL_DAWN_PKT_RX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_clearTxKnlCnt + * PURPOSE: + * To clear the PDMA TX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the TX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_clearTxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_TX_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + + osal_memset(&ptr_tx_cb->cnt, 0, sizeof(HAL_DAWN_PKT_TX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_clearRxKnlCnt + * PURPOSE: + * To clear the PDMA RX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_clearRxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + + osal_memset(&ptr_rx_cb->cnt, 0, sizeof(HAL_DAWN_PKT_RX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_setPortAttr + * PURPOSE: + * To set the port attributes such as status or speeds. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the Port cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully set the attributes. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_setPortAttr( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_PORT_COOKIE_T *ptr_cookie) +{ +#define HAL_DAWN_PKT_PORT_STATUS_UP (1) +#define HAL_DAWN_PKT_PORT_STATUS_DOWN (0) + struct net_device *ptr_net_dev; + struct net_device_priv *ptr_priv; + UI32_T port; + UI32_T status; + CLX_PORT_SPEED_T speed; + + osal_io_copyFromUser(&port, &ptr_cookie->port, sizeof(UI32_T)); + osal_io_copyFromUser(&status, &ptr_cookie->status, sizeof(UI32_T)); + osal_io_copyFromUser(&speed, &ptr_cookie->speed, sizeof(CLX_PORT_SPEED_T)); + + ptr_net_dev = HAL_DAWN_PKT_GET_PORT_NETDEV(port); + if ((NULL != ptr_net_dev) && (portspeed = SPEED_1000; + break; + case CLX_PORT_SPEED_10G: + ptr_priv->speed = SPEED_10000; + break; + case CLX_PORT_SPEED_25G: + ptr_priv->speed = 25000; + break; + case CLX_PORT_SPEED_40G: + ptr_priv->speed = 40000; + break; + case CLX_PORT_SPEED_50G: + ptr_priv->speed = 50000; + break; + case CLX_PORT_SPEED_100G: + ptr_priv->speed = 100000; + break; + default: + break; + } + } + return (CLX_E_OK); +} + +static void +_hal_dawn_pkt_lockRxChannelAll( + const UI32_T unit) +{ + UI32_T rch; + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma; + + for (rch = 0; rch < HAL_DAWN_PKT_RX_CHANNEL_LAST; rch++) + { + ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, rch); + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + } +} + +static void +_hal_dawn_pkt_unlockRxChannelAll( + const UI32_T unit) +{ + UI32_T rch; + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma; + + for (rch = 0; rch < HAL_DAWN_PKT_RX_CHANNEL_LAST; rch++) + { + ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, rch); + osal_giveSemaphore(&ptr_rx_pdma->sema); + } +} + +#if defined(NETIF_EN_NETLINK) + +static CLX_ERROR_NO_T +_hal_dawn_pkt_setIntfProperty( + const UI32_T unit, + HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T intf_id; + NETIF_NL_INTF_PROPERTY_T property; + UI32_T param0; + UI32_T param1; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&intf_id, &ptr_cookie->intf_id, sizeof(UI32_T)); + osal_io_copyFromUser(&property, &ptr_cookie->property, sizeof(NETIF_NL_INTF_PROPERTY_T)); + osal_io_copyFromUser(¶m0, &ptr_cookie->param0, sizeof(UI32_T)); + osal_io_copyFromUser(¶m1, &ptr_cookie->param1, sizeof(UI32_T)); + + _hal_dawn_pkt_lockRxChannelAll(unit); + + rc = netif_nl_setIntfProperty(unit, intf_id, property, param0, param1); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_getIntfProperty( + const UI32_T unit, + HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T intf_id; + NETIF_NL_INTF_PROPERTY_T property; + UI32_T param0; + UI32_T param1; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&intf_id, &ptr_cookie->intf_id, sizeof(UI32_T)); + osal_io_copyFromUser(&property, &ptr_cookie->property, sizeof(NETIF_NL_INTF_PROPERTY_T)); + osal_io_copyFromUser(¶m0, &ptr_cookie->param0, sizeof(UI32_T)); + + rc = netif_nl_getIntfProperty(unit, intf_id, property, ¶m0, ¶m1); + + osal_io_copyToUser(&ptr_cookie->param0, ¶m0, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->param1, ¶m1, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_createNetlink( + const UI32_T unit, + HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + NETIF_NL_NETLINK_T netlink; + UI32_T netlink_id; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&netlink, &ptr_cookie->netlink, sizeof(NETIF_NL_NETLINK_T)); + + _hal_dawn_pkt_lockRxChannelAll(unit); + + rc = netif_nl_createNetlink(unit, &netlink, &netlink_id); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + osal_io_copyToUser(&ptr_cookie->netlink.id, &netlink_id, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_destroyNetlink( + const UI32_T unit, + HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T netlink_id; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&netlink_id, &ptr_cookie->netlink.id, sizeof(UI32_T)); + + _hal_dawn_pkt_lockRxChannelAll(unit); + + rc = netif_nl_destroyNetlink(unit, netlink_id); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_getNetlink( + const UI32_T unit, + HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T id; + NETIF_NL_NETLINK_T netlink; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&id, &ptr_cookie->netlink.id, sizeof(UI32_T)); + + rc = netif_nl_getNetlink(unit, id, &netlink); + if (CLX_E_OK == rc) + { + osal_io_copyToUser(&ptr_cookie->netlink, &netlink, sizeof(NETIF_NL_NETLINK_T)); + } + else + { + rc = CLX_E_ENTRY_NOT_FOUND; + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +#endif +/* ----------------------------------------------------------------------------------- independent func */ +/* FUNCTION NAME: _hal_dawn_pkt_enQueue + * PURPOSE: + * To enqueue the target data. + * INPUT: + * ptr_que -- Pointer for the target queue + * ptr_data -- Pointer for the data to be enqueued + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully enqueue the data. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_enQueue( + HAL_DAWN_PKT_SW_QUEUE_T *ptr_que, + void *ptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_takeSemaphore(&ptr_que->sema, CLX_SEMAPHORE_WAIT_FOREVER); + rc = osal_que_enque(&ptr_que->que_id, ptr_data); + osal_giveSemaphore(&ptr_que->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deQueue + * PURPOSE: + * To dequeue the target data. + * INPUT: + * ptr_que -- Pointer for the target queue + * pptr_data -- Pointer for the data pointer to be dequeued + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dequeue the data. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deQueue( + HAL_DAWN_PKT_SW_QUEUE_T *ptr_que, + void **pptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_takeSemaphore(&ptr_que->sema, CLX_SEMAPHORE_WAIT_FOREVER); + rc = osal_que_deque(&ptr_que->que_id, pptr_data); + osal_giveSemaphore(&ptr_que->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_getQueueCount + * PURPOSE: + * To obtain the current GPD number in the target RX queue. + * INPUT: + * ptr_que -- Pointer for the target queue + * ptr_count -- Pointer for the data count + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully obtain the GPD count. + * CLX_E_BAD_PARAMETER -- Parameter pointer is null. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_getQueueCount( + HAL_DAWN_PKT_SW_QUEUE_T *ptr_que, + UI32_T *ptr_count) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_takeSemaphore(&ptr_que->sema, CLX_SEMAPHORE_WAIT_FOREVER); + osal_que_getCount(&ptr_que->que_id, ptr_count); + osal_giveSemaphore(&ptr_que->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_allocRxPayloadBuf + * PURPOSE: + * To allocate the RX packet payload buffer for the GPD. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_idx -- The current GPD index + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully allocate the buffer. + * CLX_E_NO_MEMORY -- Allocate the buffer failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_allocRxPayloadBuf( + const UI32_T unit, + const UI32_T channel, + const UI32_T gpd_idx) +{ + CLX_ERROR_NO_T rc = CLX_E_NO_MEMORY; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + CLX_ADDR_T phy_addr = 0; + + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + struct sk_buff *ptr_skb = NULL; + + ptr_skb = osal_skb_alloc(ptr_rx_cb->buf_len); + if (NULL != ptr_skb) + { + /* map skb to dma */ + phy_addr = osal_skb_mapDma(ptr_skb, DMA_FROM_DEVICE); + if (0x0 == phy_addr) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, rxch=%u, skb dma map err, size=%u\n", + unit, channel, ptr_skb->len); + osal_skb_free(ptr_skb); + rc = CLX_E_NO_MEMORY; + } + else + { + ptr_rx_pdma->pptr_skb_ring[gpd_idx] = ptr_skb; + rc = CLX_E_OK; + } + } + + if (CLX_E_OK == rc) + { + ptr_rx_gpd->data_buf_addr_hi = CLX_ADDR_64_HI(phy_addr); + ptr_rx_gpd->data_buf_addr_lo = CLX_ADDR_64_LOW(phy_addr); + ptr_rx_gpd->avbl_buf_len = ptr_rx_cb->buf_len; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_freeRxPayloadBuf + * PURPOSE: + * To free the RX packet payload buffer for the GPD. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_idx -- The current GPD index + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully free the buffer. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_freeRxPayloadBuf( + const UI32_T unit, + const UI32_T channel, + const UI32_T gpd_idx) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + CLX_ADDR_T phy_addr = 0; + + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + struct sk_buff *ptr_skb = NULL; + + phy_addr = CLX_ADDR_32_TO_64(ptr_rx_gpd->data_buf_addr_hi, ptr_rx_gpd->data_buf_addr_lo); + if (0x0 != phy_addr) + { + /* unmap dma */ + ptr_skb = ptr_rx_pdma->pptr_skb_ring[gpd_idx]; + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_FROM_DEVICE); + osal_skb_free(ptr_skb); + rc = CLX_E_OK; + } + + if (CLX_E_OK == rc) + { + ptr_rx_gpd->data_buf_addr_hi = 0x0; + ptr_rx_gpd->data_buf_addr_lo = 0x0; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_freeRxPayloadBufGpd + * PURPOSE: + * To free the RX packet payload buffer for the GPD. + * INPUT: + * unit -- The unit ID + * ptr_sw_gpd -- The pointer of RX SW GPD + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully free the buffer. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_freeRxPayloadBufGpd( + const UI32_T unit, + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + CLX_ADDR_T phy_addr = 0; + + struct sk_buff *ptr_skb = NULL; + + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->rx_gpd.data_buf_addr_hi, ptr_sw_gpd->rx_gpd.data_buf_addr_lo); + if (0x0 != phy_addr) + { + ptr_skb = ptr_sw_gpd->ptr_cookie; + osal_skb_free(ptr_skb); + rc = CLX_E_OK; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_initTxPdmaRing + * PURPOSE: + * To initialize the GPD ring of target TX channel. + * + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the GPD ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initTxPdmaRing( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + CLX_ADDR_T phy_addr = 0; + UI32_T gpd_idx = 0; + + for (gpd_idx = 0; gpd_idx < ptr_tx_pdma->gpd_num; gpd_idx++) + { + ptr_tx_gpd = HAL_DAWN_PKT_GET_TX_GPD_PTR(unit, channel, gpd_idx); + osal_memset((void *)ptr_tx_gpd, 0x0, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + ptr_tx_gpd->ioc = HAL_DAWN_PKT_IOC_HAS_INTR; + ptr_tx_gpd->ch = HAL_DAWN_PKT_CH_LAST_GPD; + ptr_tx_gpd->hwo = HAL_DAWN_PKT_HWO_SW_OWN; + osal_dma_flushCache((void *)ptr_tx_gpd, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + } + + phy_addr = osal_dma_convertVirtToPhy(ptr_tx_pdma->ptr_gpd_align_start_addr); + rc = _hal_dawn_pkt_setTxGpdStartAddrReg(unit, channel, phy_addr, ptr_tx_pdma->gpd_num); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initRxPdmaRing + * PURPOSE: + * To initialize the RX GPD ring. + * INPUT: + * unit -- The target unit + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the RX GPD ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initRxPdmaRing( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + CLX_ADDR_T phy_addr = 0; + UI32_T gpd_idx = 0; + + for (gpd_idx = 0; gpd_idx < ptr_rx_pdma->gpd_num; gpd_idx++) + { + ptr_rx_gpd = HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + osal_memset((void *)ptr_rx_gpd, 0x0, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + ptr_rx_gpd->ioc = HAL_DAWN_PKT_IOC_NO_INTR; + ptr_rx_gpd->hwo = HAL_DAWN_PKT_HWO_SW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + } + + phy_addr = osal_dma_convertVirtToPhy(ptr_rx_pdma->ptr_gpd_align_start_addr); + rc = _hal_dawn_pkt_setRxGpdStartAddrReg(unit, channel, phy_addr, ptr_rx_pdma->gpd_num); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initRxPdmaRingBuf + * PURPOSE: + * To de-init the Rx PDMA ring configuration. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Rx PDMA ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initRxPdmaRingBuf( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + UI32_T gpd_idx = 0; + + if (0 == ptr_rx_cb->buf_len) + { + return (CLX_E_BAD_PARAMETER); + } + + for (gpd_idx = 0; gpd_idx < ptr_rx_pdma->gpd_num; gpd_idx++) + { + ptr_rx_gpd = HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + osal_dma_invalidateCache((void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + rc = _hal_dawn_pkt_allocRxPayloadBuf(unit, channel, gpd_idx); + if (CLX_E_OK == rc) + { + ptr_rx_gpd->ioc = HAL_DAWN_PKT_IOC_HAS_INTR; + ptr_rx_gpd->hwo = HAL_DAWN_PKT_HWO_HW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + } + else + { + ptr_rx_cb->cnt.no_memory++; + break; + } + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitRxPdmaRingBuf + * PURPOSE: + * To de-init the Rx PDMA ring configuration. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Rx PDMA ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitRxPdmaRingBuf( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + UI32_T gpd_idx = 0; + + for (gpd_idx = 0; ((gpd_idx < ptr_rx_pdma->gpd_num) && (CLX_E_OK == rc)); gpd_idx++) + { + /* mark the GPD as invalid to prevent Rx-done task to process it */ + ptr_rx_gpd = HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + ptr_rx_gpd->hwo = HAL_DAWN_PKT_HWO_HW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + rc = _hal_dawn_pkt_freeRxPayloadBuf(unit, channel, gpd_idx); + } + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_recoverTxPdma + * PURPOSE: + * To recover the PDMA status to the initial state. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully recover PDMA. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_recoverTxPdma( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + + /* Release the software GPD ring and configure it again. */ + ptr_tx_pdma->used_idx = 0; + ptr_tx_pdma->free_idx = 0; + ptr_tx_pdma->used_gpd_num = 0; + ptr_tx_pdma->free_gpd_num = ptr_tx_pdma->gpd_num; + + _hal_dawn_pkt_stopTxChannelReg(unit, channel); + rc = _hal_dawn_pkt_initTxPdmaRing(unit, channel); + _hal_dawn_pkt_startTxChannelReg(unit, channel, 0); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_recoverRxPdma + * PURPOSE: + * To recover the RX PDMA from the error state. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully recovery the PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_recoverRxPdma( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Release the software GPD ring and configure it again. */ + ptr_rx_pdma->cur_idx = 0; + + _hal_dawn_pkt_stopRxChannelReg(unit, channel); + rc = _hal_dawn_pkt_deinitRxPdmaRingBuf(unit, channel); + if (CLX_E_OK != rc) + { + return (rc); + } + rc = _hal_dawn_pkt_initRxPdmaRing(unit, channel); + if (CLX_E_OK != rc) + { + return (rc); + } + rc = _hal_dawn_pkt_initRxPdmaRingBuf(unit, channel); + if (CLX_E_OK != rc) + { + return (rc); + } + _hal_dawn_pkt_startRxChannelReg(unit, channel, ptr_rx_pdma->gpd_num); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_freeTxGpdList + * PURPOSE: + * To free the TX SW GPD link list. + * INPUT: + * unit -- The unit ID + * ptr_sw_gpd -- The pointer of TX SW GPD + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully free the GPD list. + * NOTES: + * None + */ +static void +_hal_dawn_pkt_freeTxGpdList( + UI32_T unit, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd_cur = NULL; + + while (NULL != ptr_sw_gpd) + { + ptr_sw_gpd_cur = ptr_sw_gpd; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + osal_free(ptr_sw_gpd_cur); + } +} + +/* FUNCTION NAME: _hal_dawn_pkt_freeRxGpdList + * PURPOSE: + * To free the RX SW GPD link list. + * INPUT: + * unit -- The unit ID + * ptr_sw_gpd -- The pointer of RX SW GPD + * free_payload -- TRUE: To free the buf in SDK, FALSE: in user process. + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully recovery the PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_freeRxGpdList( + UI32_T unit, + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd, + BOOL_T free_payload) +{ + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd_cur = NULL; + + while (NULL != ptr_sw_gpd) + { + ptr_sw_gpd_cur = ptr_sw_gpd; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + if (TRUE == free_payload) + { + _hal_dawn_pkt_freeRxPayloadBufGpd(unit, ptr_sw_gpd_cur); + } + osal_free(ptr_sw_gpd_cur); + } + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- pkt_drv */ +/* FUNCTION NAME: _hal_dawn_pkt_txEnQueueBulk + * PURPOSE: + * To enqueue numbers of packet in the bulk buffer + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * number -- The number of packet to be enqueue + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_dawn_pkt_txEnQueueBulk( + const UI32_T unit, + const UI32_T channel, + const UI32_T number) +{ + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd = NULL; + UI32_T idx; + + for (idx = 0; idx < number; idx++) + { + ptr_sw_gpd = ptr_tx_pdma->pptr_sw_gpd_bulk[idx]; + ptr_tx_pdma->pptr_sw_gpd_bulk[idx] = NULL; + if (NULL != ptr_sw_gpd->callback) + { + ptr_sw_gpd->callback(unit, ptr_sw_gpd, ptr_sw_gpd->ptr_cookie); + } + } +} + + +/* FUNCTION NAME: _hal_dawn_pkt_strictTxDeQueue + * PURPOSE: + * To dequeue the packets based on the strict algorithm. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the TX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dequeue the packets. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_strictTxDeQueue( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_TX_COOKIE_T *ptr_cookie) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd = NULL; + CLX_ADDR_T sw_gpd_addr; + UI32_T que_cnt = 0; + + /* get queue count */ + _hal_dawn_pkt_getQueueCount(&ptr_tx_cb->sw_queue, &que_cnt); + + /* wait txTask event */ + if (0 == que_cnt) + { + osal_waitEvent(&ptr_tx_cb->sync_sema); + if (FALSE == ptr_tx_cb->running) + { + return (CLX_E_OTHERS); /* deinit */ + } + + ptr_tx_cb->cnt.wait_event++; + + /* re-get queue count */ + _hal_dawn_pkt_getQueueCount(&ptr_tx_cb->sw_queue, &que_cnt); + } + + /* deque */ + if (que_cnt > 0) + { + rc = _hal_dawn_pkt_deQueue(&ptr_tx_cb->sw_queue, (void **)&ptr_sw_gpd); + if (CLX_E_OK == rc) + { + ptr_tx_cb->cnt.deque_ok++; + + sw_gpd_addr = (CLX_ADDR_T)ptr_sw_gpd->ptr_cookie; + + /* Give the address of pre-saved SW GPD back to userspace */ + osal_io_copyToUser(&ptr_cookie->done_sw_gpd_addr, + &sw_gpd_addr, + sizeof(CLX_ADDR_T)); + + /* free kernel sw_gpd */ + _hal_dawn_pkt_freeTxGpdList(unit, ptr_sw_gpd); + } + else + { + ptr_tx_cb->cnt.deque_fail++; + } + } + else + { + /* It may happen at last gpd, return error and do not invoke callback. */ + rc = CLX_E_OTHERS; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_rxCheckReason + * PURPOSE: + * To check the packets to linux kernel/user. + * INPUT: + * ptr_rx_gpd -- Pointer of the RX GPD + * ptr_hit_prof -- Pointer of the hit flag + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dispatch the packets. + * NOTES: + * Reference to pkt_srv. + */ +static void +_hal_dawn_pkt_rxCheckReason( + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd, + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile, + BOOL_T *ptr_hit_prof) +{ + HAL_PKT_RX_REASON_BITMAP_T *ptr_reason_bitmap = &ptr_profile->reason_bitmap; + UI32_T bitval = 0; + UI32_T bitmap = 0x0; + + if (0 == (ptr_profile->flags & HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_REASON)) + { + /* It means that reason doesn't metters */ + *ptr_hit_prof = TRUE; + return; + } + +#define HAL_DAWN_PKT_DI_NON_L3_CPU_MIN (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_NON_L3_MIN) +#define HAL_DAWN_PKT_DI_NON_L3_CPU_MAX (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_NON_L3_MAX) +#define HAL_DAWN_PKT_DI_L3_CPU_MIN (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_L3_MIN) +#define HAL_DAWN_PKT_DI_L3_CPU_MAX (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_L3_MAX) + + switch (ptr_rx_gpd->itmh_eth.typ) + { + case HAL_DAWN_PKT_TMH_TYPE_ITMH_ETH: + + /* IPP non-L3 exception */ + if (ptr_rx_gpd->itmh_eth.dst_idx >= HAL_DAWN_PKT_DI_NON_L3_CPU_MIN && + ptr_rx_gpd->itmh_eth.dst_idx <= HAL_DAWN_PKT_DI_NON_L3_CPU_MAX) + { + bitval = ptr_rx_gpd->itmh_eth.dst_idx - HAL_DAWN_PKT_DI_NON_L3_CPU_MIN; + bitmap = 1UL << (bitval % 32); + if (0 != (ptr_reason_bitmap->ipp_excpt_bitmap[bitval / 32] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + } + + /* IPP L3 exception */ + if (ptr_rx_gpd->itmh_eth.dst_idx >= HAL_DAWN_PKT_DI_L3_CPU_MIN && + ptr_rx_gpd->itmh_eth.dst_idx <= HAL_DAWN_PKT_DI_L3_CPU_MAX) + { + bitmap = ptr_rx_gpd->itmh_eth.dst_idx - HAL_DAWN_PKT_DI_L3_CPU_MIN; + if (0 != (ptr_reason_bitmap->ipp_l3_excpt_bitmap[0] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + } + + /* IPP cp_to_cpu_bmap */ + bitmap = ptr_rx_gpd->itmh_eth.cp_to_cpu_bmap; + if (0 != (ptr_reason_bitmap->ipp_copy2cpu_bitmap[0] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + + /* IPP cp_to_cpu_rsn */ + bitval = ptr_rx_gpd->itmh_eth.cp_to_cpu_code; + bitmap = 1UL << (bitval % 32); + if (0 != (ptr_reason_bitmap->ipp_rsn_bitmap[bitval / 32] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + break; + + case HAL_DAWN_PKT_TMH_TYPE_ITMH_FAB: + case HAL_DAWN_PKT_TMH_TYPE_ETMH_FAB: + break; + + case HAL_DAWN_PKT_TMH_TYPE_ETMH_ETH: + + /* EPP exception */ + if (1 == ptr_rx_gpd->etmh_eth.redir) + { + bitval = ptr_rx_gpd->etmh_eth.excpt_code_mir_bmap; + bitmap = 1UL << (bitval % 32); + if (0 != (ptr_reason_bitmap->epp_excpt_bitmap[bitval / 32] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + } + + /* EPP cp_to_cpu_bmap */ + bitmap = ((ptr_rx_gpd->etmh_eth.cp_to_cpu_bmap_w0 << 7) | + (ptr_rx_gpd->etmh_eth.cp_to_cpu_bmap_w1)); + if (0 != (ptr_reason_bitmap->epp_copy2cpu_bitmap[0] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + break; + + default: + *ptr_hit_prof = FALSE; + break; + } +} + +static BOOL_T +_hal_dawn_pkt_comparePatternWithPayload( + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd, + const UI8_T *ptr_pattern, + const UI8_T *ptr_mask, + const UI32_T offset) +{ + CLX_ADDR_T phy_addr = 0; + UI8_T *ptr_virt_addr = NULL; + UI32_T idx; + + /* Get the packet payload */ + phy_addr = CLX_ADDR_32_TO_64(ptr_rx_gpd->data_buf_addr_hi, ptr_rx_gpd->data_buf_addr_lo); + ptr_virt_addr = (C8_T *) osal_dma_convertPhyToVirt(phy_addr); + + for (idx=0; idxflags & (HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_0 | + HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_1 | + HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_2 | + HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_3)) != 0) + { + /* Need to compare the payload with at least one of the four patterns */ + /* Pre-assume that the result is positive */ + *ptr_hit_prof = TRUE; + + /* If any of the following comparison fails, the result will be changed to negtive */ + } + else + { + return; + } + + for (idx=0; idxflags & (HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_0 << idx))) + { + match = _hal_dawn_pkt_comparePatternWithPayload(ptr_rx_gpd, + ptr_profile->pattern[idx], + ptr_profile->mask[idx], + ptr_profile->offset[idx]); + if (TRUE == match) + { + /* Do nothing */ + } + else + { + /* Change the result to negtive */ + *ptr_hit_prof = FALSE; + break; + } + } + } +} + +static void +_hal_dawn_pkt_matchUserProfile( + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd, + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_profile_list, + HAL_DAWN_PKT_NETIF_PROFILE_T **pptr_profile_hit) +{ + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_curr_node = ptr_profile_list; + BOOL_T hit; + + *pptr_profile_hit = NULL; + + while (NULL != ptr_curr_node) + { + /* 1st match reason */ + _hal_dawn_pkt_rxCheckReason(ptr_rx_gpd, ptr_curr_node->ptr_profile, &hit); + if (TRUE == hit) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "rx prof matched by reason\n"); + + /* Then, check pattern */ + _hal_dawn_pkt_rxCheckPattern(ptr_rx_gpd, ptr_curr_node->ptr_profile, &hit); + if (TRUE == hit) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "rx prof matched by pattern\n"); + + *pptr_profile_hit = ptr_curr_node->ptr_profile; + break; + } + } + + /* Seach the next profile (priority lower) */ + ptr_curr_node = ptr_curr_node->ptr_next_node; + } +} + +static void +_hal_dawn_pkt_getPacketDest( + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd, + HAL_DAWN_PKT_DEST_T *ptr_dest, + void **pptr_cookie) +{ + UI32_T port; + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_profile_list; + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile_hit; + + port = ptr_rx_gpd->itmh_eth.igr_phy_port; + ptr_profile_list = HAL_DAWN_PKT_GET_PORT_PROFILE_LIST(port); + + _hal_dawn_pkt_matchUserProfile(ptr_rx_gpd, + ptr_profile_list, + &ptr_profile_hit); + if (NULL != ptr_profile_hit) + { +#if defined(NETIF_EN_NETLINK) + if (HAL_DAWN_PKT_NETIF_RX_DST_NETLINK == ptr_profile_hit->dst_type) + { + *ptr_dest = HAL_DAWN_PKT_DEST_NETLINK; + *pptr_cookie = (void *)&ptr_profile_hit->netlink; + } + else + { + *ptr_dest = HAL_DAWN_PKT_DEST_SDK; + } +#else + *ptr_dest = HAL_DAWN_PKT_DEST_SDK; +#endif + } + else + { + *ptr_dest = HAL_DAWN_PKT_DEST_NETDEV; + } +} + +/* FUNCTION NAME: _hal_dawn_pkt_rxEnQueue + * PURPOSE: + * To enqueue the packets to multiple queues. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * ptr_sw_gpd -- Pointer for the SW Rx GPD link list + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully enqueue the packets. + * NOTES: + * None + */ +static void +_hal_dawn_pkt_rxEnQueue( + const UI32_T unit, + const UI32_T channel, + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd) +{ + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_first_gpd = ptr_sw_gpd; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0; + HAL_DAWN_PKT_DEST_T dest_type; + + /* skb meta */ + UI32_T port = 0, len = 0, total_len = 0; + struct net_device *ptr_net_dev = NULL; + struct net_device_priv *ptr_priv = NULL; + struct sk_buff *ptr_skb = NULL, *ptr_merge_skb = NULL; + UI32_T copy_offset; + void *ptr_dest; + +#if defined(PERF_EN_TEST) + /* To verify kernel Rx performance */ + if (CLX_E_OK == perf_rxTest()) + { + while (NULL != ptr_sw_gpd) + { + len += (HAL_DAWN_PKT_CH_LAST_GPD == ptr_sw_gpd->rx_gpd.ch)? + ptr_sw_gpd->rx_gpd.cnsm_buf_len : ptr_sw_gpd->rx_gpd.avbl_buf_len; + + total_len += len; + + /* unmap dma */ + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->rx_gpd.data_buf_addr_hi, ptr_sw_gpd->rx_gpd.data_buf_addr_lo); + osal_skb_unmapDma(phy_addr, len, DMA_FROM_DEVICE); + /* next */ + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + perf_rxCallback(total_len); + _hal_dawn_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, TRUE); + return ; + } +#endif + + _hal_dawn_pkt_getPacketDest(&ptr_sw_gpd->rx_gpd, &dest_type, &ptr_dest); + +#if defined(NETIF_EN_NETLINK) + if ((HAL_DAWN_PKT_DEST_NETDEV == dest_type) || + (HAL_DAWN_PKT_DEST_NETLINK == dest_type)) +#else + if (HAL_DAWN_PKT_DEST_NETDEV == dest_type) +#endif + { + /* need to encap the packet as skb */ + ptr_sw_gpd = ptr_sw_first_gpd; + while (NULL != ptr_sw_gpd) + { + len = (HAL_DAWN_PKT_CH_LAST_GPD == ptr_sw_gpd->rx_gpd.ch)? + ptr_sw_gpd->rx_gpd.cnsm_buf_len : ptr_sw_gpd->rx_gpd.avbl_buf_len; + + total_len += len; + + /* unmap dma */ + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->rx_gpd.data_buf_addr_hi, ptr_sw_gpd->rx_gpd.data_buf_addr_lo); + ptr_virt_addr = ptr_sw_gpd->ptr_cookie; + + ptr_skb = (struct sk_buff *)ptr_virt_addr; + + /* note here ptr_skb->len is the total buffer size not means the actual Rx packet len + * it should be updated later + */ + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_FROM_DEVICE); + + /* reset ptr_skb->len with real packet len instead of total buffer size */ + if (NULL == ptr_sw_gpd->ptr_next) + { + /* strip CRC padded by asic for the last gpd segment */ + ptr_skb->len = len - ETH_FCS_LEN; + } + else + { + ptr_skb->len = len; + } + + skb_set_tail_pointer(ptr_skb, ptr_skb->len); + + /* next */ + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + + port = ptr_sw_first_gpd->rx_gpd.itmh_eth.igr_phy_port; + ptr_net_dev = HAL_DAWN_PKT_GET_PORT_NETDEV(port); + + /* if the packet is composed of multiple gpd (skb), need to merge it into a single skb */ + if (NULL != ptr_sw_first_gpd->ptr_next) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, rcv pkt size=%u > gpd buf size=%u\n", + unit, channel, total_len, ptr_rx_cb->buf_len); + ptr_merge_skb = osal_skb_alloc(total_len - ETH_FCS_LEN); + if (NULL != ptr_merge_skb) + { + copy_offset = 0; + ptr_sw_gpd = ptr_sw_first_gpd; + while (NULL != ptr_sw_gpd) + { + ptr_skb = (struct sk_buff *)ptr_sw_gpd->ptr_cookie; + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, copy size=%u to buf offset=%u\n", + unit, channel, ptr_skb->len, copy_offset); + + memcpy(&(((UI8_T *)ptr_merge_skb->data)[copy_offset]), + ptr_skb->data, ptr_skb->len); + copy_offset += ptr_skb->len; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + /* put the merged skb to ptr_skb for the following process */ + ptr_skb = ptr_merge_skb; + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, alloc skb failed, size=%u\n", + unit, channel, (total_len - ETH_FCS_LEN)); + } + + /* free both sw_gpd and the skb attached on it */ + _hal_dawn_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, TRUE); + } + else + { + /* free only sw_gpd */ + _hal_dawn_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, FALSE); + } + + /* if NULL netdev, drop the skb */ + if (NULL == ptr_net_dev) + { + ptr_rx_cb->cnt.channel[channel].netdev_miss++; + osal_skb_free(ptr_skb); + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, find netdev failed\n", + unit, channel); + return; + } + + /* skb handling */ + ptr_skb->dev = ptr_net_dev; + ptr_skb->pkt_type = PACKET_HOST; /* this packet is for me */ + ptr_skb->ip_summed = CHECKSUM_UNNECESSARY; /* skip checksum */ + + /* send to linux */ + if (dest_type == HAL_DAWN_PKT_DEST_NETDEV) + { + /* skip ethernet header only for Linux net interface*/ + ptr_skb->protocol = eth_type_trans(ptr_skb, ptr_net_dev); + osal_skb_recv(ptr_skb); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) + ptr_net_dev->last_rx = jiffies; +#endif + ptr_priv = netdev_priv(ptr_net_dev); + ptr_priv->stats.rx_packets++; + ptr_priv->stats.rx_bytes += total_len; + } +#if defined(NETIF_EN_NETLINK) + else + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "hit profile dest=netlink, name=%s, mcgrp=%s\n", + ((NETIF_NL_RX_DST_NETLINK_T *)ptr_dest)->name, + ((NETIF_NL_RX_DST_NETLINK_T *)ptr_dest)->mc_group_name); + netif_nl_rxSkb(unit, ptr_skb, ptr_dest); + } +#endif + } + else if (HAL_DAWN_PKT_DEST_SDK == dest_type) + { + while (0 != _hal_dawn_pkt_enQueue(&ptr_rx_cb->sw_queue[channel], ptr_sw_gpd)) + { + ptr_rx_cb->cnt.channel[channel].enque_retry++; + HAL_DAWN_PKT_RX_ENQUE_RETRY_SLEEP(); + } + ptr_rx_cb->cnt.channel[channel].enque_ok++; + + osal_triggerEvent(&ptr_rx_cb->sync_sema); + ptr_rx_cb->cnt.channel[channel].trig_event++; + } + else if (HAL_DAWN_PKT_DEST_DROP == dest_type) + { + _hal_dawn_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, TRUE); + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, invalid pkt dest=%d\n", + unit, channel, dest_type); + } +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_flushRxQueue( + const UI32_T unit, + HAL_DAWN_PKT_SW_QUEUE_T *ptr_que) +{ + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd_knl = NULL; + CLX_ERROR_NO_T rc; + + while (1) + { + rc = _hal_dawn_pkt_deQueue(ptr_que, (void **)&ptr_sw_gpd_knl); + if (CLX_E_OK == rc) + { + _hal_dawn_pkt_freeRxGpdList(unit, ptr_sw_gpd_knl, TRUE); + } + else + { + break; + } + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_schedRxDeQueue + * PURPOSE: + * To dequeue the packets based on the configured algorithm. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dequeue the packets. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_schedRxDeQueue( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T ioctl_data; + HAL_DAWN_PKT_IOCTL_RX_GPD_T ioctl_gpd; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd_knl = NULL; + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_first_gpd_knl = NULL; + UI32_T que_cnt = 0; + UI32_T queue = 0; + UI32_T idx = 0; + UI32_T gpd_idx = 0; + /* copy Rx sw_gpd */ + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0; + UI32_T buf_len = 0; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* normal process */ + if (TRUE == ptr_rx_cb->running) + { + /* get queue and count */ + for (idx = 0; idx < HAL_DAWN_PKT_RX_QUEUE_NUM; idx++) + { + /* to gurantee the opportunity where each queue can be handler */ + queue = ((ptr_rx_cb->deque_idx + idx) % HAL_DAWN_PKT_RX_QUEUE_NUM); + _hal_dawn_pkt_getQueueCount(&ptr_rx_cb->sw_queue[queue], &que_cnt); + if (que_cnt > 0) + { + ptr_rx_cb->deque_idx = ((queue + 1) % HAL_DAWN_PKT_RX_QUEUE_NUM); + break; + } + } + + /* If all of the queues are empty, wait rxTask event */ + if (0 == que_cnt) + { + osal_waitEvent(&ptr_rx_cb->sync_sema); + + ptr_rx_cb->cnt.wait_event++; + + /* re-get queue and count */ + for (queue = 0; queue < HAL_DAWN_PKT_RX_QUEUE_NUM; queue++) + { + _hal_dawn_pkt_getQueueCount(&ptr_rx_cb->sw_queue[queue], &que_cnt); + if (que_cnt > 0) + { + ptr_rx_cb->deque_idx = ((queue + 1) % HAL_DAWN_PKT_RX_QUEUE_NUM); + break; + } + } + } + + /* deque */ + if ((que_cnt > 0) && (queue < HAL_DAWN_PKT_RX_QUEUE_NUM)) + { + rc = _hal_dawn_pkt_deQueue(&ptr_rx_cb->sw_queue[queue], (void **)&ptr_sw_gpd_knl); + if (CLX_E_OK == rc) + { + ptr_rx_cb->cnt.channel[queue].deque_ok++; + ptr_sw_first_gpd_knl = ptr_sw_gpd_knl; + + osal_io_copyFromUser(&ioctl_data, ptr_cookie, sizeof(HAL_DAWN_PKT_IOCTL_RX_COOKIE_T)); + + while (NULL != ptr_sw_gpd_knl) + { + /* get the IOCTL GPD from user */ + osal_io_copyFromUser(&ioctl_gpd, + ((void *)((CLX_HUGE_T)ioctl_data.ioctl_gpd_addr)) + + gpd_idx*sizeof(HAL_DAWN_PKT_IOCTL_RX_GPD_T), + sizeof(HAL_DAWN_PKT_IOCTL_RX_GPD_T)); + + /* get knl buf addr */ + ptr_rx_gpd = &ptr_sw_gpd_knl->rx_gpd; + phy_addr = CLX_ADDR_32_TO_64(ptr_rx_gpd->data_buf_addr_hi, ptr_rx_gpd->data_buf_addr_lo); + + ptr_virt_addr = ptr_sw_gpd_knl->ptr_cookie; + osal_skb_unmapDma(phy_addr, ((struct sk_buff *)ptr_virt_addr)->len, DMA_FROM_DEVICE); + + buf_len = (HAL_DAWN_PKT_CH_LAST_GPD == ptr_rx_gpd->ch)? + ptr_rx_gpd->cnsm_buf_len : ptr_rx_gpd->avbl_buf_len; + + /* overwrite whole rx_gpd to user + * the user should re-assign the correct value to data_buf_addr_hi, data_buf_addr_low + * after this IOCTL returns + */ + osal_io_copyToUser((void *)((CLX_HUGE_T)ioctl_gpd.hw_gpd_addr), + &ptr_sw_gpd_knl->rx_gpd, + sizeof(HAL_DAWN_PKT_RX_GPD_T)); + /* copy buf */ + /* DMA buf address allocated by the user is store in ptr_ioctl_data->gpd[idx].cookie */ + osal_io_copyToUser((void *)((CLX_HUGE_T)ioctl_gpd.dma_buf_addr), + ((struct sk_buff *)ptr_virt_addr)->data, buf_len); + ptr_sw_gpd_knl->ptr_cookie = ptr_virt_addr; + + /* next */ + ptr_sw_gpd_knl = ptr_sw_gpd_knl->ptr_next; + gpd_idx++; + } + + /* Must free kernel sw_gpd */ + _hal_dawn_pkt_freeRxGpdList(unit, ptr_sw_first_gpd_knl, TRUE); + } + else + { + ptr_rx_cb->cnt.channel[queue].deque_fail++; + } + } + else + { + /* it means that all queue's are flush -> rx stop flow */ + rc = CLX_E_OTHERS; + } + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_waitTxDone + * PURPOSE: + * To determine the next action after transfer the packet to HW. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * ptr_sw_gpd -- Pointer for the SW Tx GPD link list + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully perform the target action. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_waitTxDone( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + UI32_T last_gpd_idx = 0; + UI32_T loop_cnt = 0; + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + ; + } + else if (HAL_DAWN_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + osal_takeSemaphore(&ptr_tx_pdma->sync_intr_sema, HAL_DAWN_PKT_PDMA_TX_INTR_TIMEOUT); + /* rc = _hal_dawn_pkt_invokeTxGpdCallback(unit, ptr_sw_gpd); */ + } + else if (HAL_DAWN_PKT_TX_WAIT_SYNC_POLL == ptr_tx_cb->wait_mode) + { + last_gpd_idx = ptr_tx_pdma->free_idx + ptr_tx_pdma->used_gpd_num; + last_gpd_idx %= ptr_tx_pdma->gpd_num; + ptr_tx_gpd = HAL_DAWN_PKT_GET_TX_GPD_PTR(unit, channel, last_gpd_idx); + + while (HAL_DAWN_PKT_HWO_HW_OWN == ptr_tx_gpd->hwo) + { + osal_dma_invalidateCache((void *)ptr_tx_gpd, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + loop_cnt++; + if (0 == loop_cnt % HAL_DAWN_PKT_PDMA_TX_POLL_MAX_LOOP) + { + ptr_tx_cb->cnt.channel[channel].poll_timeout++; + rc = CLX_E_OTHERS; + break; + } + } + if (HAL_DAWN_PKT_ECC_ERROR_OCCUR == ptr_tx_gpd->ecce) + { + ptr_tx_cb->cnt.channel[channel].ecc_err++; + } + if (CLX_E_OK == rc) + { + ptr_tx_pdma->free_gpd_num += ptr_tx_pdma->used_gpd_num; + ptr_tx_pdma->used_gpd_num = 0; + ptr_tx_pdma->free_idx = ptr_tx_pdma->used_idx; + /* rc = _hal_dawn_pkt_invokeTxGpdCallback(unit, ptr_sw_gpd); */ + } + } + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_resumeAllIntf( + const UI32_T unit) +{ + struct net_device *ptr_net_dev = NULL; + UI32_T port; + + /* Unregister net devices by id */ + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_net_dev = HAL_DAWN_PKT_GET_PORT_NETDEV(port); + if (NULL != ptr_net_dev) + { + if (netif_queue_stopped(ptr_net_dev)) + { + netif_wake_queue(ptr_net_dev); + } + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_suspendAllIntf( + const UI32_T unit) +{ + struct net_device *ptr_net_dev = NULL; + UI32_T port; + + /* Unregister net devices by id */ + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_net_dev = HAL_DAWN_PKT_GET_PORT_NETDEV(port); + if (NULL != ptr_net_dev) + { + netif_stop_queue(ptr_net_dev); + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_stopAllIntf( + const UI32_T unit) +{ + struct net_device *ptr_net_dev = NULL; + UI32_T port; + + /* Unregister net devices by id */ + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_net_dev = HAL_DAWN_PKT_GET_PORT_NETDEV(port); + if (NULL != ptr_net_dev) + { + netif_tx_disable(ptr_net_dev); + } + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_sendGpd + * PURPOSE: + * To perform the packet transmission form CPU to the switch. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * ptr_sw_gpd -- Pointer for the SW Tx GPD link list + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully perform the transferring. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_sendGpd( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_first_gpd = ptr_sw_gpd; + UI32_T used_idx = 0; + UI32_T used_gpd_num = ptr_sw_gpd->gpd_num; + CLX_IRQ_FLAGS_T irq_flags; + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + + if (0 != (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_TASK)) + { + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irq_flags); + + /* If not PDMA error */ + if (FALSE == ptr_tx_pdma->err_flag) + { + /* Make Sure GPD is enough */ + if (ptr_tx_pdma->free_gpd_num >= used_gpd_num) + { + used_idx = ptr_tx_pdma->used_idx; + while (NULL != ptr_sw_gpd) + { + ptr_tx_gpd = HAL_DAWN_PKT_GET_TX_GPD_PTR(unit, channel, used_idx); + osal_dma_invalidateCache((void *)ptr_tx_gpd, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + if (HAL_DAWN_PKT_HWO_HW_OWN == ptr_tx_gpd->hwo) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, free gpd idx out-of-sync\n", + unit, channel); + rc = CLX_E_TABLE_FULL; + break; + } + + /* Fill in HW-GPD Ring */ + osal_memcpy((void *)ptr_tx_gpd, &ptr_sw_gpd->tx_gpd, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + osal_dma_flushCache((void *)ptr_tx_gpd, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + /* next */ + used_idx++; + used_idx %= ptr_tx_pdma->gpd_num; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* Fill 1st GPD in SW-GPD Ring */ + ptr_tx_pdma->pptr_sw_gpd_ring[ptr_tx_pdma->used_idx] = ptr_sw_first_gpd; + } + + /* update Tx PDMA */ + ptr_tx_pdma->used_idx = used_idx; + ptr_tx_pdma->used_gpd_num += used_gpd_num; + ptr_tx_pdma->free_gpd_num -= used_gpd_num; + + _hal_dawn_pkt_resumeTxChannelReg(unit, channel, used_gpd_num); + ptr_tx_cb->cnt.channel[channel].send_ok++; + + _hal_dawn_pkt_waitTxDone(unit, channel, ptr_sw_first_gpd); + + /* reserve 1 packet buffer for each port in case that the suspension is too late */ +#define HAL_DAWN_PKT_KNL_TX_RING_AVBL_GPD_LOW (HAL_DAWN_PORT_NUM) + if (ptr_tx_pdma->free_gpd_num < HAL_DAWN_PKT_KNL_TX_RING_AVBL_GPD_LOW) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_TX, + "u=%u, txch=%u, tx avbl gpd < %d, suspend all netdev\n", + unit, channel, HAL_DAWN_PKT_KNL_TX_RING_AVBL_GPD_LOW); + _hal_dawn_pkt_suspendAllIntf(unit); + } + } + else + { + rc = CLX_E_TABLE_FULL; + } + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma hw err\n", + unit, channel); + rc = CLX_E_OTHERS; + } + + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irq_flags); + } + else + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "Tx failed, task already deinit\n"); + rc = CLX_E_OTHERS; + } + + return (rc); +} + +/* ----------------------------------------------------------------------------------- pkt_srv */ +/* ----------------------------------------------------------------------------------- Rx Init */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_rxStop( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CHANNEL_T channel = 0; + UI32_T idx; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = NULL; + + /* Check if Rx is already stopped*/ + if (0 == (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_RX_START)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rx stop failed, not started\n", unit); + return (CLX_E_OK); + } + + /* Check if PKT Drv/Task were de-init before stopping Rx */ + /* Currently, we help to stop Rx when deinit Drv/Task, so it shouldn't enter below logic */ + if ((0 == (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_TASK)) || + (0 == (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_DRV))) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rx stop failed, pkt task & pkt drv not init\n", unit); + return (CLX_E_OK); + } + + /* Deinit Rx PDMA and free buf for Rx GPD */ + for (channel = 0; channel < HAL_DAWN_PKT_RX_CHANNEL_LAST; channel++) + { + ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + _hal_dawn_pkt_stopRxChannelReg(unit, channel); + rc = _hal_dawn_pkt_deinitRxPdmaRingBuf(unit, channel); + osal_giveSemaphore(&ptr_rx_pdma->sema); + } + + /* flush packets in all queues since Rx task may be blocked in user space + * in this case it won't do ioctl to kernel to handle remaining packets + */ + for (idx = 0; idx < HAL_DAWN_PKT_RX_QUEUE_NUM; idx++) + { + _hal_dawn_pkt_flushRxQueue(unit, &ptr_rx_cb->sw_queue[idx]); + } + + /* Return user thread */ + ptr_rx_cb->running = FALSE; + ptr_cb->init_flag &= (~HAL_DAWN_PKT_INIT_RX_START); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rx stop done, init flag=0x%x\n", unit, ptr_cb->init_flag); + + osal_triggerEvent(&ptr_rx_cb->sync_sema); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_rxStart( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CHANNEL_T channel = 0; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = NULL; + + if (0 != (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_RX_START)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rx start failed, already started\n", unit); + return (CLX_E_OK); + } + + /* init Rx PDMA and alloc buf for Rx GPD */ + for (channel = 0; channel < HAL_DAWN_PKT_RX_CHANNEL_LAST; channel++) + { + ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + rc = _hal_dawn_pkt_initRxPdmaRingBuf(unit, channel); + if (CLX_E_OK == rc) + { + ptr_rx_pdma->cur_idx = 0; + _hal_dawn_pkt_startRxChannelReg(unit, channel, ptr_rx_pdma->gpd_num); + } + osal_giveSemaphore(&ptr_rx_pdma->sema); + } + + /* enable to dequeue rx packets */ + ptr_rx_cb->running = TRUE; + + /* set the flag to record init state */ + ptr_cb->init_flag |= HAL_DAWN_PKT_INIT_RX_START; + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rx start done, init flag=0x%x\n", unit, ptr_cb->init_flag); + return (rc); +} + +/* FUNCTION NAME: hal_dawn_pkt_setRxKnlConfig + * PURPOSE: + * 1. To stop the Rx channel and deinit the Rx subsystem. + * 2. To init the Rx subsystem and start the Rx channel. + * 3. To restart the Rx subsystem + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the RX parameters. + * CLX_E_OTHERS -- Configure the parameter failed. + * NOTES: + * + */ +CLX_ERROR_NO_T +hal_dawn_pkt_setRxKnlConfig( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + HAL_DAWN_PKT_IOCTL_RX_TYPE_T rx_type = HAL_DAWN_PKT_IOCTL_RX_TYPE_LAST; + + osal_io_copyFromUser(&rx_type, &ptr_cookie->rx_type, sizeof(HAL_DAWN_PKT_IOCTL_RX_TYPE_T)); + + if (HAL_DAWN_PKT_IOCTL_RX_TYPE_DEINIT == rx_type) + { + _hal_dawn_pkt_rxStop(unit); + } + if (HAL_DAWN_PKT_IOCTL_RX_TYPE_INIT == rx_type) + { + /* To prevent buffer size from being on-the-fly changed */ + if (0 != (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_RX_START)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rx stop failed, not started\n", unit); + return (CLX_E_OK); + } + + osal_io_copyFromUser(&ptr_rx_cb->buf_len, &ptr_cookie->buf_len, sizeof(UI32_T)); + _hal_dawn_pkt_rxStart(unit); + } + + return (rc); +} + +/* FUNCTION NAME: hal_dawn_pkt_getRxKnlConfig + * PURPOSE: + * To get the Rx subsystem configuration. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the RX parameters. + * CLX_E_OTHERS -- Configure the parameter failed. + * NOTES: + * + */ +CLX_ERROR_NO_T +hal_dawn_pkt_getRxKnlConfig( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + + osal_io_copyToUser(&ptr_cookie->buf_len, &ptr_rx_cb->buf_len, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Deinit */ +/* FUNCTION NAME: hal_dawn_pkt_deinitTask + * PURPOSE: + * To de-initialize the Task for packet module. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dinitialize the control block. + * CLX_E_OTHERS -- Initialize the control block failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_deinitTask( + const UI32_T unit) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + UI32_T channel = 0; + + /* to prevent net intf from Tx packet */ + ptr_tx_cb->net_tx_allowed = FALSE; + + /* In case that some undestroyed net intf keep Tx after task deinit */ + _hal_dawn_pkt_stopAllIntf(unit); + + if (0 == (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_TASK)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rx stop failed, not started\n", unit); + return (CLX_E_OK); + } + + /* Need to stop Rx before de-init Task */ + if (0 != (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_RX_START)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, pkt task deinit failed, rx not stop\n", unit); + + _hal_dawn_pkt_rxStop(unit); + } + + /* Make the Rx IOCTL from userspace return back*/ + osal_triggerEvent(&ptr_rx_cb->sync_sema); + + /* Destroy txTask */ + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + ptr_tx_cb->running = FALSE; + osal_triggerEvent(&ptr_tx_cb->sync_sema); + } + + /* Destroy handleRxDoneTask */ + for (channel = 0; channel < HAL_DAWN_PKT_RX_CHANNEL_LAST; channel++) + { + osal_stopThread(&ptr_rx_cb->isr_task_id[channel]); + osal_triggerEvent(HAL_DAWN_PKT_RCH_EVENT(unit, channel)); + osal_destroyThread(&ptr_rx_cb->isr_task_id[channel]); + } + + /* Destroy handleTxDoneTask */ + for (channel = 0; channel < HAL_DAWN_PKT_TX_CHANNEL_LAST; channel++) + { + osal_stopThread(&ptr_tx_cb->isr_task_id[channel]); + osal_triggerEvent(HAL_DAWN_PKT_TCH_EVENT(unit, channel)); + osal_destroyThread(&ptr_tx_cb->isr_task_id[channel]); + } + + /* Destroy handleErrorTask */ + osal_stopThread(&ptr_cb->err_task_id); + osal_triggerEvent(HAL_DAWN_PKT_ERR_EVENT(unit)); + osal_destroyThread(&ptr_cb->err_task_id); + + /* Set the flag to record init state */ + ptr_cb->init_flag &= (~HAL_DAWN_PKT_INIT_TASK); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, pkt task deinit done, init flag=0x%x\n", + unit, ptr_cb->init_flag); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitTxPdma + * PURPOSE: + * To de-initialize the Tx PDMA configuration of the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target Tx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Tx PDMA. + * CLX_E_OTHERS -- De-init the Tx PDMA failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitTxPdma( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + + _hal_dawn_pkt_stopTxChannelReg(unit, channel); + + /* Free DMA and flush queue */ + osal_dma_free(ptr_tx_pdma->ptr_gpd_start_addr); + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + osal_free(ptr_tx_pdma->pptr_sw_gpd_ring); + osal_free(ptr_tx_pdma->pptr_sw_gpd_bulk); + } + else if (HAL_DAWN_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + osal_destroySemaphore(&ptr_tx_pdma->sync_intr_sema); + } + + osal_destroyIsrLock(&ptr_tx_pdma->ring_lock); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitRxPdma + * PURPOSE: + * To de-initialize the Rx PDMA configuration of the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target Rx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Rx PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitRxPdma( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Free DMA */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + osal_dma_free(ptr_rx_pdma->ptr_gpd_start_addr); + osal_giveSemaphore(&ptr_rx_pdma->sema); + osal_destroySemaphore(&ptr_rx_pdma->sema); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitPktCb + * PURPOSE: + * To de-init the control block of Drv. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitPktCb( + const UI32_T unit) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + UI32_T idx = 0, vec = sizeof(_hal_dawn_pkt_intr_vec) / sizeof(HAL_DAWN_PKT_INTR_VEC_T); + + for (idx = 0; idx < vec; idx++) + { + osal_destroyEvent(&_hal_dawn_pkt_intr_vec[idx].intr_event); + ptr_cb->intr_bitmap &= ~(_hal_dawn_pkt_intr_vec[idx].intr_reg); + } + + /* Unregister PKT interrupt functions */ + osal_mdc_registerIsr(unit, NULL, NULL); + osal_destroyIsrLock(&ptr_cb->intr_lock); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitPktTxCb + * PURPOSE: + * To de-init the control block of Tx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitPktTxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_CHANNEL_T channel = 0; + + /* Deinitialize TX PDMA sub-system.*/ + for (channel = 0; channel < HAL_DAWN_PKT_TX_CHANNEL_LAST; channel++) + { + _hal_dawn_pkt_deinitTxPdma(unit, channel); + } + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* Destroy the sync semaphore of txTask */ + osal_destroyEvent(&ptr_tx_cb->sync_sema); + + /* Deinitialize Tx GPD-queue (of first SW-GPD) from handleTxDoneTask to txTask */ + osal_destroySemaphore(&ptr_tx_cb->sw_queue.sema); + osal_que_destroy(&ptr_tx_cb->sw_queue.que_id); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitPktRxCb + * PURPOSE: + * To de-init the control block of Rx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitPktRxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_CHANNEL_T channel = 0; + UI32_T queue = 0; + + /* Deinitialize RX PDMA sub-system */ + for (channel = 0; channel < HAL_DAWN_PKT_RX_CHANNEL_LAST; channel++) + { + _hal_dawn_pkt_deinitRxPdma(unit, channel); + } + + /* Destroy the sync semaphore of rxTask */ + osal_destroyEvent(&ptr_rx_cb->sync_sema); + + /* Deinitialize Rx GPD-queue (of first SW-GPD) from handleRxDoneTask to rxTask */ + for (queue = 0; queue < HAL_DAWN_PKT_RX_QUEUE_NUM; queue++) + { + osal_destroySemaphore(&ptr_rx_cb->sw_queue[queue].sema); + osal_que_destroy(&ptr_rx_cb->sw_queue[queue].que_id); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitL1Isr + * PURPOSE: + * To de-initialize the PDMA L1 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-initialize for the L1 ISR. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitL1Isr( + const UI32_T unit) +{ + UI32_T idx = 0, vec = sizeof(_hal_dawn_pkt_intr_vec) / sizeof(HAL_DAWN_PKT_INTR_VEC_T); + + for (idx = 0; idx < vec; idx++) + { + _hal_dawn_pkt_maskIntr(unit, _hal_dawn_pkt_intr_vec[idx].intr_reg); + _hal_dawn_pkt_disableIntr(unit, _hal_dawn_pkt_intr_vec[idx].intr_reg); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_deinitL2Isr + * PURPOSE: + * To initialize the PDMA L2 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure for the L2 ISR. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_deinitL2Isr( + const UI32_T unit) +{ + HAL_DAWN_PKT_L2_ISR_T isr_status = 0x0; + + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH0); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH1); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH2); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH3); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH0); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH1); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH2); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH3); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RX_QID_MAP_ERR); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RX_FRAME_ERR); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_MASK_SET), + &isr_status, sizeof(UI32_T)); + + isr_status = 0x0; + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_EN), + &isr_status, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_deinitPktDrv + * PURPOSE: + * To invoke the functions to de-initialize the control block for each + * PDMA subsystem. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-initialize the control blocks. + * CLX_E_OTHERS -- De-initialize the control blocks failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_deinitPktDrv( + const UI32_T unit) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (0 == (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_DRV)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, pkt drv deinit failed, not inited\n", unit); + return (CLX_E_OK); + } + + rc = _hal_dawn_pkt_deinitL2Isr(unit); + + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_deinitL1Isr(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_deinitPktRxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_deinitPktTxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_deinitPktCb(unit); + } + + ptr_cb->init_flag &= (~HAL_DAWN_PKT_INIT_DRV); + + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, + "u=%u, pkt drv deinit done, init flag=0x%x\n", + unit, ptr_cb->init_flag); + return (rc); +} + +/* ----------------------------------------------------------------------------------- Init */ +/* FUNCTION NAME: _hal_dawn_pkt_handleTxErrStat + * PURPOSE: + * To handle the TX flow control ISR. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the interrpt. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_handleTxErrStat( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + CLX_IRQ_FLAGS_T irg_flags; + + if (HAL_DAWN_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + /* Notify the TX process to make it release the channel semaphore. */ + osal_giveSemaphore(&ptr_tx_pdma->sync_intr_sema); + } + + /* Set the error flag. */ + + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + ptr_tx_pdma->err_flag = TRUE; + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + + osal_triggerEvent(HAL_DAWN_PKT_TCH_EVENT(unit, channel)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_handleRxErrStat + * PURPOSE: + * To handle the error which occurs in RX channels. + * INPUT: + * unit -- The unit ID + * channel -- The channel where the error occurs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the error situation. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_handleRxErrStat( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Set the error flag. */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + ptr_rx_pdma->err_flag = TRUE; + osal_giveSemaphore(&ptr_rx_pdma->sema); + + osal_triggerEvent(HAL_DAWN_PKT_RCH_EVENT(unit, channel)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_handleTxL2Isr + * PURPOSE: + * To handle the TX L2 interrupt according to the ISR status. + * INPUT: + * unit -- The unit ID + * channel -- The channel where the interrupt occurs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the L2 interrupt. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_handleTxL2Isr( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_T isr_status = 0x0; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + + osal_mdc_readPciReg(unit, + HAL_DAWN_PKT_GET_PDMA_TCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_TCH_INT_STAT), channel), + &isr_status, sizeof(isr_status)); + + _hal_dawn_pkt_maskAllTxL2IsrReg(unit, channel); + + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd hwo err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_hwo_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd chksum err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_chksm_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd num overflow err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_no_ovfl_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd dma read err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_dma_read_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma buf size err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR); + ptr_tx_cb->cnt.channel[channel].buf_size_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_TX, + "u=%u, txch=%u, pdma pkt runt\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR); + ptr_tx_cb->cnt.channel[channel].runt_err++; + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_TX, + "u=%u, txch=%u, pdma pkt over size\n", unit, channel);; + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR); + ptr_tx_cb->cnt.channel[channel].ovsz_err++; + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma len mismatch err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR); + ptr_tx_cb->cnt.channel[channel].len_mismatch_err++; + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma pkt buf dma read err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR); + ptr_tx_cb->cnt.channel[channel].pktpl_dma_read_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_COS_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma tx cos err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_COS_ERROR); + ptr_tx_cb->cnt.channel[channel].cos_err++; + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd num > 255 err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_gt255_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PFC)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_TX, + "u=%u, txch=%u, pdma flow ctrl\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PFC); + ptr_tx_cb->cnt.channel[channel].pfc++; + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma credit underflow err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR); + ptr_tx_cb->cnt.channel[channel].credit_udfl_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_TX), + "u=%u, txch=%u, pdma dma write err\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR); + ptr_tx_cb->cnt.channel[channel].dma_write_err++; + _hal_dawn_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_TX, + "u=%u, txch=%u, pdma stop done\n", unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + ptr_tx_cb->cnt.channel[channel].sw_issue_stop++; + } + if (0 != isr_status) + { + _hal_dawn_pkt_unmaskAllTxL2IsrReg(unit, channel); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_handleRxL2Isr + * PURPOSE: + * To handle the RX L2 interrupt according to the ISR status. + * INPUT: + * unit -- The unit ID + * channel -- The channel where the interrupt occurs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the L2 interrupt. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_handleRxL2Isr( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_T isr_status = 0x0; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + + osal_mdc_readPciReg(unit, + HAL_DAWN_PKT_GET_PDMA_RCH_REG(HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_RCH_INT_STAT), channel), + &isr_status, sizeof(isr_status)); + + _hal_dawn_pkt_maskAllRxL2IsrReg(unit, channel); + + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma avbl gpd low\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW); + ptr_rx_cb->cnt.channel[channel].avbl_gpd_low++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma avbl gpd empty\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY); + ptr_rx_cb->cnt.channel[channel].avbl_gpd_empty++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma avbl gpd err\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR); + ptr_rx_cb->cnt.channel[channel].avbl_gpd_err++; + _hal_dawn_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma gpd chksum err\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR); + ptr_rx_cb->cnt.channel[channel].gpd_chksm_err++; + _hal_dawn_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma dma read err\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR); + ptr_rx_cb->cnt.channel[channel].dma_read_err++; + _hal_dawn_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma dma write err\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR); + ptr_rx_cb->cnt.channel[channel].dma_write_err++; + _hal_dawn_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma stop done\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + ptr_rx_cb->cnt.channel[channel].sw_issue_stop++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma gpd num > 255 err\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR); + ptr_rx_cb->cnt.channel[channel].gpd_gt255_err++; + _hal_dawn_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma tod ununit err\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT); + ptr_rx_cb->cnt.channel[channel].tod_uninit++; + _hal_dawn_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP)) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_RX), + "u=%u, rxch=%u, pdma pkt err drop\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP); + ptr_rx_cb->cnt.channel[channel].pkt_err_drop++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma pkt under size\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP); + ptr_rx_cb->cnt.channel[channel].udsz_drop++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma pkt over size\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP); + ptr_rx_cb->cnt.channel[channel].ovsz_drop++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma cmdq overflow\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP); + ptr_rx_cb->cnt.channel[channel].cmdq_ovf_drop++; + } + if (0 != (isr_status & HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, pdma fifo overflow\n", unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP); + ptr_rx_cb->cnt.channel[channel].fifo_ovf_drop++; + } + if (0 != isr_status) + { + _hal_dawn_pkt_unmaskAllRxL2IsrReg(unit, channel); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_handleErrorTask + * PURPOSE: + * To invoke the corresponding handler for the L2 interrupts. + * INPUT: + * ptr_argv -- The unit ID + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_dawn_pkt_handleErrorTask( + void *ptr_argv) +{ + UI32_T unit = (UI32_T)((CLX_HUGE_T)ptr_argv); + HAL_DAWN_PKT_L2_ISR_T isr_status = 0x0; + + osal_initRunThread(); + do + { + /* receive Error-ISR */ + osal_waitEvent(HAL_DAWN_PKT_ERR_EVENT(unit)); + if (CLX_E_OK != osal_isRunThread()) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, + "u=%u, err task destroyed\n", unit); + break; /* deinit-thread */ + } + + osal_mdc_readPciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_STAT), + &isr_status, sizeof(UI32_T)); + + if (0 != (HAL_DAWN_PKT_L2_ISR_RCH0 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, rxch=0, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleRxL2Isr(unit, HAL_DAWN_PKT_RX_CHANNEL_0); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_RCH1 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, rxch=1, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleRxL2Isr(unit, HAL_DAWN_PKT_RX_CHANNEL_1); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_RCH2 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, rxch=2, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleRxL2Isr(unit, HAL_DAWN_PKT_RX_CHANNEL_2); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_RCH3 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, rxch=3, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleRxL2Isr(unit, HAL_DAWN_PKT_RX_CHANNEL_3); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_TCH0 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, txch=0, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleTxL2Isr(unit, HAL_DAWN_PKT_TX_CHANNEL_0); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_TCH1 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, txch=1, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleTxL2Isr(unit, HAL_DAWN_PKT_TX_CHANNEL_1); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_TCH2 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, txch=2, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleTxL2Isr(unit, HAL_DAWN_PKT_TX_CHANNEL_2); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_TCH3 & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, txch=3, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_dawn_pkt_handleTxL2Isr(unit, HAL_DAWN_PKT_TX_CHANNEL_3); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_RX_QID_MAP_ERR & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, rcv rx qid map err isr, status=0x%x\n", + unit, isr_status); + } + if (0 != (HAL_DAWN_PKT_L2_ISR_RX_FRAME_ERR & isr_status)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, rcv rx frame err isr, status=0x%x\n", + unit, isr_status); + } + if (0 != isr_status) + { + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_CLR), + &isr_status, sizeof(UI32_T)); + + _hal_dawn_pkt_unmaskIntr(unit, HAL_DAWN_PKT_ERR_REG(unit)); + } + + } while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +/* FUNCTION NAME: _hal_dawn_pkt_handleTxDoneTask + * PURPOSE: + * To handle the TX done interrupt for the specified TX channel. + * INPUT: + * ptr_argv -- The unit ID and channel ID + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_dawn_pkt_handleTxDoneTask( + void *ptr_argv) +{ + /* cookie or index */ + UI32_T unit = ((HAL_DAWN_PKT_ISR_COOKIE_T *)ptr_argv)->unit; + HAL_DAWN_PKT_TX_CHANNEL_T channel = (HAL_DAWN_PKT_TX_CHANNEL_T) + ((HAL_DAWN_PKT_ISR_COOKIE_T *)ptr_argv)->channel; + /* control block */ + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + UI32_T first_gpd_idx = 0; /* To record the first GPD */ + UI32_T loop_cnt = 0; + CLX_IRQ_FLAGS_T irg_flags; + unsigned long timeout = 0; + UI32_T bulk_pkt_cnt = 0, idx; + + osal_initRunThread(); + do + { + /* receive Tx-Done-ISR */ + osal_waitEvent(HAL_DAWN_PKT_TCH_EVENT(unit, channel)); + if (CLX_E_OK != osal_isRunThread()) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_TX, + "u=%u, txch=%u, tx done task destroyed\n", unit, channel); + break; /* deinit-thread */ + } + + /* protect Tx PDMA + * for sync-intr, the sema is locked by sendGpd + */ + if (HAL_DAWN_PKT_TX_WAIT_SYNC_INTR != ptr_tx_cb->wait_mode) + { + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + } + + loop_cnt = ptr_tx_pdma->used_gpd_num; + while (loop_cnt > 0) + { + ptr_tx_gpd = HAL_DAWN_PKT_GET_TX_GPD_PTR(unit, channel, ptr_tx_pdma->free_idx); + osal_dma_invalidateCache((void *)ptr_tx_gpd, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + /* If hwo=HW, it might be: + * 1. err_flag=TRUE -> HW breakdown -> enque and recover -> break + * 2. err_flag=FALSE -> HW busy -> break + */ + if (HAL_DAWN_PKT_HWO_HW_OWN == ptr_tx_gpd->hwo) + { + if (TRUE == ptr_tx_pdma->err_flag) + { + /* flush the incomplete Tx packet */ + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + for (idx = 0; idx < ptr_tx_pdma->gpd_num; idx++) + { + if (NULL != ptr_tx_pdma->pptr_sw_gpd_ring[idx]) + { + ptr_tx_pdma->pptr_sw_gpd_bulk[bulk_pkt_cnt] + = ptr_tx_pdma->pptr_sw_gpd_ring[idx]; + ptr_tx_pdma->pptr_sw_gpd_ring[idx] = NULL; + bulk_pkt_cnt++; + } + } + } + + /* do error recover */ + first_gpd_idx = 0; + if (CLX_E_OK == _hal_dawn_pkt_recoverTxPdma(unit, channel)) + { + ptr_tx_pdma->err_flag = FALSE; + ptr_tx_cb->cnt.channel[channel].err_recover++; + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_TX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, txch=%u, err recover failed\n", + unit, channel); + } + } + else + { + } + break; + } + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* If hwo=SW and ch=0, record the head of sw gpd in bulk buf */ + if (HAL_DAWN_PKT_CH_LAST_GPD == ptr_tx_gpd->ch) + { + ptr_tx_pdma->pptr_sw_gpd_bulk[bulk_pkt_cnt] + = ptr_tx_pdma->pptr_sw_gpd_ring[first_gpd_idx]; + + bulk_pkt_cnt++; + ptr_tx_pdma->pptr_sw_gpd_ring[first_gpd_idx] = NULL; + + /* next SW-GPD must be the head of another PKT->SW-GPD */ + first_gpd_idx = ptr_tx_pdma->free_idx + 1; + first_gpd_idx %= ptr_tx_pdma->gpd_num; + } + } + + if (HAL_DAWN_PKT_ECC_ERROR_OCCUR == ptr_tx_gpd->ecce) + { + ptr_tx_cb->cnt.channel[channel].ecc_err++; + } + + /* update Tx PDMA */ + ptr_tx_pdma->free_idx++; + ptr_tx_pdma->free_idx %= ptr_tx_pdma->gpd_num; + ptr_tx_pdma->used_gpd_num--; + ptr_tx_pdma->free_gpd_num++; + loop_cnt--; + } + + /* let the netdev resume Tx */ + _hal_dawn_pkt_resumeAllIntf(unit); + + /* update ISR and counter */ + ptr_tx_cb->cnt.channel[channel].tx_done++; + + _hal_dawn_pkt_unmaskIntr(unit, HAL_DAWN_PKT_TCH_REG(unit, channel)); + + if (HAL_DAWN_PKT_TX_WAIT_SYNC_INTR != ptr_tx_cb->wait_mode) + { + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + } + else + { + osal_giveSemaphore(&ptr_tx_pdma->sync_intr_sema); + } + + /* enque packet after releasing the spinlock */ + _hal_dawn_pkt_txEnQueueBulk(unit, channel, bulk_pkt_cnt); + bulk_pkt_cnt = 0; + + /* prevent this task from executing too long */ + if (!(time_before(jiffies, timeout))) + { + schedule(); + timeout = jiffies + 1; /* continuously free tx descriptor for 1 tick */ + } + + } while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +/* FUNCTION NAME: _hal_dawn_pkt_handleRxDoneTask + * PURPOSE: + * To handle the RX done interrupt for the specified RX channel. + * INPUT: + * ptr_argv -- The unit ID and channel ID + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_dawn_pkt_handleRxDoneTask( + void *ptr_argv) +{ + /* cookie or index */ + UI32_T unit = ((HAL_DAWN_PKT_ISR_COOKIE_T *)ptr_argv)->unit; + HAL_DAWN_PKT_RX_CHANNEL_T channel = (HAL_DAWN_PKT_RX_CHANNEL_T) + ((HAL_DAWN_PKT_ISR_COOKIE_T *)ptr_argv)->channel; + + /* control block */ + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_DAWN_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + + BOOL_T first = TRUE; + BOOL_T last = FALSE; + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_gpd = NULL; + HAL_DAWN_PKT_RX_SW_GPD_T *ptr_sw_first_gpd = NULL; + UI32_T loop_cnt = 0; + unsigned long timeout = 0; + + osal_initRunThread(); + do + { + /* receive Rx-Done-ISR */ + osal_waitEvent(HAL_DAWN_PKT_RCH_EVENT(unit, channel)); + if (CLX_E_OK != osal_isRunThread()) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_RX, + "u=%u, rxch=%u, rx done task destroyed\n", unit, channel); + break; /* deinit-thread */ + } + + /* check if Rx-system is inited */ + if (0 == ptr_rx_cb->buf_len) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rxch=%u, rx gpd buf len=0\n", + unit, channel); + continue; + } + + /* protect Rx PDMA */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + loop_cnt = ptr_rx_pdma->gpd_num; + while (loop_cnt > 0) + { + ptr_rx_gpd = HAL_DAWN_PKT_GET_RX_GPD_PTR(unit, channel, ptr_rx_pdma->cur_idx); + osal_dma_invalidateCache((void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + /* If hwo=HW, it might be: + * 1. err_flag=TRUE -> HW breakdown -> enque and recover -> break + * 2. err_flag=FALSE -> HW busy -> break + */ + if (HAL_DAWN_PKT_HWO_HW_OWN == ptr_rx_gpd->hwo) + { + if (TRUE == ptr_rx_pdma->err_flag) + { + /* free the last incomplete Rx packet */ + if ((NULL != ptr_sw_first_gpd) && + (NULL != ptr_sw_gpd)) + { + ptr_sw_gpd->ptr_next = NULL; + ptr_sw_first_gpd->rx_complete = FALSE; + _hal_dawn_pkt_rxEnQueue(unit, channel, ptr_sw_first_gpd); + ptr_sw_first_gpd = NULL; + } + + /* do error recover */ + first = TRUE; + last = FALSE; + if (CLX_E_OK == _hal_dawn_pkt_recoverRxPdma(unit, channel)) + { + ptr_rx_pdma->err_flag = FALSE; + ptr_rx_cb->cnt.channel[channel].err_recover++; + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rxch=%u, err recover failed\n", + unit, channel); + } + } + else + { + } + break; + } + + /* Move HW-GPD to SW-GPD and append to a link-list */ + if (TRUE == first) + { + ptr_sw_first_gpd = (HAL_DAWN_PKT_RX_SW_GPD_T *)osal_alloc(sizeof(HAL_DAWN_PKT_RX_SW_GPD_T)); + ptr_sw_gpd = ptr_sw_first_gpd; + if (NULL != ptr_sw_gpd) + { + memcpy(&ptr_sw_gpd->rx_gpd, (void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + first = FALSE; + } + else + { + ptr_rx_cb->cnt.no_memory++; + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rxch=%u, alloc 1st sw gpd failed, size=%zu\n", + unit, channel, sizeof(HAL_DAWN_PKT_RX_SW_GPD_T)); + break; + } + } + else + { + ptr_sw_gpd->ptr_next = (HAL_DAWN_PKT_RX_SW_GPD_T *)osal_alloc(sizeof(HAL_DAWN_PKT_RX_SW_GPD_T)); + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + if (NULL != ptr_sw_gpd) + { + memcpy(&ptr_sw_gpd->rx_gpd, (void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + } + else + { + ptr_rx_cb->cnt.no_memory++; + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_RX | HAL_DAWN_PKT_DBG_ERR), + "u=%u, rxch=%u, alloc mid sw gpd failed, size=%zu\n", + unit, channel, sizeof(HAL_DAWN_PKT_RX_SW_GPD_T)); + break; + } + } + + ptr_sw_gpd->ptr_cookie = ptr_rx_pdma->pptr_skb_ring[ptr_rx_pdma->cur_idx]; + + /* If hwo=SW and ch=0, enque SW-GPD and signal rxTask */ + if (HAL_DAWN_PKT_CH_LAST_GPD == ptr_rx_gpd->ch) + { + last = TRUE; + } + + /* If hwo=SW and ch=*, re-alloc-buf and resume */ + while (CLX_E_OK != _hal_dawn_pkt_allocRxPayloadBuf(unit, channel, ptr_rx_pdma->cur_idx)) + { + ptr_rx_cb->cnt.no_memory++; + HAL_DAWN_PKT_ALLOC_MEM_RETRY_SLEEP(); + } + ptr_rx_gpd->ioc = HAL_DAWN_PKT_IOC_HAS_INTR; + ptr_rx_gpd->hwo = HAL_DAWN_PKT_HWO_HW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + /* Enque the SW-GPD to rxTask */ + if (TRUE == last) + { + ptr_sw_gpd->ptr_next = NULL; + ptr_sw_first_gpd->rx_complete = TRUE; + _hal_dawn_pkt_rxEnQueue(unit, channel, ptr_sw_first_gpd); + ptr_sw_first_gpd = NULL; + + /* To rebuild the SW GPD link list */ + first = TRUE; + last = FALSE; + } + + _hal_dawn_pkt_resumeRxChannelReg(unit, channel, 1); + + /* update Rx PDMA */ + ptr_rx_pdma->cur_idx++; + ptr_rx_pdma->cur_idx %= ptr_rx_pdma->gpd_num; + loop_cnt--; + } + + osal_giveSemaphore(&ptr_rx_pdma->sema); + + /* update ISR and counter */ + ptr_rx_cb->cnt.channel[channel].rx_done++; + + _hal_dawn_pkt_unmaskIntr(unit, HAL_DAWN_PKT_RCH_REG(unit, channel)); + + /* prevent this task from executing too long */ + if (!(time_before(jiffies, timeout))) + { + schedule(); + timeout = jiffies + 1; /* continuously rx for 1 tick */ + } + + } while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +static void +_hal_dawn_pkt_net_dev_tx_callback( + const UI32_T unit, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd, + struct sk_buff *ptr_skb) +{ + CLX_ADDR_T phy_addr = 0; + + /* unmap dma */ + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->tx_gpd.data_buf_addr_hi, ptr_sw_gpd->tx_gpd.data_buf_addr_lo); + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_TO_DEVICE); + + /* free skb */ + osal_skb_free(ptr_skb); + + /* free gpd */ + osal_free(ptr_sw_gpd); +} + +/* FUNCTION NAME: hal_dawn_pkt_initTask + * PURPOSE: + * To initialize the Task for packet module. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dinitialize the control block. + * CLX_E_OTHERS -- Initialize the control block failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_initTask( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + UI32_T channel = 0; + + if (0 != (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_TASK)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, pkt task init failed, not inited\n", unit); + return (rc); + } + + /* Init handleErrorTask */ + rc = osal_createThread("ERROR", HAL_DFLT_CFG_PKT_ERROR_ISR_THREAD_STACK, + HAL_DFLT_CFG_PKT_ERROR_ISR_THREAD_PRI, _hal_dawn_pkt_handleErrorTask, + (void *)((CLX_HUGE_T)unit), &ptr_cb->err_task_id); + + /* Init handleTxDoneTask */ + for (channel = 0; ((channel < HAL_DAWN_PKT_TX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + ptr_tx_cb->isr_task_cookie[channel].unit = unit; + ptr_tx_cb->isr_task_cookie[channel].channel = channel; + + rc = osal_createThread("TX_ISR", HAL_DFLT_CFG_PKT_TX_ISR_THREAD_STACK, + HAL_DFLT_CFG_PKT_TX_ISR_THREAD_PRI, _hal_dawn_pkt_handleTxDoneTask, + (void *)&ptr_tx_cb->isr_task_cookie[channel], + &ptr_tx_cb->isr_task_id[channel]); + } + + /* Init handleRxDoneTask */ + for (channel = 0; ((channel < HAL_DAWN_PKT_RX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + ptr_rx_cb->isr_task_cookie[channel].unit = unit; + ptr_rx_cb->isr_task_cookie[channel].channel = channel; + + rc = osal_createThread("RX_ISR", HAL_DFLT_CFG_PKT_RX_ISR_THREAD_STACK, + HAL_DFLT_CFG_PKT_RX_ISR_THREAD_PRI, _hal_dawn_pkt_handleRxDoneTask, + (void *)&ptr_rx_cb->isr_task_cookie[channel], + &ptr_rx_cb->isr_task_id[channel]); + } + + /* Init txTask */ + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + ptr_tx_cb->running = TRUE; + } + + ptr_cb->init_flag |= HAL_DAWN_PKT_INIT_TASK; + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, + "u=%u, pkt task init done, init flag=0x%x\n", unit, ptr_cb->init_flag); + + /* For some specail case in warmboot, the netifs are not destroyed during sdk deinit + * but stopped, here we need to resume them with the original carrier status + */ + _hal_dawn_pkt_resumeAllIntf(unit); + + ptr_tx_cb->net_tx_allowed = TRUE; + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initTxPdma + * PURPOSE: + * To initialize the TX PDMA. + * INPUT: + * unit -- The unit ID + * channel -- The target Tx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the TX PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initTxPdma( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_DAWN_PKT_GET_TX_PDMA_PTR(unit, channel); + CLX_IRQ_FLAGS_T irg_flags; + + /* Isr lock to protect Tx PDMA */ + osal_createIsrLock("TCH_LCK", &ptr_tx_pdma->ring_lock); + + if (HAL_DAWN_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + /* Sync semaphore to signal sendTxPacket */ + osal_createSemaphore("TCH_SYN", CLX_SEMAPHORE_SYNC, &ptr_tx_pdma->sync_intr_sema); + } + + /* Reset Tx PDMA */ + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + + ptr_tx_pdma->used_idx = 0; + ptr_tx_pdma->free_idx = 0; + ptr_tx_pdma->used_gpd_num = 0; + ptr_tx_pdma->free_gpd_num = HAL_DFLT_CFG_PKT_TX_GPD_NUM; + ptr_tx_pdma->gpd_num = HAL_DFLT_CFG_PKT_TX_GPD_NUM; + + /* Prepare the HW-GPD ring */ + ptr_tx_pdma->ptr_gpd_start_addr = (HAL_DAWN_PKT_TX_GPD_T *)osal_dma_alloc( + (ptr_tx_pdma->gpd_num + 1) * sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + if (NULL != ptr_tx_pdma->ptr_gpd_start_addr) + { + osal_memset(ptr_tx_pdma->ptr_gpd_start_addr, 0x0, + (ptr_tx_pdma->gpd_num + 1) * sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + ptr_tx_pdma->ptr_gpd_align_start_addr = (HAL_DAWN_PKT_TX_GPD_T *)HAL_DAWN_PKT_PDMA_ALIGN_ADDR( + (CLX_HUGE_T)ptr_tx_pdma->ptr_gpd_start_addr, sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + rc = _hal_dawn_pkt_initTxPdmaRing(unit, channel); + if (CLX_E_OK == rc) + { + _hal_dawn_pkt_startTxChannelReg(unit, channel, 0); + } + } + else + { + ptr_tx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + if (CLX_E_OK == rc) + { + /* Prepare the SW-GPD ring */ + ptr_tx_pdma->pptr_sw_gpd_ring = (HAL_DAWN_PKT_TX_SW_GPD_T **)osal_alloc( + ptr_tx_pdma->gpd_num * sizeof(HAL_DAWN_PKT_TX_SW_GPD_T *)); + + if (NULL != ptr_tx_pdma->pptr_sw_gpd_ring) + { + osal_memset(ptr_tx_pdma->pptr_sw_gpd_ring, 0x0, + ptr_tx_pdma->gpd_num * sizeof(HAL_DAWN_PKT_TX_SW_GPD_T *)); + } + else + { + ptr_tx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + + /* a temp buffer to store the 1st sw gpd for each packet to be enque + * we cannot enque packet before release a spinlock + */ + ptr_tx_pdma->pptr_sw_gpd_bulk = (HAL_DAWN_PKT_TX_SW_GPD_T **)osal_alloc( + ptr_tx_pdma->gpd_num * sizeof(HAL_DAWN_PKT_TX_SW_GPD_T *)); + + if (NULL != ptr_tx_pdma->pptr_sw_gpd_bulk) + { + osal_memset(ptr_tx_pdma->pptr_sw_gpd_bulk, 0x0, + ptr_tx_pdma->gpd_num * sizeof(HAL_DAWN_PKT_TX_SW_GPD_T *)); + } + else + { + ptr_tx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + } + } + + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initRxPdma + * PURPOSE: + * To initialize the RX PDMA. + * INPUT: + * unit -- The unit ID + * channel -- The target Rx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the RX PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initRxPdma( + const UI32_T unit, + const HAL_DAWN_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_DAWN_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Binary semaphore to protect Rx PDMA */ + osal_createSemaphore("RCH_LCK", CLX_SEMAPHORE_BINARY, &ptr_rx_pdma->sema); + + /* Reset Rx PDMA */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + ptr_rx_pdma->cur_idx = 0; + ptr_rx_pdma->gpd_num = HAL_DFLT_CFG_PKT_RX_GPD_NUM; + + /* Prepare the HW-GPD ring */ + ptr_rx_pdma->ptr_gpd_start_addr = (HAL_DAWN_PKT_RX_GPD_T *)osal_dma_alloc( + (ptr_rx_pdma->gpd_num + 1) * sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + if (NULL != ptr_rx_pdma->ptr_gpd_start_addr) + { + osal_memset(ptr_rx_pdma->ptr_gpd_start_addr, 0, + (ptr_rx_pdma->gpd_num + 1) * sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + ptr_rx_pdma->ptr_gpd_align_start_addr = (HAL_DAWN_PKT_RX_GPD_T *)HAL_DAWN_PKT_PDMA_ALIGN_ADDR( + (CLX_HUGE_T)ptr_rx_pdma->ptr_gpd_start_addr, sizeof(HAL_DAWN_PKT_RX_GPD_T)); + + /* will initRxPdmaRingBuf and start RCH after setRxConfig */ + rc = _hal_dawn_pkt_initRxPdmaRing(unit, channel); + } + else + { + ptr_rx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + + if (CLX_E_OK == rc) + { + /* Prepare the SKB ring */ + ptr_rx_pdma->pptr_skb_ring = (struct sk_buff **)osal_alloc( + ptr_rx_pdma->gpd_num * sizeof(struct sk_buff *)); + + if (NULL != ptr_rx_pdma->pptr_skb_ring) + { + osal_memset(ptr_rx_pdma->pptr_skb_ring, 0x0, + ptr_rx_pdma->gpd_num * sizeof(struct sk_buff *)); + } + else + { + ptr_rx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + } + + osal_giveSemaphore(&ptr_rx_pdma->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initPktCb + * PURPOSE: + * To initialize the control block of Drv. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initPktCb( + const UI32_T unit) +{ + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + UI32_T idx = 0, vec = sizeof(_hal_dawn_pkt_intr_vec) / sizeof(HAL_DAWN_PKT_INTR_VEC_T); + + osal_memset(ptr_cb, 0x0, sizeof(HAL_DAWN_PKT_DRV_CB_T)); + + /* Register PKT interrupt functions */ + osal_createIsrLock("ISR_LOCK", &ptr_cb->intr_lock); + osal_mdc_registerIsr(unit, _hal_dawn_pkt_dispatcher, (void *)((CLX_HUGE_T)unit)); + + for (idx = 0; idx < vec; idx++) + { + osal_createEvent("ISR_EVENT", &_hal_dawn_pkt_intr_vec[idx].intr_event); + ptr_cb->intr_bitmap |= (_hal_dawn_pkt_intr_vec[idx].intr_reg); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initPktTxCb + * PURPOSE: + * To initialize the control block of Rx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control block. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initPktTxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + HAL_DAWN_PKT_TX_CHANNEL_T channel = 0; + + osal_memset(ptr_tx_cb, 0x0, sizeof(HAL_DAWN_PKT_TX_CB_T)); + + ptr_tx_cb->wait_mode = HAL_DAWN_PKT_TX_WAIT_MODE; + + if (HAL_DAWN_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* Sync semaphore to signal txTask */ + osal_createEvent("TX_SYNC", &ptr_tx_cb->sync_sema); + + /* Initialize Tx GPD-queue (of first SW-GPD) from handleTxDoneTask to txTask */ + ptr_tx_cb->sw_queue.len = HAL_DFLT_CFG_PKT_TX_QUEUE_LEN; + ptr_tx_cb->sw_queue.weight = 0; + + osal_createSemaphore("TX_QUE", CLX_SEMAPHORE_BINARY, &ptr_tx_cb->sw_queue.sema); + osal_que_create(&ptr_tx_cb->sw_queue.que_id, ptr_tx_cb->sw_queue.len); + } + else if (HAL_DAWN_PKT_TX_WAIT_SYNC_POLL == ptr_tx_cb->wait_mode) + { + /* Disable TX done ISR. */ + for (channel = 0; channel < HAL_DAWN_PKT_TX_CHANNEL_LAST; channel++) + { + _hal_dawn_pkt_disableIntr(unit, HAL_DAWN_PKT_TCH_REG(unit, channel)); + } + } + + /* Init Tx PDMA */ + for (channel = 0; ((channel < HAL_DAWN_PKT_TX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + rc = _hal_dawn_pkt_initTxPdma(unit, channel); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initPktRxCb + * PURPOSE: + * To initialize the control block of Rx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control block. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initPktRxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_DAWN_PKT_RX_CB_T *ptr_rx_cb = HAL_DAWN_PKT_GET_RX_CB_PTR(unit); + HAL_DAWN_PKT_RX_CHANNEL_T channel = 0; + UI32_T queue = 0; + + osal_memset(ptr_rx_cb, 0x0, sizeof(HAL_DAWN_PKT_RX_CB_T)); + + ptr_rx_cb->sched_mode = HAL_DFLT_CFG_PKT_RX_SCHED_MODE; + + /* Sync semaphore to signal rxTask */ + osal_createEvent("RX_SYNC", &ptr_rx_cb->sync_sema); + + /* Initialize Rx GPD-queue (of first SW-GPD) from handleRxDoneTask to rxTask */ + for (queue = 0; ((queue < HAL_DAWN_PKT_RX_QUEUE_NUM) && (CLX_E_OK == rc)); queue++) + { + ptr_rx_cb->sw_queue[queue].len = HAL_DFLT_CFG_PKT_RX_QUEUE_LEN; + ptr_rx_cb->sw_queue[queue].weight = HAL_DFLT_CFG_PKT_RX_QUEUE_WEIGHT; + + osal_createSemaphore("RX_QUE", CLX_SEMAPHORE_BINARY, &ptr_rx_cb->sw_queue[queue].sema); + osal_que_create(&ptr_rx_cb->sw_queue[queue].que_id, ptr_rx_cb->sw_queue[queue].len); + } + + /* Init Rx PDMA */ + for (channel = 0; ((channel < HAL_DAWN_PKT_RX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + rc = _hal_dawn_pkt_initRxPdma(unit, channel); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initL1Isr + * PURPOSE: + * To initialize the PDMA L1 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the L1 ISR. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initL1Isr( + const UI32_T unit) +{ + UI32_T idx = 0, vec = sizeof(_hal_dawn_pkt_intr_vec) / sizeof(HAL_DAWN_PKT_INTR_VEC_T); + + for (idx = 0; idx < vec; idx++) + { + _hal_dawn_pkt_enableIntr(unit, _hal_dawn_pkt_intr_vec[idx].intr_reg); + _hal_dawn_pkt_unmaskIntr(unit, _hal_dawn_pkt_intr_vec[idx].intr_reg); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_dawn_pkt_initL2Isr + * PURPOSE: + * To initialize the PDMA L2 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure for the L2 ISR. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_dawn_pkt_initL2Isr( + const UI32_T unit) +{ + HAL_DAWN_PKT_L2_ISR_T isr_status = 0x0; + + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH0); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH1); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH2); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RCH3); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH0); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH1); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH2); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_TCH3); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RX_QID_MAP_ERR); + HAL_DAWN_PKT_SET_BITMAP(isr_status, HAL_DAWN_PKT_L2_ISR_RX_FRAME_ERR); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_EN), + &isr_status, sizeof(UI32_T)); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_MASK_SET), + &isr_status, sizeof(UI32_T)); + + return (CLX_E_OK); + +} + +CLX_ERROR_NO_T +_hal_dawn_pkt_resetIosCreditCfg( + const UI32_T unit) +{ +#define HAL_DAWN_PKT_PDMA_CREDIT_CFG_RESET_OFFSET (16) + + UI32_T credit_cfg = 0x0; + UI32_T idx; + + for (idx=0; idxptr_profile = ptr_new_profile; + + /* Create the 1st node in the interface profile list */ + if (NULL == *pptr_profile_list) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "prof list empty\n"); + *pptr_profile_list = ptr_new_prof_node; + ptr_new_prof_node->ptr_next_node = NULL; + } + else + { + ptr_prev_node = *pptr_profile_list; + ptr_curr_node = *pptr_profile_list; + + while (ptr_curr_node != NULL) + { + if (ptr_curr_node->ptr_profile->priority <= ptr_new_profile->priority) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "find prof id=%d (%s) higher priority=%d, search next\n", + ptr_curr_node->ptr_profile->id, + ptr_curr_node->ptr_profile->name, + ptr_curr_node->ptr_profile->priority); + /* Search the next node */ + ptr_prev_node = ptr_curr_node; + ptr_curr_node = ptr_curr_node->ptr_next_node; + } + else + { + /* Insert intermediate node */ + ptr_new_prof_node->ptr_next_node = ptr_curr_node; + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "insert prof id=%d (%s) before prof id=%d (%s) (priority=%d >= %d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_curr_node->ptr_profile->id, + ptr_curr_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority, + ptr_curr_node->ptr_profile->priority); + + if (ptr_prev_node == ptr_curr_node) + { + /* There is no previous node: change the root */ + *pptr_profile_list = ptr_new_prof_node; + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "insert prof id=%d (%s) to head (priority=%d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority); + } + else + { + ptr_prev_node->ptr_next_node = ptr_new_prof_node; + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "insert prof id=%d (%s) after prof id=%d (%s) (priority=%d <= %d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_prev_node->ptr_profile->id, + ptr_prev_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority, + ptr_prev_node->ptr_profile->priority); + } + + return (CLX_E_OK); + } + } + + /* Insert node to the tail of list */ + ptr_prev_node->ptr_next_node = ptr_new_prof_node; + ptr_new_prof_node->ptr_next_node = NULL; + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "insert prof id=%d (%s) to tail, after prof id=%d (%s) (priority=%d <= %d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_prev_node->ptr_profile->id, + ptr_prev_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority, + ptr_prev_node->ptr_profile->priority); + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_addProfToAllIntf( + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_new_profile) +{ + UI32_T port; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + /* Shall we check if the interface is ever created on the port?? */ + /* if (NULL != ptr_port_db->ptr_net_dev) */ + if (1) + { + _hal_dawn_pkt_addProfToList(ptr_new_profile, &ptr_port_db->ptr_profile_list); + } + } + + return (CLX_E_OK); +} + +static HAL_DAWN_PKT_NETIF_PROFILE_T * +_hal_dawn_pkt_delProfFromListById( + const UI32_T id, + HAL_DAWN_PKT_PROFILE_NODE_T **pptr_profile_list) +{ + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_temp_node; + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_curr_node, *ptr_prev_node; + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile = NULL;; + + if (NULL != *pptr_profile_list) + { + /* Check the 1st node */ + if (id == (*pptr_profile_list)->ptr_profile->id) + { + ptr_profile = (*pptr_profile_list)->ptr_profile; + ptr_temp_node = (*pptr_profile_list); + (*pptr_profile_list) = ptr_temp_node->ptr_next_node; + + if (NULL != ptr_temp_node->ptr_next_node) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "choose prof id=%d (%s) as new head\n", + ptr_temp_node->ptr_next_node->ptr_profile->id, + ptr_temp_node->ptr_next_node->ptr_profile->name); + } + else + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "prof list is empty\n"); + } + + + osal_free(ptr_temp_node); + } + else + { + ptr_prev_node = *pptr_profile_list; + ptr_curr_node = ptr_prev_node->ptr_next_node; + + while (NULL != ptr_curr_node) + { + if (id != ptr_curr_node->ptr_profile->id) + { + ptr_prev_node = ptr_curr_node; + ptr_curr_node = ptr_curr_node->ptr_next_node; + } + else + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "find prof id=%d, free done\n", id); + + ptr_profile = ptr_curr_node->ptr_profile; + ptr_prev_node->ptr_next_node = ptr_curr_node->ptr_next_node; + osal_free(ptr_curr_node); + break; + } + } + } + } + + if (NULL == ptr_profile) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_PROFILE | HAL_DAWN_PKT_DBG_ERR), + "find prof failed, id=%d\n", id); + } + + return (ptr_profile); +} + + +static CLX_ERROR_NO_T +_hal_dawn_pkt_delProfFromAllIntfById( + const UI32_T id) +{ + UI32_T port; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + /* Shall we check if the interface is ever created on the port?? */ + /* if (NULL != ptr_port_db->ptr_net_dev) */ + if (1) + { + _hal_dawn_pkt_delProfFromListById(id, &ptr_port_db->ptr_profile_list); + } + } + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_allocProfEntry( + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile) +{ + UI32_T idx; + + for (idx=0; idxid = idx; + return (CLX_E_OK); + } + } + return (CLX_E_TABLE_FULL); +} + +static HAL_DAWN_PKT_NETIF_PROFILE_T * +_hal_dawn_pkt_freeProfEntry( + const UI32_T id) +{ + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile = NULL; + + if (id < HAL_DAWN_PKT_NET_PROFILE_NUM_MAX) + { + ptr_profile = _ptr_hal_dawn_pkt_profile_entry[id]; + _ptr_hal_dawn_pkt_profile_entry[id] = NULL; + } + + return (ptr_profile); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_destroyAllIntf( + const UI32_T unit) +{ + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + + /* Unregister net devices by id, although the "id" is now relavent to "port" we still perform a search */ + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, + "u=%u, find intf %s (id=%d) on phy port=%d, destroy done\n", + unit, + ptr_port_db->meta.name, + ptr_port_db->meta.port, + ptr_port_db->meta.port); + + netif_tx_disable(ptr_port_db->ptr_net_dev); + unregister_netdev(ptr_port_db->ptr_net_dev); + free_netdev(ptr_port_db->ptr_net_dev); + + /* Don't need to remove profiles on this port. + * In fact, the profile is binding to "port" not "intf". + */ + /* _hal_dawn_pkt_destroyProfList(ptr_port_db->ptr_profile_list); */ + + osal_memset(ptr_port_db, 0x0, sizeof(HAL_DAWN_PKT_NETIF_PORT_DB_T)); + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_delProfListOnAllIntf( + const UI32_T unit) +{ + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_curr_node, *ptr_next_node; + + /* Unregister net devices by id, although the "id" is now relavent to "port" we still perform a search */ + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_profile_list) /* valid intf */ + { + ptr_curr_node = ptr_port_db->ptr_profile_list; + while (NULL != ptr_curr_node) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "u=%u, del prof id=%d on phy port=%d\n", + unit, ptr_curr_node->ptr_profile->id, port); + + ptr_next_node = ptr_curr_node->ptr_next_node; + osal_free(ptr_curr_node); + ptr_curr_node = ptr_next_node; + } + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_destroyAllProfile( + const UI32_T unit) +{ + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile; + UI32_T prof_id; + + _hal_dawn_pkt_delProfListOnAllIntf(unit); + + for (prof_id=0; prof_idid, + ptr_profile->name, + ptr_profile->priority, + ptr_profile->flags); + osal_free(ptr_profile); + } + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_dawn_pkt_initPktDrv + * PURPOSE: + * To invoke the functions to initialize the control block for each + * PDMA subsystem. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control blocks. + * CLX_E_OTHERS -- Initialize the control blocks failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_dawn_pkt_initPktDrv( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T channel = 0; + UI32_T flush_intr = 0x0; + UI32_T clear_intr = 0xffffffff; + HAL_DAWN_PKT_DRV_CB_T *ptr_cb = HAL_DAWN_PKT_GET_DRV_CB_PTR(unit); + + /* There's a case that PDMA Tx is on-going when doing chip reset, + * where PDMA may hang and be not programmable since current Tx packet + * stucks due to IOS credit too low. + * Thus, we always reset IOS credit value before progrmming Tx PDMA. + */ + _hal_dawn_pkt_resetIosCreditCfg(unit); + + /* Since the users may kill SDK application without a de-init flow, + * we help to detect if NETIF is ever init before, and perform deinit. + * (Because the users cannot perform Task init bypassing Drv init, this + * check is required only in here) + */ + if (0 != (ptr_cb->init_flag & HAL_DAWN_PKT_INIT_DRV)) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, init pkt drv failed, inited\n", unit); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, stop rx pkt\n", unit); + _hal_dawn_pkt_rxStop(unit); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, stop all intf\n", unit); + _hal_dawn_pkt_stopAllIntf(unit); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, deinit pkt task\n", unit); + + hal_dawn_pkt_deinitTask(unit); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, deinit pkt drv\n", unit); + hal_dawn_pkt_deinitPktDrv(unit); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, destroy all prof\n", unit); + _hal_dawn_pkt_destroyAllProfile(unit); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, + "u=%u, destroy all intf\n", unit); + _hal_dawn_pkt_destroyAllIntf(unit); + } + + /* [cold-boot] 1. stop DMA channel + * 2. disable/mask/clear the interrupt status. + */ + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_EN), + &flush_intr, sizeof(UI32_T)); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_MASK_SET), + &clear_intr, sizeof(UI32_T)); + + osal_mdc_writePciReg(unit, + HAL_DAWN_PKT_GET_MMIO(HAL_DAWN_PKT_PDMA_ERR_INT_CLR), + &clear_intr, sizeof(UI32_T)); + + for (channel = 0; channel < HAL_DAWN_PKT_TX_CHANNEL_LAST; channel++) + { + _hal_dawn_pkt_stopTxChannelReg(unit, channel); + _hal_dawn_pkt_maskAllTxL2IsrReg(unit, channel); + _hal_dawn_pkt_clearTxL2IsrStatusReg(unit, channel, clear_intr); + } + + for (channel = 0; channel < HAL_DAWN_PKT_RX_CHANNEL_LAST; channel++) + { + _hal_dawn_pkt_stopRxChannelReg(unit, channel); + _hal_dawn_pkt_maskAllRxL2IsrReg(unit, channel); + _hal_dawn_pkt_clearRxL2IsrStatusReg(unit, channel, clear_intr); + } + + rc = _hal_dawn_pkt_initPktCb(unit); + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_initPktTxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_initPktRxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_initL1Isr(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_dawn_pkt_initL2Isr(unit); + } + + /* Set the flag to record init state */ + ptr_cb->init_flag |= HAL_DAWN_PKT_INIT_DRV; + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, + "u=%u, pkt drv init done, init flag=0x%x\n", unit, ptr_cb->init_flag); + + return (rc); +} + +/* ----------------------------------------------------------------------------------- Init: I/O */ +CLX_ERROR_NO_T +hal_dawn_pkt_getNetDev( + const UI32_T unit, + const UI32_T port, + struct net_device **pptr_net_dev) +{ + *pptr_net_dev = HAL_DAWN_PKT_GET_PORT_NETDEV(port); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +hal_dawn_pkt_prepareGpd( + const UI32_T unit, + const CLX_ADDR_T phy_addr, + const UI32_T len, + const UI32_T port, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + /* fill up tx_gpd */ + ptr_sw_gpd->tx_gpd.data_buf_addr_hi = CLX_ADDR_64_HI(phy_addr); + ptr_sw_gpd->tx_gpd.data_buf_addr_lo = CLX_ADDR_64_LOW(phy_addr); + ptr_sw_gpd->tx_gpd.data_buf_size = len; + ptr_sw_gpd->tx_gpd.chksum = 0x0; + ptr_sw_gpd->tx_gpd.ipc = 0; /* Raw mode, sent to plane 0 */ + ptr_sw_gpd->tx_gpd.prg = HAL_DAWN_PKT_PRG_PROCESS_GPD; + ptr_sw_gpd->tx_gpd.hwo = HAL_DAWN_PKT_HWO_HW_OWN; + ptr_sw_gpd->tx_gpd.ch = HAL_DAWN_PKT_CH_LAST_GPD; + ptr_sw_gpd->tx_gpd.ioc = HAL_DAWN_PKT_IOC_HAS_INTR; + ptr_sw_gpd->tx_gpd.pkt_len = len; + ptr_sw_gpd->tx_gpd.crcc = HAL_DAWN_PKT_CRCC_SUM_BY_HW; + + /* fill up cpu header */ + ptr_sw_gpd->tx_gpd.itmh_eth.skip_ipp = 1; + ptr_sw_gpd->tx_gpd.itmh_eth.skip_epp = 1; + ptr_sw_gpd->tx_gpd.itmh_eth.color = 0; /* Green */ + ptr_sw_gpd->tx_gpd.itmh_eth.tc = 15; /* Max tc */ + ptr_sw_gpd->tx_gpd.itmh_eth.igr_phy_port = 0; + + ptr_sw_gpd->tx_gpd.pph_l2.mrk_pcp_val = 7; /* Max pcp */ + ptr_sw_gpd->tx_gpd.pph_l2.mrk_pcp_dei_en = 1; + + /* destination index + * 1. to local ETH port + * 2. to remote ETH port + * 3. to remote CPU + */ + ptr_sw_gpd->tx_gpd.itmh_eth.dst_idx = port; + + /* [CL8360] we should set all-1 for the following fields to skip some tm-logic */ + + /* TM header */ + ptr_sw_gpd->tx_gpd.itmh_eth.src_idx = 0x7fff; + ptr_sw_gpd->tx_gpd.itmh_eth.intf_fdid = 0x3fff; + ptr_sw_gpd->tx_gpd.itmh_eth.src_supp_tag = 0x1f; + ptr_sw_gpd->tx_gpd.itmh_eth.nvo3_mgid = 0x6fff; + ptr_sw_gpd->tx_gpd.itmh_eth.nvo3_src_supp_tag_w0 = 0x1; + ptr_sw_gpd->tx_gpd.itmh_eth.nvo3_src_supp_tag_w1 = 0xf; + + /* PP header */ + ptr_sw_gpd->tx_gpd.pph_l2.nvo3_encap_idx = HAL_INVALID_NVO3_ENCAP_IDX; + ptr_sw_gpd->tx_gpd.pph_l2.nvo3_adj_idx = HAL_INVALID_NVO3_ADJ_IDX; + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Init: net_dev_ops */ +static int +_hal_dawn_pkt_net_dev_init( + struct net_device *ptr_net_dev) +{ + return 0; +} + +static int +_hal_dawn_pkt_net_dev_open( + struct net_device *ptr_net_dev) +{ + netif_start_queue(ptr_net_dev); + +#if defined(PERF_EN_TEST) + /* Tx (len, tx_channel, rx_channel, test_skb) */ + perf_test(64, 1, 0, FALSE); + perf_test(64, 2, 0, FALSE); + perf_test(64, 4, 0, FALSE); + + perf_test(1518, 1, 0, FALSE); + perf_test(1518, 2, 0, FALSE); + perf_test(1518, 4, 0, FALSE); + + perf_test(9216, 1, 0, FALSE); + perf_test(9216, 2, 0, FALSE); + perf_test(9216, 4, 0, FALSE); + + /* Rx (len, tx_channel, rx_channel, test_skb) */ + perf_test(64, 0, 1, FALSE); + perf_test(64, 0, 3, FALSE); + perf_test(64, 0, 4, FALSE); + + perf_test(1518, 0, 1, FALSE); + perf_test(1518, 0, 3, FALSE); + perf_test(1518, 0, 4, FALSE); + + perf_test(9216, 0, 1, FALSE); + perf_test(9216, 0, 3, FALSE); + perf_test(9216, 0, 4, FALSE); +#endif + + return 0; +} + +static int +_hal_dawn_pkt_net_dev_stop( + struct net_device *ptr_net_dev) +{ + netif_stop_queue(ptr_net_dev); + return 0; +} + +static int +_hal_dawn_pkt_net_dev_ioctl( + struct net_device *ptr_net_dev, + struct ifreq *ptr_ifreq, + int cmd) +{ + return 0; +} + +static netdev_tx_t +_hal_dawn_pkt_net_dev_tx( + struct sk_buff *ptr_skb, + struct net_device *ptr_net_dev) +{ + struct net_device_priv *ptr_priv = netdev_priv(ptr_net_dev); + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb; + /* chip meta */ + unsigned int unit; + unsigned int channel = 0; + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd = NULL; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0x0; + + if (NULL == ptr_priv) + { + /* in case that the netdev has been freed/reset somewhere */ + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, "get netdev_priv failed\n"); + return -EFAULT; + } + + /* check skb */ + if (NULL == ptr_skb) + { + ptr_priv->stats.tx_errors++; + return -EFAULT; + } + + unit = ptr_priv->unit; + + ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + /* for warm de-init procedure, if any net intf not destroyed, it is possible + * that kernel still has packets to send causing segmentation fault + */ + if (FALSE == ptr_tx_cb->net_tx_allowed) { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, "net tx during sdk de-init\n"); + ptr_priv->stats.tx_dropped++; + osal_skb_free(ptr_skb); + return NETDEV_TX_OK; + } + + /* pad to 60-bytes if skb_len < 60, see: eth_skb_pad(skb) */ + if (ptr_skb->len < ETH_ZLEN) + { + skb_pad(ptr_skb, ETH_ZLEN - ptr_skb->len); + skb_set_tail_pointer(ptr_skb, ETH_ZLEN); + ptr_skb->len = ETH_ZLEN; + } + + /* pad 4-bytes for chip-crc */ + skb_pad(ptr_skb, ETH_FCS_LEN); + skb_set_tail_pointer(ptr_skb, ETH_FCS_LEN); + ptr_skb->len += ETH_FCS_LEN; + + /* alloc gpd */ + ptr_sw_gpd = osal_alloc(sizeof(HAL_DAWN_PKT_TX_SW_GPD_T)); + if (NULL == ptr_sw_gpd) + { + ptr_priv->stats.tx_errors++; + osal_skb_free(ptr_skb); + } + else + { + /* map skb to dma */ + ptr_virt_addr = ptr_skb->data; + phy_addr = osal_skb_mapDma(ptr_skb, DMA_TO_DEVICE); + if (0x0 == phy_addr) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_ERR, "u=%u, txch=%u, skb dma map err\n", + unit, channel); + ptr_priv->stats.tx_errors++; + osal_skb_free(ptr_skb); + osal_free(ptr_sw_gpd); + } + else + { + /* trans skb to gpd */ + memset(ptr_sw_gpd, 0x0, sizeof(HAL_DAWN_PKT_TX_SW_GPD_T)); + ptr_sw_gpd->callback = (void *)_hal_dawn_pkt_net_dev_tx_callback; + ptr_sw_gpd->ptr_cookie = (void *)ptr_skb; + ptr_sw_gpd->gpd_num = 1; + ptr_sw_gpd->ptr_next = NULL; + ptr_sw_gpd->channel = channel; + + /* prepare gpd */ + hal_dawn_pkt_prepareGpd(unit, phy_addr, ptr_skb->len, ptr_priv->port, ptr_sw_gpd); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + ptr_net_dev->trans_start = jiffies; +#else + netdev_get_tx_queue(ptr_net_dev, 0)->trans_start = jiffies; +#endif + /* send gpd */ + if (CLX_E_OK == hal_dawn_pkt_sendGpd(unit, channel, ptr_sw_gpd)) + { + ptr_priv->stats.tx_packets++; + ptr_priv->stats.tx_bytes += ptr_skb->len; + } + else + { + ptr_priv->stats.tx_fifo_errors++; /* to record the extreme cases where packets are dropped */ + ptr_priv->stats.tx_dropped++; + + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_TO_DEVICE); + osal_skb_free(ptr_skb); + osal_free(ptr_sw_gpd); + } + } + } + + return NETDEV_TX_OK; +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +static void +_hal_dawn_pkt_net_dev_tx_timeout( + struct net_device *ptr_net_dev, + unsigned int txqueue) +#else +static void +_hal_dawn_pkt_net_dev_tx_timeout( + struct net_device *ptr_net_dev) +#endif +{ + netif_stop_queue(ptr_net_dev); + osal_sleepThread(1000); + netif_wake_queue(ptr_net_dev); +} + +static struct net_device_stats * +_hal_dawn_pkt_net_dev_get_stats( + struct net_device *ptr_net_dev) +{ + struct net_device_priv *ptr_priv = netdev_priv(ptr_net_dev); + + return (&ptr_priv->stats); +} + +static int +_hal_dawn_pkt_net_dev_set_mtu( + struct net_device *ptr_net_dev, + int new_mtu) +{ + if (new_mtu < 64 || new_mtu > 9216) + { + return -EINVAL; + } + ptr_net_dev->mtu = new_mtu; /* This mtu need to be synced to chip's */ + return 0; +} + +static int +_hal_dawn_pkt_net_dev_set_mac( + struct net_device *ptr_net_dev, + void *ptr_mac_addr) +{ + struct sockaddr *ptr_addr = ptr_mac_addr; + + memcpy(ptr_net_dev->dev_addr, ptr_addr->sa_data, ptr_net_dev->addr_len); + return 0; +} + +static void +_hal_dawn_pkt_net_dev_set_rx_mode( + struct net_device *ptr_dev) +{ + if (ptr_dev->flags & IFF_PROMISC) + { + } + else + { + if (ptr_dev->flags & IFF_ALLMULTI) + { + } + else + { + if (netdev_mc_empty(ptr_dev)) + { + return; + } + } + } +} + +static struct net_device_ops _hal_dawn_pkt_net_dev_ops = +{ + .ndo_init = _hal_dawn_pkt_net_dev_init, + .ndo_open = _hal_dawn_pkt_net_dev_open, + .ndo_stop = _hal_dawn_pkt_net_dev_stop, + .ndo_do_ioctl = _hal_dawn_pkt_net_dev_ioctl, + .ndo_start_xmit = _hal_dawn_pkt_net_dev_tx, + .ndo_tx_timeout = _hal_dawn_pkt_net_dev_tx_timeout, + .ndo_get_stats = _hal_dawn_pkt_net_dev_get_stats, + .ndo_change_mtu = _hal_dawn_pkt_net_dev_set_mtu, + .ndo_set_mac_address = _hal_dawn_pkt_net_dev_set_mac, + .ndo_set_rx_mode = _hal_dawn_pkt_net_dev_set_rx_mode, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +static int +_hal_dawn_pkt_net_dev_ethtool_get( + struct net_device *ptr_dev, + struct ethtool_cmd *ptr_cmd) +{ + struct net_device_priv *ptr_priv; + + ptr_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE; + ptr_cmd->port = PORT_FIBRE; + ptr_cmd->duplex = DUPLEX_FULL; + + ptr_priv = netdev_priv(ptr_dev); + ethtool_cmd_speed_set(ptr_cmd, ptr_priv->speed); + + return 0; +} +#endif + +static struct ethtool_ops _hal_dawn_pkt_net_dev_ethtool_ops = +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + .get_settings = _hal_dawn_pkt_net_dev_ethtool_get, +#endif + .get_link = ethtool_op_get_link, +}; + +static void +_hal_dawn_pkt_setup( + struct net_device *ptr_net_dev) +{ + struct net_device_priv *ptr_priv = netdev_priv(ptr_net_dev); + + /* setup net device */ + ether_setup(ptr_net_dev); + ptr_net_dev->netdev_ops = &_hal_dawn_pkt_net_dev_ops; + ptr_net_dev->ethtool_ops = &_hal_dawn_pkt_net_dev_ethtool_ops; + ptr_net_dev->watchdog_timeo = HAL_DAWN_PKT_TX_TIMEOUT; + ptr_net_dev->mtu = HAL_DAWN_PKT_MAX_ETH_FRAME_SIZE; /* This mtu need to be synced to chip's */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0) + ptr_net_dev->min_mtu = 64; + ptr_net_dev->max_mtu = 65535; +#endif + random_ether_addr(ptr_net_dev->dev_addr); /* Please use the mac-addr of interface. */ + + /* setup private data */ + ptr_priv->ptr_net_dev = ptr_net_dev; + memset(&ptr_priv->stats, 0, sizeof(struct net_device_stats)); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_createIntf( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_INTF_T net_intf = {0}; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + struct net_device *ptr_net_dev = NULL; + struct net_device_priv *ptr_priv = NULL; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* Lock all Rx tasks to avoid any access to the intf during packet processing */ + /* Only Rx tasks are locked since Tx action is performed under a spinlock protection */ + _hal_dawn_pkt_lockRxChannelAll(unit); + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, "u=%u, create intf name=%s, phy port=%d\n", + unit, net_intf.name, net_intf.port); + + /* To check if the interface with the same name exists in kernel */ + ptr_net_dev = dev_get_by_name(&init_net, net_intf.name); + if (NULL != ptr_net_dev) + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_ERR | HAL_DAWN_PKT_DBG_INTF), + "u=%u, create intf failed, exist same name=%s\n", + unit, net_intf.name); + + dev_put(ptr_net_dev); + +#if defined(HAL_DAWN_PKT_FORCR_REMOVE_DUPLICATE_NETDEV) + ptr_net_dev->operstate = IF_OPER_DOWN; + netif_carrier_off(ptr_net_dev); + netif_tx_disable(ptr_net_dev); + unregister_netdev(ptr_net_dev); + free_netdev(ptr_net_dev); +#endif + _hal_dawn_pkt_unlockRxChannelAll(unit); + return (CLX_E_ENTRY_EXISTS); + } + + /* Bind the net dev and intf meta data to internel port-based array */ + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(net_intf.port); + if (ptr_port_db->ptr_net_dev == NULL) + { + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) + ptr_net_dev = alloc_netdev(sizeof(struct net_device_priv), + net_intf.name, NET_NAME_UNKNOWN, _hal_dawn_pkt_setup); +#else + ptr_net_dev = alloc_netdev(sizeof(struct net_device_priv), + net_intf.name, _hal_dawn_pkt_setup); +#endif + memcpy(ptr_net_dev->dev_addr, net_intf.mac, ptr_net_dev->addr_len); + + ptr_priv = netdev_priv(ptr_net_dev); + + /* Port info will be used when packet sent from this netdev */ + ptr_priv->port = net_intf.port; + ptr_priv->id = net_intf.port; + ptr_priv->unit = unit; + + register_netdev(ptr_net_dev); + + netif_carrier_off(ptr_net_dev); + + net_intf.id = net_intf.port; /* Currently, id is 1-to-1 mapped to port */ + osal_memcpy(&ptr_port_db->meta, &net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + + ptr_port_db->ptr_net_dev = ptr_net_dev; + + /* Copy the intf-id to user space */ + osal_io_copyToUser(&ptr_cookie->net_intf, &net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_INTF | HAL_DAWN_PKT_DBG_ERR), + "u=%u, create intf failed, exist on phy port=%d\n", + unit, net_intf.port); + /* The user needs to delete the existing intf binding to the same port */ + rc = CLX_E_ENTRY_EXISTS; + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_destroyIntf( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_INTF_T net_intf = {0}; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + /* Lock all Rx tasks to avoid any access to the intf during packet processing */ + /* Only Rx tasks are locked since Tx action is performed under a spinlock protection */ + _hal_dawn_pkt_lockRxChannelAll(unit); + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + + /* Unregister net devices by id, although the "id" is now relavent to "port" we still perform a search */ + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, + "u=%u, find intf %s (id=%d) on phy port=%d, destroy done\n", + unit, + ptr_port_db->meta.name, + ptr_port_db->meta.id, + ptr_port_db->meta.port); + + netif_carrier_off(ptr_port_db->ptr_net_dev); + netif_tx_disable(ptr_port_db->ptr_net_dev); + unregister_netdev(ptr_port_db->ptr_net_dev); + free_netdev(ptr_port_db->ptr_net_dev); + + /* Don't need to remove profiles on this port. + * In fact, the profile is binding to "port" not "intf". + */ + /* _hal_dawn_pkt_destroyProfList(ptr_port_db->ptr_profile_list); */ + + osal_memset(ptr_port_db, 0x0, sizeof(HAL_DAWN_PKT_NETIF_PORT_DB_T)); + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_traverseProfList( + UI32_T intf_id, + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_prof_list) +{ + HAL_DAWN_PKT_PROFILE_NODE_T *ptr_curr_node; + + ptr_curr_node = ptr_prof_list; + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, "intf id=%d, prof list=", intf_id); + while(NULL != ptr_curr_node) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, "%s (%d) => ", + ptr_curr_node->ptr_profile->name, + ptr_curr_node->ptr_profile->priority); + ptr_curr_node = ptr_curr_node->ptr_next_node; + } + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, "null\n"); + return (CLX_E_OK); +} + + +static CLX_ERROR_NO_T +_hal_dawn_pkt_getIntf( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_INTF_T net_intf = {0}; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_INTF, "u=%u, find intf id=%d\n", unit, net_intf.id); + _hal_dawn_pkt_traverseProfList(net_intf.id, ptr_port_db->ptr_profile_list); + osal_io_copyToUser(&ptr_cookie->net_intf, &ptr_port_db->meta, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +static HAL_DAWN_PKT_NETIF_PROFILE_T * +_hal_dawn_pkt_getProfEntry( + const UI32_T id) +{ + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile = NULL; + + if (id < HAL_DAWN_PKT_NET_PROFILE_NUM_MAX) + { + if (NULL != _ptr_hal_dawn_pkt_profile_entry[id]) + { + ptr_profile = _ptr_hal_dawn_pkt_profile_entry[id]; + } + } + + return (ptr_profile); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_createProfile( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + CLX_ERROR_NO_T rc; + + /* Lock all Rx tasks to avoid profiles being refered during packet processing */ + /* Need to lock all Rx tasks since packets from all Rx channels do profile lookup */ + _hal_dawn_pkt_lockRxChannelAll(unit); + + ptr_profile = osal_alloc(sizeof(HAL_DAWN_PKT_NETIF_PROFILE_T)); + osal_io_copyFromUser(ptr_profile, &ptr_cookie->net_profile, + sizeof(HAL_DAWN_PKT_NETIF_PROFILE_T)); + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "u=%u, create prof name=%s, priority=%d, flag=0x%x\n", + unit, + ptr_profile->name, + ptr_profile->priority, + ptr_profile->flags); + + /* Save the profile to the profile array and assign the index to ptr_profile->id */ + rc = _hal_dawn_pkt_allocProfEntry(ptr_profile); + if (CLX_E_OK == rc) + { + /* Insert the profile to the corresponding (port) interface */ + if ((ptr_profile->flags & HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PORT) != 0) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "u=%u, bind prof to phy port=%d\n", unit, ptr_profile->port); + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(ptr_profile->port); + _hal_dawn_pkt_addProfToList(ptr_profile, &ptr_port_db->ptr_profile_list); + } + else + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "u=%u, bind prof to all intf\n", unit); + _hal_dawn_pkt_addProfToAllIntf(ptr_profile); + } + + /* Copy the ptr_profile->id to user space */ + osal_io_copyToUser(&ptr_cookie->net_profile, ptr_profile, sizeof(HAL_DAWN_PKT_NETIF_PROFILE_T)); + } + else + { + HAL_DAWN_PKT_DBG((HAL_DAWN_PKT_DBG_PROFILE | HAL_DAWN_PKT_DBG_ERR), + "u=%u, alloc prof entry failed, tbl full\n", unit); + osal_free(ptr_profile); + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_destroyProfile( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_PROFILE_T profile = {0}; + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* Lock all Rx tasks to avoid profiles being refered during packet processing */ + /* Need to lock all Rx tasks since packets from all Rx channels do profile lookup */ + _hal_dawn_pkt_lockRxChannelAll(unit); + + osal_io_copyFromUser(&profile, &ptr_cookie->net_profile, + sizeof(HAL_DAWN_PKT_NETIF_PROFILE_T)); + + /* Remove the profile from corresponding interface (port) */ + _hal_dawn_pkt_delProfFromAllIntfById(profile.id); + + ptr_profile = _hal_dawn_pkt_freeProfEntry(profile.id); + if (NULL != ptr_profile) + { + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_PROFILE, + "u=%u, destroy prof id=%d, name=%s, priority=%d, flag=0x%x\n", + unit, + ptr_profile->id, + ptr_profile->name, + ptr_profile->priority, + ptr_profile->flags); + osal_free(ptr_profile); + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_dawn_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_getProfile( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_PROFILE_T profile = {0}; + HAL_DAWN_PKT_NETIF_PROFILE_T *ptr_profile; + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_io_copyFromUser(&profile, &ptr_cookie->net_profile, sizeof(HAL_DAWN_PKT_NETIF_PROFILE_T)); + + ptr_profile = _hal_dawn_pkt_getProfEntry(profile.id); + if (NULL != ptr_profile) + { + osal_io_copyToUser(&ptr_cookie->net_profile, ptr_profile, sizeof(HAL_DAWN_PKT_NETIF_PROFILE_T)); + } + else + { + rc = CLX_E_ENTRY_NOT_FOUND; + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_getIntfCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_INTF_T net_intf = {0}; + HAL_DAWN_PKT_NETIF_INTF_CNT_T intf_cnt = {0}; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + struct net_device_priv *ptr_priv; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + ptr_priv = netdev_priv(ptr_port_db->ptr_net_dev); + intf_cnt.rx_pkt = ptr_priv->stats.rx_packets; + intf_cnt.tx_pkt = ptr_priv->stats.tx_packets; + intf_cnt.tx_error = ptr_priv->stats.tx_errors; + intf_cnt.tx_queue_full = ptr_priv->stats.tx_fifo_errors; + + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->cnt, &intf_cnt, sizeof(HAL_DAWN_PKT_NETIF_INTF_CNT_T)); + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_dawn_pkt_clearIntfCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_DAWN_PKT_NETIF_INTF_T net_intf = {0}; + HAL_DAWN_PKT_NETIF_PORT_DB_T *ptr_port_db; + struct net_device_priv *ptr_priv; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_DAWN_PKT_NETIF_INTF_T)); + + for (port = 0; port < HAL_DAWN_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_DAWN_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + ptr_priv = netdev_priv(ptr_port_db->ptr_net_dev); + ptr_priv->stats.rx_packets = 0; + ptr_priv->stats.tx_packets = 0; + ptr_priv->stats.tx_errors = 0; + ptr_priv->stats.tx_fifo_errors = 0; + + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Init: dev_ops */ +static void +_hal_dawn_pkt_dev_tx_callback( + const UI32_T unit, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd_usr) +{ + UI32_T channel = ptr_sw_gpd->channel; + HAL_DAWN_PKT_TX_CB_T *ptr_tx_cb = HAL_DAWN_PKT_GET_TX_CB_PTR(unit); + + while (0 != _hal_dawn_pkt_enQueue(&ptr_tx_cb->sw_queue, ptr_sw_gpd)) + { + ptr_tx_cb->cnt.channel[channel].enque_retry++; + HAL_DAWN_PKT_TX_ENQUE_RETRY_SLEEP(); + } + ptr_tx_cb->cnt.channel[channel].enque_ok++; + + osal_triggerEvent(&ptr_tx_cb->sync_sema); + ptr_tx_cb->cnt.channel[channel].trig_event++; +} + +ssize_t +hal_dawn_pkt_dev_tx( + struct file *file, + const char __user *buf, + size_t count, + loff_t *pos) +{ + int ret = 0; + int idx = 0; + unsigned int unit = 0; + unsigned int channel = 0; + HAL_DAWN_PKT_IOCTL_TX_COOKIE_T tx_cookie; + HAL_DAWN_PKT_IOCTL_TX_GPD_T ioctl_gpd; + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd_knl = NULL; + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_first_sw_gpd_knl = NULL; + + /* copy the tx-cookie */ + osal_io_copyFromUser(&tx_cookie, (void *)buf, sizeof(HAL_DAWN_PKT_IOCTL_TX_COOKIE_T)); + + unit = tx_cookie.unit; + channel = tx_cookie.channel; + + ptr_sw_gpd_knl = osal_alloc(sizeof(HAL_DAWN_PKT_TX_SW_GPD_T)); + ptr_first_sw_gpd_knl = ptr_sw_gpd_knl; + + /* create SW GPD based on the content of each IOCTL GPD */ + while (1) + { + osal_io_copyFromUser(&ioctl_gpd, + ((void *)((CLX_HUGE_T)tx_cookie.ioctl_gpd_addr)) + +idx*sizeof(HAL_DAWN_PKT_IOCTL_TX_GPD_T), + sizeof(HAL_DAWN_PKT_IOCTL_TX_GPD_T)); + + ptr_sw_gpd_knl->channel = ioctl_gpd.channel; + ptr_sw_gpd_knl->gpd_num = ioctl_gpd.gpd_num; + ptr_sw_gpd_knl->ptr_cookie = (void *)ioctl_gpd.cookie; + + /* directly copy user's HW GPD */ + osal_io_copyFromUser(&ptr_sw_gpd_knl->tx_gpd, + (void *)((CLX_HUGE_T)ioctl_gpd.hw_gpd_addr), + sizeof(HAL_DAWN_PKT_TX_GPD_T)); + + /* replace the callback */ + ptr_sw_gpd_knl->callback = (void *)_hal_dawn_pkt_dev_tx_callback; + + /* save the first SW GPD address from userspace since + * we have replaced the original callback + */ + ptr_sw_gpd_knl->ptr_cookie = (void *)ioctl_gpd.sw_gpd_addr; + + if (HAL_DAWN_PKT_CH_LAST_GPD == ptr_sw_gpd_knl->tx_gpd.ch) + { + ptr_sw_gpd_knl->ptr_next = NULL; + break; + } + else + { + ptr_sw_gpd_knl->ptr_next = (HAL_DAWN_PKT_TX_SW_GPD_T *)osal_alloc( + sizeof(HAL_DAWN_PKT_TX_SW_GPD_T)); + ptr_sw_gpd_knl = ptr_sw_gpd_knl->ptr_next; + idx++; + } + } + + ret = hal_dawn_pkt_sendGpd(unit, channel, ptr_first_sw_gpd_knl); + if (CLX_E_OK != ret) + { + _hal_dawn_pkt_freeTxGpdList(unit, ptr_first_sw_gpd_knl); + } + + /* return 0 if success */ + return (ret); +} + +long +hal_dawn_pkt_dev_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + + /* cmd */ + HAL_DAWN_PKT_IOCTL_CMD_T *ptr_cmd = (HAL_DAWN_PKT_IOCTL_CMD_T *)&cmd; + unsigned int unit = ptr_cmd->field.unit; + HAL_DAWN_PKT_IOCTL_TYPE_T type = ptr_cmd->field.type; + + HAL_DAWN_PKT_DBG(HAL_DAWN_PKT_DBG_COMMON, "u=%u, ioctl type=%u, cmd=%u\n", + unit, type, cmd); + + switch (type) + { + /* network interface */ + case HAL_DAWN_PKT_IOCTL_TYPE_CREATE_INTF: + ret = _hal_dawn_pkt_createIntf(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_DESTROY_INTF: + ret = _hal_dawn_pkt_destroyIntf(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_GET_INTF: + ret = _hal_dawn_pkt_getIntf(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_CREATE_PROFILE: + ret = _hal_dawn_pkt_createProfile(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_DESTROY_PROFILE: + ret = _hal_dawn_pkt_destroyProfile(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_GET_PROFILE: + ret = _hal_dawn_pkt_getProfile(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_GET_INTF_CNT: + ret = _hal_dawn_pkt_getIntfCnt(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_CLEAR_INTF_CNT: + ret = _hal_dawn_pkt_clearIntfCnt(unit, (HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + /* driver */ + case HAL_DAWN_PKT_IOCTL_TYPE_WAIT_RX_FREE: + ret = _hal_dawn_pkt_schedRxDeQueue(unit, (HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_WAIT_TX_FREE: + ret = _hal_dawn_pkt_strictTxDeQueue(unit, (HAL_DAWN_PKT_IOCTL_TX_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_SET_RX_CFG: + ret = hal_dawn_pkt_setRxKnlConfig(unit, (HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_GET_RX_CFG: + ret = hal_dawn_pkt_getRxKnlConfig(unit, (HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_DEINIT_TASK: + ret = hal_dawn_pkt_deinitTask(unit); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_DEINIT_DRV: + ret = hal_dawn_pkt_deinitPktDrv(unit); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_INIT_TASK: + ret = hal_dawn_pkt_initTask(unit); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_INIT_DRV: + ret = hal_dawn_pkt_initPktDrv(unit); + break; + + /* counter */ + case HAL_DAWN_PKT_IOCTL_TYPE_GET_TX_CNT: + ret = hal_dawn_pkt_getTxKnlCnt(unit, (HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_GET_RX_CNT: + ret = hal_dawn_pkt_getRxKnlCnt(unit, (HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_CLEAR_TX_CNT: + ret = hal_dawn_pkt_clearTxKnlCnt(unit, (HAL_DAWN_PKT_IOCTL_TX_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_CLEAR_RX_CNT: + ret = hal_dawn_pkt_clearRxKnlCnt(unit, (HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_DAWN_PKT_IOCTL_TYPE_SET_PORT_ATTR: + ret = hal_dawn_pkt_setPortAttr(unit, (HAL_DAWN_PKT_IOCTL_PORT_COOKIE_T *)arg); + break; + +#if defined(NETIF_EN_NETLINK) + case HAL_DAWN_PKT_IOCTL_TYPE_NL_SET_INTF_PROPERTY: + ret = _hal_dawn_pkt_setIntfProperty(unit, (HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_DAWN_PKT_IOCTL_TYPE_NL_GET_INTF_PROPERTY: + ret = _hal_dawn_pkt_getIntfProperty(unit, (HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_DAWN_PKT_IOCTL_TYPE_NL_CREATE_NETLINK: + ret = _hal_dawn_pkt_createNetlink(unit, (HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_DAWN_PKT_IOCTL_TYPE_NL_DESTROY_NETLINK: + ret = _hal_dawn_pkt_destroyNetlink(unit, (HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_DAWN_PKT_IOCTL_TYPE_NL_GET_NETLINK: + ret = _hal_dawn_pkt_getNetlink(unit, (HAL_DAWN_PKT_NL_IOCTL_COOKIE_T *)arg); + break; +#endif + + default: + ret = -1; + break; + } + + return (ret); +} + +/* ----------------------------------------------------------------------------------- Init/Deinit */ +CLX_ERROR_NO_T +hal_dawn_pkt_init( + const UI32_T unit) +{ + /* Init Thread */ + osal_init(); + + /* Reset all database*/ + osal_memset(_hal_dawn_pkt_port_db, 0x0, + (HAL_DAWN_PKT_MAX_PORT_NUM * sizeof(HAL_DAWN_PKT_NETIF_PORT_DB_T))); + osal_memset(_hal_dawn_pkt_rx_cb, 0x0, + CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM*sizeof(HAL_DAWN_PKT_RX_CB_T)); + osal_memset(_hal_dawn_pkt_tx_cb, 0x0, + CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM*sizeof(HAL_DAWN_PKT_TX_CB_T)); + osal_memset(_hal_dawn_pkt_drv_cb, 0x0, + CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM*sizeof(HAL_DAWN_PKT_DRV_CB_T)); + +#if defined(NETIF_EN_NETLINK) + netif_nl_init(); +#endif + + return (0); +} + +CLX_ERROR_NO_T +hal_dawn_pkt_exit( + const UI32_T unit) +{ + /* 1st. Stop all netdev (if any) to prevent kernel from Tx new packets */ + _hal_dawn_pkt_stopAllIntf(unit); + + /* 2nd. Stop Rx HW DMA and free all the DMA buffer hooked on the ring */ + _hal_dawn_pkt_rxStop(unit); + + /* 3rd. Need to wait Rx done task process all the availavle packets on GPD ring */ +#define HAL_DAWN_PKT_MODULE_EXIT_HOLD_TIME_US (1000000) + osal_sleepThread(HAL_DAWN_PKT_MODULE_EXIT_HOLD_TIME_US); + + /* 4th. Stop all the internal tasks (if any) */ + hal_dawn_pkt_deinitTask(unit); + + /* 5th. Deinit pkt driver for common database/interrupt source (if required) */ + hal_dawn_pkt_deinitPktDrv(unit); + + /* 6th. Clean up those intf/profiles not been destroyed */ + _hal_dawn_pkt_destroyAllProfile(unit); + _hal_dawn_pkt_destroyAllIntf(unit); + + osal_deinit(); + + return (0); +} diff --git a/platform/clounix/clounix-modules/modules/src/clx_netif/hal_lightning_pkt_knl.c b/platform/clounix/clounix-modules/modules/src/clx_netif/hal_lightning_pkt_knl.c new file mode 100755 index 000000000000..0a801f08b383 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_netif/hal_lightning_pkt_knl.c @@ -0,0 +1,6600 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: hal_lightning_pkt_knl.c + * PURPOSE: + * To provide Linux kernel for PDMA TX/RX control. + * + * NOTES: + * + */ + +/***************************************************************************** + * INCLUDE FILE DECLARATIONS + ***************************************************************************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* netif */ +#include +#include +#include + +#include + +/* clx_sdk */ +#include +#include + +/***************************************************************************** + * CHIP DEPENDENT VARIABLES + ***************************************************************************** + */ +/* Interrupt */ +#define HAL_LIGHTNING_PKT_ERR_REG(__unit__) (_hal_lightning_pkt_intr_vec[0].intr_reg) +#define HAL_LIGHTNING_PKT_TCH_REG(__unit__, __channel__) (_hal_lightning_pkt_intr_vec[1 + (__channel__)].intr_reg) +#define HAL_LIGHTNING_PKT_RCH_REG(__unit__, __channel__) (_hal_lightning_pkt_intr_vec[5 + (__channel__)].intr_reg) + +#define HAL_LIGHTNING_PKT_ERR_EVENT(__unit__) (&_hal_lightning_pkt_intr_vec[0].intr_event) +#define HAL_LIGHTNING_PKT_TCH_EVENT(__unit__, __channel__) (&_hal_lightning_pkt_intr_vec[1 + (__channel__)].intr_event) +#define HAL_LIGHTNING_PKT_RCH_EVENT(__unit__, __channel__) (&_hal_lightning_pkt_intr_vec[5 + (__channel__)].intr_event) + +#define HAL_LIGHTNING_PKT_ERR_CNT(__unit__) (_hal_lightning_pkt_intr_vec[0].intr_cnt) +#define HAL_LIGHTNING_PKT_TCH_CNT(__unit__, __channel__) (_hal_lightning_pkt_intr_vec[1 + (__channel__)].intr_cnt) +#define HAL_LIGHTNING_PKT_RCH_CNT(__unit__, __channel__) (_hal_lightning_pkt_intr_vec[5 + (__channel__)].intr_cnt) + + +/* This flag value will be specified when user inserts kernel module. */ +#define HAL_LIGHTNING_PKT_DBG_ERR (0x1UL << 0) +#define HAL_LIGHTNING_PKT_DBG_TX (0x1UL << 1) +#define HAL_LIGHTNING_PKT_DBG_RX (0x1UL << 2) +#define HAL_LIGHTNING_PKT_DBG_INTF (0x1UL << 3) +#define HAL_LIGHTNING_PKT_DBG_PROFILE (0x1UL << 4) +#define HAL_LIGHTNING_PKT_DBG_COMMON (0x1UL << 5) +#define HAL_LIGHTNING_PKT_DBG_NETLINK (0x1UL << 6) + +extern UI32_T ext_dbg_flag; + +#define HAL_LIGHTNING_PKT_DBG(__flag__, ...) do \ +{ \ + if (0 != ((__flag__) & (ext_dbg_flag))) \ + { \ + osal_printf(__VA_ARGS__); \ + } \ +}while (0) + +typedef struct +{ + UI32_T intr_reg; + CLX_SEMAPHORE_ID_T intr_event; + UI32_T intr_cnt; + +} HAL_LIGHTNING_PKT_INTR_VEC_T; + +typedef struct HAL_LIGHTNING_PKT_PROFILE_NODE_S +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile; + struct HAL_LIGHTNING_PKT_PROFILE_NODE_S *ptr_next_node; + +} HAL_LIGHTNING_PKT_PROFILE_NODE_T; + +typedef struct +{ + HAL_LIGHTNING_PKT_NETIF_INTF_T meta; + struct net_device *ptr_net_dev; + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_profile_list; /* the profiles binding to this interface */ + +} HAL_LIGHTNING_PKT_NETIF_PORT_DB_T; + + +static HAL_LIGHTNING_PKT_INTR_VEC_T _hal_lightning_pkt_intr_vec[] = +{ + { /* 0: PDMA_ERR */ 1UL << 0, 0x0, 0 }, + { /* 1: TX_CH0 */ 1UL << 28, 0x0, 0 }, + { /* 2: TX_CH1 */ 1UL << 29, 0x0, 0 }, + { /* 3: TX_CH2 */ 1UL << 30, 0x0, 0 }, + { /* 4: TX_CH3 */ 1UL << 31, 0x0, 0 }, + { /* 5: RX_CH0 */ 1UL << 24, 0x0, 0 }, + { /* 6: RX_CH1 */ 1UL << 25, 0x0, 0 }, + { /* 7: RX_CH2 */ 1UL << 26, 0x0, 0 }, + { /* 8: RX_CH3 */ 1UL << 27, 0x0, 0 }, +}; + +/***************************************************************************** + * NAMING CONSTANT DECLARATIONS + ***************************************************************************** + */ +/* Sleep Time Definitions */ +#define HAL_LIGHTNING_PKT_TX_DEQUE_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_LIGHTNING_PKT_RX_DEQUE_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_LIGHTNING_PKT_TX_ENQUE_RETRY_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_LIGHTNING_PKT_RX_ENQUE_RETRY_SLEEP() osal_sleepThread(1000) /* us */ +#define HAL_LIGHTNING_PKT_ALLOC_MEM_RETRY_SLEEP() osal_sleepThread(1000) /* us */ + +/* Network Device Definitions */ +/* In case that the watchdog alarm during warm-boot if intf isn't killed */ +#define HAL_LIGHTNING_PKT_TX_TIMEOUT (30*HZ) +#define HAL_LIGHTNING_PKT_MAX_ETH_FRAME_SIZE (HAL_LIGHTNING_PKT_RX_MAX_LEN) +#define HAL_LIGHTNING_PKT_MAX_PORT_NUM (HAL_LIGHTNING_PORT_NUM + 1) /* CPU port */ + +#define HAL_LIGHTNING_PKT_NET_PROFILE_NUM_MAX (256) + +static HAL_LIGHTNING_PKT_NETIF_PROFILE_T *_ptr_hal_lightning_pkt_profile_entry[HAL_LIGHTNING_PKT_NET_PROFILE_NUM_MAX] = {0}; +static HAL_LIGHTNING_PKT_NETIF_PORT_DB_T _hal_lightning_pkt_port_db[HAL_LIGHTNING_PKT_MAX_PORT_NUM]; + +/***************************************************************************** + * MACRO VLAUE DECLARATIONS + ***************************************************************************** + */ + +/***************************************************************************** + * MACRO FUNCTION DECLARATIONS + ***************************************************************************** + */ +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit) (&_hal_lightning_pkt_drv_cb[unit]) +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit) (&_hal_lightning_pkt_tx_cb[unit]) +#define HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel) (&_hal_lightning_pkt_tx_cb[unit].pdma[channel]) +#define HAL_LIGHTNING_PKT_GET_TX_GPD_PTR(unit, channel, gpd) (&_hal_lightning_pkt_tx_cb[unit].pdma[channel].ptr_gpd_align_start_addr[gpd]) +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit) (&_hal_lightning_pkt_rx_cb[unit]) +#define HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel) (&_hal_lightning_pkt_rx_cb[unit].pdma[channel]) +#define HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, gpd) (&_hal_lightning_pkt_rx_cb[unit].pdma[channel].ptr_gpd_align_start_addr[gpd]) +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_GET_PORT_DB(port) (&_hal_lightning_pkt_port_db[port]) +#define HAL_LIGHTNING_PKT_GET_PORT_PROFILE_LIST(port) (_hal_lightning_pkt_port_db[port].ptr_profile_list) +#define HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port) _hal_lightning_pkt_port_db[port].ptr_net_dev + +/***************************************************************************** + * DATA TYPE DECLARATIONS + ***************************************************************************** + */ +/* ----------------------------------------------------------------------------------- General structure */ +typedef struct +{ + UI32_T unit; + UI32_T channel; + +} HAL_LIGHTNING_PKT_ISR_COOKIE_T; + +typedef struct +{ + CLX_HUGE_T que_id; + CLX_SEMAPHORE_ID_T sema; + UI32_T len; /* Software CPU queue maximum length. */ + UI32_T weight; /* The weight for thread de-queue algorithm. */ + +} HAL_LIGHTNING_PKT_SW_QUEUE_T; + +typedef struct +{ + /* handleErrorTask */ + CLX_THREAD_ID_T err_task_id; + + /* INTR dispatcher */ + CLX_ISRLOCK_ID_T intr_lock; + UI32_T intr_bitmap; + +#define HAL_LIGHTNING_PKT_INIT_DRV (1UL << 0) +#define HAL_LIGHTNING_PKT_INIT_TASK (1UL << 1) +#define HAL_LIGHTNING_PKT_INIT_INTR (1UL << 2) +#define HAL_LIGHTNING_PKT_INIT_RX_START (1UL << 3) + /* a bitmap to record the init status */ + UI32_T init_flag; + +} HAL_LIGHTNING_PKT_DRV_CB_T; + +/* ----------------------------------------------------------------------------------- TX structure */ +typedef struct +{ + /* CLX_SEMAPHORE_ID_T sema; */ + + /* since the Tx GPD ring may be accessed by multiple process including + * ndo_start_xmit (SW IRQ), it must be protected with an ISRLOCK + * instead of the original semaphore + */ + CLX_ISRLOCK_ID_T ring_lock; + + UI32_T used_idx; /* SW send index = LAMP simulate the Tx HW index */ + UI32_T free_idx; /* SW free index */ + UI32_T used_gpd_num; + UI32_T free_gpd_num; + UI32_T gpd_num; + + HAL_LIGHTNING_PKT_TX_GPD_T *ptr_gpd_start_addr; + HAL_LIGHTNING_PKT_TX_GPD_T *ptr_gpd_align_start_addr; + BOOL_T err_flag; + + /* ASYNC */ + HAL_LIGHTNING_PKT_TX_SW_GPD_T **pptr_sw_gpd_ring; + HAL_LIGHTNING_PKT_TX_SW_GPD_T **pptr_sw_gpd_bulk; /* temporary store packets to be enque */ + + /* SYNC_INTR */ + CLX_SEMAPHORE_ID_T sync_intr_sema; + +} HAL_LIGHTNING_PKT_TX_PDMA_T; + +typedef struct +{ + HAL_LIGHTNING_PKT_TX_WAIT_T wait_mode; + HAL_LIGHTNING_PKT_TX_PDMA_T pdma[HAL_LIGHTNING_PKT_TX_CHANNEL_LAST]; + HAL_LIGHTNING_PKT_TX_CNT_T cnt; + + /* handleTxDoneTask */ + CLX_THREAD_ID_T isr_task_id[HAL_LIGHTNING_PKT_TX_CHANNEL_LAST]; + HAL_LIGHTNING_PKT_ISR_COOKIE_T isr_task_cookie[HAL_LIGHTNING_PKT_TX_CHANNEL_LAST]; + + /* txTask */ + HAL_LIGHTNING_PKT_SW_QUEUE_T sw_queue; + CLX_SEMAPHORE_ID_T sync_sema; + CLX_THREAD_ID_T task_id; + BOOL_T running; /* TRUE when Init txTask + * FALSE when Destroy txTask + */ + /* to block net intf Tx in driver level since netif_tx_disable() + * cannot always prevent intf from Tx in time + */ + BOOL_T net_tx_allowed; +} HAL_LIGHTNING_PKT_TX_CB_T; + +/* ----------------------------------------------------------------------------------- RX structure */ +typedef struct +{ + CLX_SEMAPHORE_ID_T sema; + UI32_T cur_idx; /* SW free index */ + UI32_T gpd_num; + + HAL_LIGHTNING_PKT_RX_GPD_T *ptr_gpd_start_addr; + HAL_LIGHTNING_PKT_RX_GPD_T *ptr_gpd_align_start_addr; + BOOL_T err_flag; + struct sk_buff **pptr_skb_ring; +} HAL_LIGHTNING_PKT_RX_PDMA_T; + +typedef struct +{ + /* Rx system configuration */ + UI32_T buf_len; + + HAL_LIGHTNING_PKT_RX_SCHED_T sched_mode; + HAL_LIGHTNING_PKT_RX_PDMA_T pdma[HAL_LIGHTNING_PKT_RX_CHANNEL_LAST]; + HAL_LIGHTNING_PKT_RX_CNT_T cnt; + + /* handleRxDoneTask */ + CLX_THREAD_ID_T isr_task_id[HAL_LIGHTNING_PKT_RX_CHANNEL_LAST]; + HAL_LIGHTNING_PKT_ISR_COOKIE_T isr_task_cookie[HAL_LIGHTNING_PKT_RX_CHANNEL_LAST]; + + /* rxTask */ + HAL_LIGHTNING_PKT_SW_QUEUE_T sw_queue[HAL_LIGHTNING_PKT_RX_QUEUE_NUM]; + UI32_T deque_idx; + CLX_SEMAPHORE_ID_T sync_sema; + CLX_THREAD_ID_T task_id; + CLX_SEMAPHORE_ID_T deinit_sema; /* To sync-up the Rx-stop and thread flush queues */ + BOOL_T running; /* TRUE when rxStart + * FALSE when rxStop + */ + +} HAL_LIGHTNING_PKT_RX_CB_T; + +/* ----------------------------------------------------------------------------------- Network Device */ +struct net_device_priv +{ + struct net_device *ptr_net_dev; + struct net_device_stats stats; + UI32_T unit; + UI32_T id; + UI32_T port; + UI16_T vlan; + UI32_T speed; +}; + +typedef enum +{ + HAL_LIGHTNING_PKT_DEST_NETDEV = 0, + HAL_LIGHTNING_PKT_DEST_SDK, +#if defined(NETIF_EN_NETLINK) + HAL_LIGHTNING_PKT_DEST_NETLINK, +#endif + HAL_LIGHTNING_PKT_DEST_DROP, + HAL_LIGHTNING_PKT_DEST_LAST +} HAL_LIGHTNING_PKT_DEST_T; + +/***************************************************************************** + * GLOBAL VARIABLE DECLARATIONS + ***************************************************************************** + */ + +/***************************************************************************** + * STATIC VARIABLE DECLARATIONS + ***************************************************************************** + */ +/*---------------------------------------------------------------------------*/ +static HAL_LIGHTNING_PKT_DRV_CB_T _hal_lightning_pkt_drv_cb[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; +static HAL_LIGHTNING_PKT_TX_CB_T _hal_lightning_pkt_tx_cb[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; +static HAL_LIGHTNING_PKT_RX_CB_T _hal_lightning_pkt_rx_cb[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; +/*---------------------------------------------------------------------------*/ + +/***************************************************************************** + * LOCAL SUBPROGRAM DECLARATIONS + ***************************************************************************** + */ +/* ----------------------------------------------------------------------------------- Interrupt */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_enableIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + UI32_T intr_en = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_readPciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + intr_en |= intr_bitmap; + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_disableIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + UI32_T intr_en = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_readPciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + intr_en &= ~intr_bitmap; + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_EN_HI), &intr_en, sizeof(intr_en)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_maskIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_CLR_HI), &intr_bitmap, sizeof(intr_bitmap)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_unmaskIntr( + const UI32_T unit, + const UI32_T intr_bitmap) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_SET_HI), &intr_bitmap, sizeof(intr_bitmap)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_dispatcher( + void *ptr_cookie) +{ + UI32_T unit = (UI32_T)((CLX_HUGE_T)ptr_cookie); + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + CLX_IRQ_FLAGS_T irq_flag = 0; + + UI32_T idx = 0, vec = sizeof(_hal_lightning_pkt_intr_vec) / sizeof(HAL_LIGHTNING_PKT_INTR_VEC_T); + UI32_T intr_mask = ptr_cb->intr_bitmap; + UI32_T intr_unmask = 0; + UI32_T intr_status = 0; + + /* MASK, READ and CLEAR PKT IRQs */ + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_CLR_HI), &intr_mask, sizeof(UI32_T)); + osal_mdc_readPciReg (unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_STAT_HI), &intr_status, sizeof(UI32_T)); + intr_status = intr_status & intr_mask; + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_CLR_HI), &intr_status, sizeof(UI32_T)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + /* Module thread handle and unmask the interrupt */ + intr_unmask = intr_status ^ intr_mask; + if (0x0 != intr_status) + { + for (idx = 0; idx < vec; idx++) + { + if (_hal_lightning_pkt_intr_vec[idx].intr_reg & intr_status) + { + osal_triggerEvent(&_hal_lightning_pkt_intr_vec[idx].intr_event); + _hal_lightning_pkt_intr_vec[idx].intr_cnt++; + } + } + } + + /* UNMASK other PKT IRQs */ + osal_takeIsrLock(&ptr_cb->intr_lock, &irq_flag); + osal_mdc_writePciReg(unit, HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_SET_HI), &intr_unmask, sizeof(UI32_T)); + osal_giveIsrLock(&ptr_cb->intr_lock, &irq_flag); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- RW HW Regs */ +/* FUNCTION NAME: _hal_lightning_pkt_startTxChannelReg + * PURPOSE: + * To issue "START" command to the target TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None. + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_startTxChannelReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_LIGHTNING_PKT_TCH_CMD_REG_T tch_cmd; + + tch_cmd.reg = 0x0; + tch_cmd.field.tch_start = 0x1; + tch_cmd.field.tch_gpd_add_no_lo = gpd_num & 0xff; + tch_cmd.field.tch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_CMD), channel), + &tch_cmd.reg, sizeof(HAL_LIGHTNING_PKT_TCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_startRxChannelReg + * PURPOSE: + * To issue "START" command to the target RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_startRxChannelReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_LIGHTNING_PKT_RCH_CMD_REG_T rch_cmd; + + rch_cmd.reg = 0x0; + rch_cmd.field.rch_start = 0x1; + rch_cmd.field.rch_gpd_add_no_lo = gpd_num & 0xff; + rch_cmd.field.rch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_CMD), channel), + &rch_cmd.reg, sizeof(HAL_LIGHTNING_PKT_RCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_resumeTxChannelReg + * PURPOSE: + * To issue "RESUME" command to the target TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_resumeTxChannelReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_LIGHTNING_PKT_TCH_CMD_REG_T tch_cmd; + + tch_cmd.reg = 0x0; + tch_cmd.field.tch_resume = 0x1; + tch_cmd.field.tch_gpd_add_no_lo = gpd_num & 0xff; + tch_cmd.field.tch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_CMD), channel), + &tch_cmd.reg, sizeof(HAL_LIGHTNING_PKT_TCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_resumeRxChannelReg + * PURPOSE: + * To issue "RESUME" command to the target RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_num -- The GPD ring length of the channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_resumeRxChannelReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel, + const UI32_T gpd_num) +{ + HAL_LIGHTNING_PKT_RCH_CMD_REG_T rch_cmd; + + rch_cmd.reg = 0x0; + rch_cmd.field.rch_resume = 0x1; + rch_cmd.field.rch_gpd_add_no_lo = gpd_num & 0xff; + rch_cmd.field.rch_gpd_add_no_hi = (gpd_num & 0xff00) >> 8; + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_CMD), channel), + &rch_cmd.reg, sizeof(HAL_LIGHTNING_PKT_RCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_stopTxChannelReg + * PURPOSE: + * To issue "STOP" command to the target TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_stopTxChannelReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_TCH_CMD_REG_T tch_cmd; + + tch_cmd.reg = 0x0; + tch_cmd.field.tch_stop = 0x1; + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_CMD), channel), + &tch_cmd.reg, sizeof(HAL_LIGHTNING_PKT_TCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_stopRxChannelReg + * PURPOSE: + * To issue "STOP" command to the target RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_stopRxChannelReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_RCH_CMD_REG_T rch_cmd; + + rch_cmd.reg = 0x0; + rch_cmd.field.rch_stop = 0x1; + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_CMD), channel), + &rch_cmd.reg, sizeof(HAL_LIGHTNING_PKT_RCH_CMD_REG_T)); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Init HW Regs */ +/* FUNCTION NAME: _hal_lightning_pkt_setTxGpdStartAddrReg + * PURPOSE: + * To configure the start address and the length of target GPD ring of TX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * gpd_start_addr -- The start address of the GPD ring + * gpd_ring_sz -- The size of the GPD ring + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_setTxGpdStartAddrReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + const CLX_ADDR_T gpd_start_addr, + const UI32_T gpd_ring_sz) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T tch_gpd_ring_start_addr_lo = 0; + UI32_T tch_gpd_ring_start_addr_hi = 0; + UI32_T tch_gpd_ring_size = 0; + + /* Configure the low 32-bit address. */ + tch_gpd_ring_start_addr_lo = (UI32_T)CLX_ADDR_64_LOW(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_GPD_RING_START_ADDR_LO), channel), + &tch_gpd_ring_start_addr_lo, sizeof(UI32_T)); + + /* Configure the high 32-bit address. */ + if (CLX_E_OK == rc) + { + tch_gpd_ring_start_addr_hi = (UI32_T)CLX_ADDR_64_HI(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_GPD_RING_START_ADDR_HI), channel), + &tch_gpd_ring_start_addr_hi, sizeof(UI32_T)); + } + + /* Configure the GPD ring size. */ + if (CLX_E_OK == rc) + { + tch_gpd_ring_size = gpd_ring_sz; + + rc = osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_GPD_RING_SIZE), channel), + &tch_gpd_ring_size, sizeof(UI32_T)); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_setRxGpdStartAddrReg + * PURPOSE: + * To configure the start address and the length of target GPD ring of RX channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_start_addr -- The start address of the GPD ring + * gpd_ring_sz -- The size of the GPD ring + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the register. + * CLX_E_OTHERS -- Configure the register failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_setRxGpdStartAddrReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel, + const CLX_ADDR_T gpd_start_addr, + const UI32_T gpd_ring_sz) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T rch_gpd_ring_start_addr_lo = 0; + UI32_T rch_gpd_ring_start_addr_hi = 0; + UI32_T rch_gpd_ring_size = 0; + + /* Configure the low 32-bit address. */ + rch_gpd_ring_start_addr_lo = (UI32_T)CLX_ADDR_64_LOW(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_GPD_RING_START_ADDR_LO), channel), + &rch_gpd_ring_start_addr_lo, sizeof(UI32_T)); + + /* Configure the high 32-bit address. */ + if (CLX_E_OK == rc) + { + rch_gpd_ring_start_addr_hi = (UI32_T)CLX_ADDR_64_HI(gpd_start_addr); + + rc = osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_GPD_RING_START_ADDR_HI), channel), + &rch_gpd_ring_start_addr_hi, sizeof(UI32_T)); + } + + /* Configure the GPD ring size. */ + if (CLX_E_OK == rc) + { + rch_gpd_ring_size = gpd_ring_sz; + + rc = osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_GPD_RING_SIZE), channel), + &rch_gpd_ring_size, sizeof(UI32_T)); + } + + return (rc); +} + +/* ----------------------------------------------------------------------------------- ISR HW Regs */ +/* FUNCTION NAME: _hal_lightning_pkt_maskAllTxL2IsrReg + * PURPOSE: + * To mask all the TX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully mask all the TX L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_maskAllTxL2IsrReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_LIGHTNING_PKT_CLR_BITMAP(reg, + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_COS_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PFC | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_maskAllRxL2IsrReg + * PURPOSE: + * To mask all the L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully mask all the L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_maskAllRxL2IsrReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_LIGHTNING_PKT_CLR_BITMAP(reg, + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_unmaskAllTxL2IsrReg + * PURPOSE: + * To unmask all the TX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully unmask all the TX L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_unmaskAllTxL2IsrReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_LIGHTNING_PKT_SET_BITMAP(reg, + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_COS_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PFC | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_unmaskAllRxL2IsrReg + * PURPOSE: + * To unmask all the L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully unmask all the L2 interrupts. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_unmaskAllRxL2IsrReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + UI32_T reg = 0; + + HAL_LIGHTNING_PKT_SET_BITMAP(reg, + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP | + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_INT_MASK), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_clearTxL2IsrStatusReg + * PURPOSE: + * To clear the status of TX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * isr_bitmap -- The bitmap used to specify the target ISRs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear L1 ISR status. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_clearTxL2IsrStatusReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + const HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_T isr_bitmap) +{ + UI32_T reg = 0; + + HAL_LIGHTNING_PKT_SET_BITMAP(reg, isr_bitmap); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_INT_CLR), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_clearRxL2IsrStatusReg + * PURPOSE: + * To clear the status of RX L2 interrupts for the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * isr_bitmap -- The bitmap used to specify the target ISRs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear RX L2 ISR status. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_clearRxL2IsrStatusReg( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel, + const HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_T isr_bitmap) +{ + UI32_T reg = 0; + + HAL_LIGHTNING_PKT_SET_BITMAP(reg, isr_bitmap); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_INT_CLR), channel), + ®, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_getTxIntrCnt + * PURPOSE: + * To get the PDMA TX interrupt counters of the target channel. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_getTxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt) +{ + *ptr_intr_cnt = HAL_LIGHTNING_PKT_TCH_CNT(unit, channel); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_getRxIntrCnt + * PURPOSE: + * To get the PDMA RX interrupt counters of the target channel. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_getRxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt) +{ + *ptr_intr_cnt = HAL_LIGHTNING_PKT_RCH_CNT(unit, channel); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_getTxKnlCnt + * PURPOSE: + * To get the PDMA TX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the TX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_getTxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + + osal_io_copyToUser(&ptr_cookie->tx_cnt, &ptr_tx_cb->cnt, sizeof(HAL_LIGHTNING_PKT_TX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_getRxKnlCnt + * PURPOSE: + * To get the PDMA RX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully get the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_getRxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + + osal_io_copyToUser(&ptr_cookie->rx_cnt, &ptr_rx_cb->cnt, sizeof(HAL_LIGHTNING_PKT_RX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_clearTxKnlCnt + * PURPOSE: + * To clear the PDMA TX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the TX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_clearTxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + + osal_memset(&ptr_tx_cb->cnt, 0, sizeof(HAL_LIGHTNING_PKT_TX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_clearRxKnlCnt + * PURPOSE: + * To clear the PDMA RX counters of the target channel. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully clear the counters. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_clearRxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + + osal_memset(&ptr_rx_cb->cnt, 0, sizeof(HAL_LIGHTNING_PKT_RX_CNT_T)); + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_setPortAttr + * PURPOSE: + * To set the port attributes such as status or speeds. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the Port cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully set the attributes. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_setPortAttr( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_PORT_COOKIE_T *ptr_cookie) +{ +#define HAL_LIGHTNING_PKT_PORT_STATUS_UP (1) +#define HAL_LIGHTNING_PKT_PORT_STATUS_DOWN (0) + struct net_device *ptr_net_dev; + struct net_device_priv *ptr_priv; + UI32_T port; + UI32_T status; + CLX_PORT_SPEED_T speed; + + osal_io_copyFromUser(&port, &ptr_cookie->port, sizeof(UI32_T)); + osal_io_copyFromUser(&status, &ptr_cookie->status, sizeof(UI32_T)); + osal_io_copyFromUser(&speed, &ptr_cookie->speed, sizeof(CLX_PORT_SPEED_T)); + + ptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + if ((NULL != ptr_net_dev) && (portspeed = SPEED_1000; + break; + case CLX_PORT_SPEED_10G: + ptr_priv->speed = SPEED_10000; + break; + case CLX_PORT_SPEED_25G: + ptr_priv->speed = 25000; + break; + case CLX_PORT_SPEED_40G: + ptr_priv->speed = 40000; + break; + case CLX_PORT_SPEED_50G: + ptr_priv->speed = 50000; + break; + case CLX_PORT_SPEED_100G: + ptr_priv->speed = 100000; + break; + case CLX_PORT_SPEED_200G: + ptr_priv->speed = 200000; + break; + case CLX_PORT_SPEED_400G: + ptr_priv->speed = 400000; + break; + default: + break; + } + } + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_getPortAttr + * PURPOSE: + * To get the port attributes such as status or speeds. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the Port cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully set the attributes. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_getPortAttr( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_PORT_COOKIE_T *ptr_cookie) +{ + struct net_device *ptr_net_dev; + struct net_device_priv *ptr_priv; + UI32_T port; + UI32_T status; + CLX_PORT_SPEED_T speed; + + osal_io_copyFromUser(&port, &ptr_cookie->port, sizeof(UI32_T)); + + ptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + if ((NULL == ptr_net_dev) || (port >= HAL_LIGHTNING_PKT_MAX_PORT_NUM)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "%s(%d): Failed to get netdev, port %d\n", + __FUNCTION__, __LINE__, port); + return -1; + } + status = netif_carrier_ok(ptr_net_dev); + + ptr_priv = netdev_priv(ptr_net_dev); + switch(ptr_priv->speed) + { + case SPEED_1000: + speed = CLX_PORT_SPEED_1G; + break; + case SPEED_10000: + speed = CLX_PORT_SPEED_10G; + break; + case 25000: + speed = CLX_PORT_SPEED_25G; + break; + case 40000: + speed = CLX_PORT_SPEED_40G; + break; + case 50000: + speed = CLX_PORT_SPEED_50G; + break; + case 100000: + speed = CLX_PORT_SPEED_100G; + break; + case 200000: + speed = CLX_PORT_SPEED_200G; + break; + case 400000: + speed = CLX_PORT_SPEED_400G; + break; + default: + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "%s(%d): Unknown speed %d, port %d\n", + __FUNCTION__, __LINE__, ptr_priv->speed, port); + speed = CLX_PORT_SPEED_400G; + break; + } + osal_io_copyToUser(&ptr_cookie->status, &status, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->speed, &speed, sizeof(CLX_PORT_SPEED_T)); + return (CLX_E_OK); +} + + +static void +_hal_lightning_pkt_lockRxChannelAll( + const UI32_T unit) +{ + UI32_T rch; + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma; + + for (rch = 0; rch < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; rch++) + { + ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, rch); + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + } +} + +static void +_hal_lightning_pkt_unlockRxChannelAll( + const UI32_T unit) +{ + UI32_T rch; + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma; + + for (rch = 0; rch < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; rch++) + { + ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, rch); + osal_giveSemaphore(&ptr_rx_pdma->sema); + } +} + +#if defined(NETIF_EN_NETLINK) + +static CLX_ERROR_NO_T +_hal_lightning_pkt_setIntfProperty( + const UI32_T unit, + HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T intf_id; + NETIF_NL_INTF_PROPERTY_T property; + UI32_T param0; + UI32_T param1; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&intf_id, &ptr_cookie->intf_id, sizeof(UI32_T)); + osal_io_copyFromUser(&property, &ptr_cookie->property, sizeof(NETIF_NL_INTF_PROPERTY_T)); + osal_io_copyFromUser(¶m0, &ptr_cookie->param0, sizeof(UI32_T)); + osal_io_copyFromUser(¶m1, &ptr_cookie->param1, sizeof(UI32_T)); + + _hal_lightning_pkt_lockRxChannelAll(unit); + + rc = netif_nl_setIntfProperty(unit, intf_id, property, param0, param1); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_getIntfProperty( + const UI32_T unit, + HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T intf_id; + NETIF_NL_INTF_PROPERTY_T property; + UI32_T param0; + UI32_T param1; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&intf_id, &ptr_cookie->intf_id, sizeof(UI32_T)); + osal_io_copyFromUser(&property, &ptr_cookie->property, sizeof(NETIF_NL_INTF_PROPERTY_T)); + osal_io_copyFromUser(¶m0, &ptr_cookie->param0, sizeof(UI32_T)); + + rc = netif_nl_getIntfProperty(unit, intf_id, property, ¶m0, ¶m1); + + osal_io_copyToUser(&ptr_cookie->param0, ¶m0, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->param1, ¶m1, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_createNetlink( + const UI32_T unit, + HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + NETIF_NL_NETLINK_T netlink; + UI32_T netlink_id; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&netlink, &ptr_cookie->netlink, sizeof(NETIF_NL_NETLINK_T)); + + _hal_lightning_pkt_lockRxChannelAll(unit); + + rc = netif_nl_createNetlink(unit, &netlink, &netlink_id); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + osal_io_copyToUser(&ptr_cookie->netlink.id, &netlink_id, sizeof(UI32_T)); + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_destroyNetlink( + const UI32_T unit, + HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T netlink_id; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&netlink_id, &ptr_cookie->netlink.id, sizeof(UI32_T)); + + _hal_lightning_pkt_lockRxChannelAll(unit); + + rc = netif_nl_destroyNetlink(unit, netlink_id); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_getNetlink( + const UI32_T unit, + HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *ptr_cookie) +{ + UI32_T id; + NETIF_NL_NETLINK_T netlink; + CLX_ERROR_NO_T rc; + + osal_io_copyFromUser(&id, &ptr_cookie->netlink.id, sizeof(UI32_T)); + + rc = netif_nl_getNetlink(unit, id, &netlink); + if (CLX_E_OK == rc) + { + osal_io_copyToUser(&ptr_cookie->netlink, &netlink, sizeof(NETIF_NL_NETLINK_T)); + } + else + { + rc = CLX_E_ENTRY_NOT_FOUND; + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +#endif + +/* ----------------------------------------------------------------------------------- independent func */ +/* FUNCTION NAME: _hal_lightning_pkt_enQueue + * PURPOSE: + * To enqueue the target data. + * INPUT: + * ptr_que -- Pointer for the target queue + * ptr_data -- Pointer for the data to be enqueued + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully enqueue the data. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_enQueue( + HAL_LIGHTNING_PKT_SW_QUEUE_T *ptr_que, + void *ptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_takeSemaphore(&ptr_que->sema, CLX_SEMAPHORE_WAIT_FOREVER); + rc = osal_que_enque(&ptr_que->que_id, ptr_data); + osal_giveSemaphore(&ptr_que->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deQueue + * PURPOSE: + * To dequeue the target data. + * INPUT: + * ptr_que -- Pointer for the target queue + * pptr_data -- Pointer for the data pointer to be dequeued + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dequeue the data. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deQueue( + HAL_LIGHTNING_PKT_SW_QUEUE_T *ptr_que, + void **pptr_data) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_takeSemaphore(&ptr_que->sema, CLX_SEMAPHORE_WAIT_FOREVER); + rc = osal_que_deque(&ptr_que->que_id, pptr_data); + osal_giveSemaphore(&ptr_que->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_getQueueCount + * PURPOSE: + * To obtain the current GPD number in the target RX queue. + * INPUT: + * ptr_que -- Pointer for the target queue + * ptr_count -- Pointer for the data count + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully obtain the GPD count. + * CLX_E_BAD_PARAMETER -- Parameter pointer is null. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_getQueueCount( + HAL_LIGHTNING_PKT_SW_QUEUE_T *ptr_que, + UI32_T *ptr_count) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_takeSemaphore(&ptr_que->sema, CLX_SEMAPHORE_WAIT_FOREVER); + osal_que_getCount(&ptr_que->que_id, ptr_count); + osal_giveSemaphore(&ptr_que->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_allocRxPayloadBuf + * PURPOSE: + * To allocate the RX packet payload buffer for the GPD. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_idx -- The current GPD index + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully allocate the buffer. + * CLX_E_NO_MEMORY -- Allocate the buffer failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_allocRxPayloadBuf( + const UI32_T unit, + const UI32_T channel, + const UI32_T gpd_idx) +{ + CLX_ERROR_NO_T rc = CLX_E_NO_MEMORY; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + CLX_ADDR_T phy_addr = 0; + + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + struct sk_buff *ptr_skb = NULL; + + ptr_skb = osal_skb_alloc(ptr_rx_cb->buf_len); + if (NULL != ptr_skb) + { + /* map skb to dma */ + phy_addr = osal_skb_mapDma(ptr_skb, DMA_FROM_DEVICE); + if (0x0 == phy_addr) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, rxch=%u, skb dma map err, size=%u\n", + unit, channel, ptr_skb->len); + osal_skb_free(ptr_skb); + rc = CLX_E_NO_MEMORY; + } + else + { + ptr_rx_pdma->pptr_skb_ring[gpd_idx] = ptr_skb; + rc = CLX_E_OK; + } + } + + if (CLX_E_OK == rc) + { + ptr_rx_gpd->data_buf_addr_hi = CLX_ADDR_64_HI(phy_addr); + ptr_rx_gpd->data_buf_addr_lo = CLX_ADDR_64_LOW(phy_addr); + ptr_rx_gpd->avbl_buf_len = ptr_rx_cb->buf_len; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_freeRxPayloadBuf + * PURPOSE: + * To free the RX packet payload buffer for the GPD. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * gpd_idx -- The current GPD index + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully free the buffer. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_freeRxPayloadBuf( + const UI32_T unit, + const UI32_T channel, + const UI32_T gpd_idx) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + CLX_ADDR_T phy_addr = 0; + + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + struct sk_buff *ptr_skb = NULL; + + phy_addr = CLX_ADDR_32_TO_64(ptr_rx_gpd->data_buf_addr_hi, ptr_rx_gpd->data_buf_addr_lo); + if (0x0 != phy_addr) + { + /* unmap dma */ + ptr_skb = ptr_rx_pdma->pptr_skb_ring[gpd_idx]; + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_FROM_DEVICE); + osal_skb_free(ptr_skb); + rc = CLX_E_OK; + } + + if (CLX_E_OK == rc) + { + ptr_rx_gpd->data_buf_addr_hi = 0x0; + ptr_rx_gpd->data_buf_addr_lo = 0x0; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_freeRxPayloadBufGpd + * PURPOSE: + * To free the RX packet payload buffer for the GPD. + * INPUT: + * unit -- The unit ID + * ptr_sw_gpd -- The pointer of RX SW GPD + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully free the buffer. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_freeRxPayloadBufGpd( + const UI32_T unit, + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd) +{ + CLX_ERROR_NO_T rc = CLX_E_OTHERS; + CLX_ADDR_T phy_addr = 0; + + struct sk_buff *ptr_skb = NULL; + + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->rx_gpd.data_buf_addr_hi, ptr_sw_gpd->rx_gpd.data_buf_addr_lo); + if (0x0 != phy_addr) + { + ptr_skb = ptr_sw_gpd->ptr_cookie; + osal_skb_free(ptr_skb); + rc = CLX_E_OK; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_initTxPdmaRing + * PURPOSE: + * To initialize the GPD ring of target TX channel. + * + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the GPD ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initTxPdmaRing( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + CLX_ADDR_T phy_addr = 0; + UI32_T gpd_idx = 0; + + for (gpd_idx = 0; gpd_idx < ptr_tx_pdma->gpd_num; gpd_idx++) + { + ptr_tx_gpd = HAL_LIGHTNING_PKT_GET_TX_GPD_PTR(unit, channel, gpd_idx); + osal_memset((void *)ptr_tx_gpd, 0x0, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + ptr_tx_gpd->ioc = HAL_LIGHTNING_PKT_IOC_HAS_INTR; + ptr_tx_gpd->ch = HAL_LIGHTNING_PKT_CH_LAST_GPD; + ptr_tx_gpd->hwo = HAL_LIGHTNING_PKT_HWO_SW_OWN; + osal_dma_flushCache((void *)ptr_tx_gpd, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + } + + phy_addr = osal_dma_convertVirtToPhy(ptr_tx_pdma->ptr_gpd_align_start_addr); + rc = _hal_lightning_pkt_setTxGpdStartAddrReg(unit, channel, phy_addr, ptr_tx_pdma->gpd_num); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initRxPdmaRing + * PURPOSE: + * To initialize the RX GPD ring. + * INPUT: + * unit -- The target unit + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the RX GPD ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initRxPdmaRing( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + CLX_ADDR_T phy_addr = 0; + UI32_T gpd_idx = 0; + + for (gpd_idx = 0; gpd_idx < ptr_rx_pdma->gpd_num; gpd_idx++) + { + ptr_rx_gpd = HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + osal_memset((void *)ptr_rx_gpd, 0x0, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + ptr_rx_gpd->ioc = HAL_LIGHTNING_PKT_IOC_NO_INTR; + ptr_rx_gpd->hwo = HAL_LIGHTNING_PKT_HWO_SW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + } + + phy_addr = osal_dma_convertVirtToPhy(ptr_rx_pdma->ptr_gpd_align_start_addr); + rc = _hal_lightning_pkt_setRxGpdStartAddrReg(unit, channel, phy_addr, ptr_rx_pdma->gpd_num); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initRxPdmaRingBuf + * PURPOSE: + * To de-init the Rx PDMA ring configuration. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Rx PDMA ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initRxPdmaRingBuf( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + UI32_T gpd_idx = 0; + + if (0 == ptr_rx_cb->buf_len) + { + return (CLX_E_BAD_PARAMETER); + } + + for (gpd_idx = 0; gpd_idx < ptr_rx_pdma->gpd_num; gpd_idx++) + { + ptr_rx_gpd = HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + osal_dma_invalidateCache((void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + rc = _hal_lightning_pkt_allocRxPayloadBuf(unit, channel, gpd_idx); + if (CLX_E_OK == rc) + { + ptr_rx_gpd->ioc = HAL_LIGHTNING_PKT_IOC_HAS_INTR; + ptr_rx_gpd->hwo = HAL_LIGHTNING_PKT_HWO_HW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + } + else + { + ptr_rx_cb->cnt.no_memory++; + break; + } + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitRxPdmaRingBuf + * PURPOSE: + * To de-init the Rx PDMA ring configuration. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Rx PDMA ring. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitRxPdmaRingBuf( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + UI32_T gpd_idx = 0; + + for (gpd_idx = 0; ((gpd_idx < ptr_rx_pdma->gpd_num) && (CLX_E_OK == rc)); gpd_idx++) + { + /* mark the GPD as invalid to prevent Rx-done task to process it */ + ptr_rx_gpd = HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, gpd_idx); + ptr_rx_gpd->hwo = HAL_LIGHTNING_PKT_HWO_HW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + rc = _hal_lightning_pkt_freeRxPayloadBuf(unit, channel, gpd_idx); + } + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_recoverTxPdma + * PURPOSE: + * To recover the PDMA status to the initial state. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully recover PDMA. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_recoverTxPdma( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + + /* Release the software GPD ring and configure it again. */ + ptr_tx_pdma->used_idx = 0; + ptr_tx_pdma->free_idx = 0; + ptr_tx_pdma->used_gpd_num = 0; + ptr_tx_pdma->free_gpd_num = ptr_tx_pdma->gpd_num; + + _hal_lightning_pkt_stopTxChannelReg(unit, channel); + rc = _hal_lightning_pkt_initTxPdmaRing(unit, channel); + _hal_lightning_pkt_startTxChannelReg(unit, channel, 0); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_recoverRxPdma + * PURPOSE: + * To recover the RX PDMA from the error state. + * INPUT: + * unit -- The unit ID + * channel -- The target RX channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully recovery the PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_recoverRxPdma( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Release the software GPD ring and configure it again. */ + ptr_rx_pdma->cur_idx = 0; + + _hal_lightning_pkt_stopRxChannelReg(unit, channel); + rc = _hal_lightning_pkt_deinitRxPdmaRingBuf(unit, channel); + if (CLX_E_OK != rc) + { + return (rc); + } + rc = _hal_lightning_pkt_initRxPdmaRing(unit, channel); + if (CLX_E_OK != rc) + { + return (rc); + } + rc = _hal_lightning_pkt_initRxPdmaRingBuf(unit, channel); + if (CLX_E_OK != rc) + { + return (rc); + } + _hal_lightning_pkt_startRxChannelReg(unit, channel, ptr_rx_pdma->gpd_num); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_freeTxGpdList + * PURPOSE: + * To free the TX SW GPD link list. + * INPUT: + * unit -- The unit ID + * ptr_sw_gpd -- The pointer of TX SW GPD + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully free the GPD list. + * NOTES: + * None + */ +static void +_hal_lightning_pkt_freeTxGpdList( + UI32_T unit, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd_cur = NULL; + + while (NULL != ptr_sw_gpd) + { + ptr_sw_gpd_cur = ptr_sw_gpd; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + osal_free(ptr_sw_gpd_cur); + } +} + +/* FUNCTION NAME: _hal_lightning_pkt_freeRxGpdList + * PURPOSE: + * To free the RX SW GPD link list. + * INPUT: + * unit -- The unit ID + * ptr_sw_gpd -- The pointer of RX SW GPD + * free_payload -- TRUE: To free the buf in SDK, FALSE: in user process. + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully recovery the PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_freeRxGpdList( + UI32_T unit, + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd, + BOOL_T free_payload) +{ + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd_cur = NULL; + + while (NULL != ptr_sw_gpd) + { + ptr_sw_gpd_cur = ptr_sw_gpd; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + if (TRUE == free_payload) + { + _hal_lightning_pkt_freeRxPayloadBufGpd(unit, ptr_sw_gpd_cur); + } + osal_free(ptr_sw_gpd_cur); + } + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- pkt_drv */ +/* FUNCTION NAME: _hal_lightning_pkt_txEnQueueBulk + * PURPOSE: + * To enqueue numbers of packet in the bulk buffer + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * number -- The number of packet to be enqueue + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_lightning_pkt_txEnQueueBulk( + const UI32_T unit, + const UI32_T channel, + const UI32_T number) +{ + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd = NULL; + UI32_T idx; + + for (idx = 0; idx < number; idx++) + { + ptr_sw_gpd = ptr_tx_pdma->pptr_sw_gpd_bulk[idx]; + ptr_tx_pdma->pptr_sw_gpd_bulk[idx] = NULL; + if (NULL != ptr_sw_gpd->callback) + { + ptr_sw_gpd->callback(unit, ptr_sw_gpd, ptr_sw_gpd->ptr_cookie); + } + } +} + + +/* FUNCTION NAME: _hal_lightning_pkt_strictTxDeQueue + * PURPOSE: + * To dequeue the packets based on the strict algorithm. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the TX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dequeue the packets. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_strictTxDeQueue( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T *ptr_cookie) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd = NULL; + CLX_ADDR_T sw_gpd_addr; + UI32_T que_cnt = 0; + + /* get queue count */ + _hal_lightning_pkt_getQueueCount(&ptr_tx_cb->sw_queue, &que_cnt); + + /* wait txTask event */ + if (0 == que_cnt) + { + osal_waitEvent(&ptr_tx_cb->sync_sema); + if (FALSE == ptr_tx_cb->running) + { + return (CLX_E_OTHERS); /* deinit */ + } + + ptr_tx_cb->cnt.wait_event++; + + /* re-get queue count */ + _hal_lightning_pkt_getQueueCount(&ptr_tx_cb->sw_queue, &que_cnt); + } + + /* deque */ + if (que_cnt > 0) + { + rc = _hal_lightning_pkt_deQueue(&ptr_tx_cb->sw_queue, (void **)&ptr_sw_gpd); + if (CLX_E_OK == rc) + { + ptr_tx_cb->cnt.deque_ok++; + + sw_gpd_addr = (CLX_ADDR_T)ptr_sw_gpd->ptr_cookie; + + /* Give the address of pre-saved SW GPD back to userspace */ + osal_io_copyToUser(&ptr_cookie->done_sw_gpd_addr, + &sw_gpd_addr, + sizeof(CLX_ADDR_T)); + + /* free kernel sw_gpd */ + _hal_lightning_pkt_freeTxGpdList(unit, ptr_sw_gpd); + } + else + { + ptr_tx_cb->cnt.deque_fail++; + } + } + else + { + /* It may happen at last gpd, return error and do not invoke callback. */ + rc = CLX_E_OTHERS; + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_rxCheckReason + * PURPOSE: + * To check the packets to linux kernel/user. + * INPUT: + * ptr_rx_gpd -- Pointer of the RX GPD + * ptr_hit_prof -- Pointer of the hit flag + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dispatch the packets. + * NOTES: + * Reference to pkt_srv. + */ +static void +_hal_lightning_pkt_rxCheckReason( + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd, + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile, + BOOL_T *ptr_hit_prof) +{ + HAL_PKT_RX_REASON_BITMAP_T *ptr_reason_bitmap = &ptr_profile->reason_bitmap; + UI32_T bitval = 0; + UI32_T bitmap = 0x0; + + if (0 == (ptr_profile->flags & HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_REASON)) + { + /* It means that reason doesn't metters */ + *ptr_hit_prof = TRUE; + return; + } + +#define HAL_LIGHTNING_PKT_DI_NON_L3_CPU_MIN (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_NON_L3_MIN) +#define HAL_LIGHTNING_PKT_DI_NON_L3_CPU_MAX (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_NON_L3_MAX) +#define HAL_LIGHTNING_PKT_DI_L3_CPU_MIN (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_L3_MIN) +#define HAL_LIGHTNING_PKT_DI_L3_CPU_MAX (HAL_EXCPT_CPU_BASE_ID + HAL_EXCPT_CPU_L3_MAX) + + switch (ptr_rx_gpd->itmh_eth.typ) + { + case HAL_LIGHTNING_PKT_TMH_TYPE_ITMH_ETH: + + /* IPP non-L3 exception */ + if (ptr_rx_gpd->itmh_eth.dst_idx >= HAL_LIGHTNING_PKT_DI_NON_L3_CPU_MIN && + ptr_rx_gpd->itmh_eth.dst_idx <= HAL_LIGHTNING_PKT_DI_NON_L3_CPU_MAX) + { + bitval = ptr_rx_gpd->itmh_eth.dst_idx - HAL_LIGHTNING_PKT_DI_NON_L3_CPU_MIN; + bitmap = 1UL << (bitval % 32); + if (0 != (ptr_reason_bitmap->ipp_excpt_bitmap[bitval / 32] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + } + + /* IPP L3 exception */ + if (ptr_rx_gpd->itmh_eth.dst_idx >= HAL_LIGHTNING_PKT_DI_L3_CPU_MIN && + ptr_rx_gpd->itmh_eth.dst_idx <= HAL_LIGHTNING_PKT_DI_L3_CPU_MAX) + { + bitmap = ptr_rx_gpd->itmh_eth.dst_idx - HAL_LIGHTNING_PKT_DI_L3_CPU_MIN; + if (0 != (ptr_reason_bitmap->ipp_l3_excpt_bitmap[0] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + } + + /* IPP cp_to_cpu_bmap */ + bitmap = ptr_rx_gpd->itmh_eth.cp_to_cpu_bmap; + if (0 != (ptr_reason_bitmap->ipp_copy2cpu_bitmap[0] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + + /* IPP cp_to_cpu_rsn */ + bitval = ptr_rx_gpd->itmh_eth.cp_to_cpu_code; + bitmap = 1UL << (bitval % 32); + if (0 != (ptr_reason_bitmap->ipp_rsn_bitmap[bitval / 32] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + break; + + case HAL_LIGHTNING_PKT_TMH_TYPE_ITMH_FAB: + case HAL_LIGHTNING_PKT_TMH_TYPE_ETMH_FAB: + break; + + case HAL_LIGHTNING_PKT_TMH_TYPE_ETMH_ETH: + + /* EPP exception */ + if (1 == ptr_rx_gpd->etmh_eth.redir) + { + bitval = ptr_rx_gpd->etmh_eth.excpt_code_mir_bmap; + bitmap = 1UL << (bitval % 32); + if (0 != (ptr_reason_bitmap->epp_excpt_bitmap[bitval / 32] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + } + + /* EPP cp_to_cpu_bmap */ + bitmap = ((ptr_rx_gpd->etmh_eth.cp_to_cpu_bmap_w0 << 7) | + (ptr_rx_gpd->etmh_eth.cp_to_cpu_bmap_w1)); + if (0 != (ptr_reason_bitmap->epp_copy2cpu_bitmap[0] & bitmap)) + { + *ptr_hit_prof = TRUE; + break; + } + break; + + default: + *ptr_hit_prof = FALSE; + break; + } +} + +static BOOL_T +_hal_lightning_pkt_comparePatternWithPayload( + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd, + const UI8_T *ptr_pattern, + const UI8_T *ptr_mask, + const UI32_T offset) +{ + CLX_ADDR_T phy_addr = 0; + UI8_T *ptr_virt_addr = NULL; + UI32_T idx; + + /* Get the packet payload */ + phy_addr = CLX_ADDR_32_TO_64(ptr_rx_gpd->data_buf_addr_hi, ptr_rx_gpd->data_buf_addr_lo); + ptr_virt_addr = (C8_T *) osal_dma_convertPhyToVirt(phy_addr); + + for (idx=0; idxflags & (HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_0 | + HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_1 | + HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_2 | + HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_3)) != 0) + { + /* Need to compare the payload with at least one of the four patterns */ + /* Pre-assume that the result is positive */ + *ptr_hit_prof = TRUE; + + /* If any of the following comparison fails, the result will be changed to negtive */ + } + else + { + return; + } + + for (idx=0; idxflags & (HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_0 << idx))) + { + match = _hal_lightning_pkt_comparePatternWithPayload(ptr_rx_gpd, + ptr_profile->pattern[idx], + ptr_profile->mask[idx], + ptr_profile->offset[idx]); + if (TRUE == match) + { + /* Do nothing */ + } + else + { + /* Change the result to negtive */ + *ptr_hit_prof = FALSE; + break; + } + } + } +} + +static void +_hal_lightning_pkt_matchUserProfile( + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd, + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_profile_list, + HAL_LIGHTNING_PKT_NETIF_PROFILE_T **pptr_profile_hit) +{ + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_curr_node = ptr_profile_list; + BOOL_T hit; + + *pptr_profile_hit = NULL; + + while (NULL != ptr_curr_node) + { + /* 1st match reason */ + _hal_lightning_pkt_rxCheckReason(ptr_rx_gpd, ptr_curr_node->ptr_profile, &hit); + if (TRUE == hit) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "rx prof matched by reason\n"); + + /* Then, check pattern */ + _hal_lightning_pkt_rxCheckPattern(ptr_rx_gpd, ptr_curr_node->ptr_profile, &hit); + if (TRUE == hit) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "rx prof matched by pattern\n"); + + *pptr_profile_hit = ptr_curr_node->ptr_profile; + break; + } + } + + /* Seach the next profile (priority lower) */ + ptr_curr_node = ptr_curr_node->ptr_next_node; + } +} + +static void +_hal_lightning_pkt_getPacketDest( + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd, + HAL_LIGHTNING_PKT_DEST_T *ptr_dest, + void **pptr_cookie) +{ + UI32_T port; + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_profile_list; + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile_hit; + + port = ptr_rx_gpd->itmh_eth.igr_phy_port; + ptr_profile_list = HAL_LIGHTNING_PKT_GET_PORT_PROFILE_LIST(port); + + _hal_lightning_pkt_matchUserProfile(ptr_rx_gpd, + ptr_profile_list, + &ptr_profile_hit); + if (NULL != ptr_profile_hit) + { +#if defined(NETIF_EN_NETLINK) + if (HAL_LIGHTNING_PKT_NETIF_RX_DST_NETLINK == ptr_profile_hit->dst_type) + { + *ptr_dest = HAL_LIGHTNING_PKT_DEST_NETLINK; + *pptr_cookie = (void *)&ptr_profile_hit->netlink; + } + else + { + *ptr_dest = HAL_LIGHTNING_PKT_DEST_SDK; + } +#else + *ptr_dest = HAL_LIGHTNING_PKT_DEST_SDK; +#endif + } + else + { + *ptr_dest = HAL_LIGHTNING_PKT_DEST_NETDEV; + } +} + +/* FUNCTION NAME: _hal_lightning_pkt_rxEnQueue + * PURPOSE: + * To enqueue the packets to multiple queues. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * ptr_sw_gpd -- Pointer for the SW Rx GPD link list + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully enqueue the packets. + * NOTES: + * None + */ +static void +_hal_lightning_pkt_rxEnQueue( + const UI32_T unit, + const UI32_T channel, + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd) +{ + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_first_gpd = ptr_sw_gpd; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0; + HAL_LIGHTNING_PKT_DEST_T dest_type; + + /* skb meta */ + UI32_T port = 0, len = 0, total_len = 0; + struct net_device *ptr_net_dev = NULL; + struct net_device_priv *ptr_priv = NULL; + struct sk_buff *ptr_skb = NULL, *ptr_merge_skb = NULL; + UI32_T copy_offset; + void *ptr_dest; + +#if defined(PERF_EN_TEST) + /* To verify kernel Rx performance */ + if (CLX_E_OK == perf_rxTest()) + { + while (NULL != ptr_sw_gpd) + { + len += (HAL_LIGHTNING_PKT_CH_LAST_GPD == ptr_sw_gpd->rx_gpd.ch)? + ptr_sw_gpd->rx_gpd.cnsm_buf_len : ptr_sw_gpd->rx_gpd.avbl_buf_len; + + total_len += len; + + /* unmap dma */ + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->rx_gpd.data_buf_addr_hi, ptr_sw_gpd->rx_gpd.data_buf_addr_lo); + osal_skb_unmapDma(phy_addr, len, DMA_FROM_DEVICE); + /* next */ + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + perf_rxCallback(total_len); + _hal_lightning_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, TRUE); + return ; + } +#endif + + _hal_lightning_pkt_getPacketDest(&ptr_sw_gpd->rx_gpd, &dest_type, &ptr_dest); + +#if defined(NETIF_EN_NETLINK) + if ((HAL_LIGHTNING_PKT_DEST_NETDEV == dest_type) || + (HAL_LIGHTNING_PKT_DEST_NETLINK == dest_type)) +#else + if (HAL_LIGHTNING_PKT_DEST_NETDEV == dest_type) +#endif + { + /* need to encap the packet as skb */ + ptr_sw_gpd = ptr_sw_first_gpd; + while (NULL != ptr_sw_gpd) + { + len = (HAL_LIGHTNING_PKT_CH_LAST_GPD == ptr_sw_gpd->rx_gpd.ch)? + ptr_sw_gpd->rx_gpd.cnsm_buf_len : ptr_sw_gpd->rx_gpd.avbl_buf_len; + + total_len += len; + + /* unmap dma */ + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->rx_gpd.data_buf_addr_hi, ptr_sw_gpd->rx_gpd.data_buf_addr_lo); + ptr_virt_addr = ptr_sw_gpd->ptr_cookie; + + ptr_skb = (struct sk_buff *)ptr_virt_addr; + + /* note here ptr_skb->len is the total buffer size not means the actual Rx packet len + * it should be updated later + */ + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_FROM_DEVICE); + + /* reset ptr_skb->len with real packet len instead of total buffer size */ + if (NULL == ptr_sw_gpd->ptr_next) + { + /* strip CRC padded by asic for the last gpd segment */ + ptr_skb->len = len - ETH_FCS_LEN; + } + else + { + ptr_skb->len = len; + } + + skb_set_tail_pointer(ptr_skb, ptr_skb->len); + + /* next */ + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + + port = ptr_sw_first_gpd->rx_gpd.itmh_eth.igr_phy_port; + ptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + + /* if the packet is composed of multiple gpd (skb), need to merge it into a single skb */ + if (NULL != ptr_sw_first_gpd->ptr_next) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, rcv pkt size=%u > gpd buf size=%u\n", + unit, channel, total_len, ptr_rx_cb->buf_len); + ptr_merge_skb = osal_skb_alloc(total_len - ETH_FCS_LEN); + if (NULL != ptr_merge_skb) + { + copy_offset = 0; + ptr_sw_gpd = ptr_sw_first_gpd; + while (NULL != ptr_sw_gpd) + { + ptr_skb = (struct sk_buff *)ptr_sw_gpd->ptr_cookie; + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, copy size=%u to buf offset=%u\n", + unit, channel, ptr_skb->len, copy_offset); + + memcpy(&(((UI8_T *)ptr_merge_skb->data)[copy_offset]), + ptr_skb->data, ptr_skb->len); + copy_offset += ptr_skb->len; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + /* put the merged skb to ptr_skb for the following process */ + ptr_skb = ptr_merge_skb; + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, alloc skb failed, size=%u\n", + unit, channel, (total_len - ETH_FCS_LEN)); + } + + /* free both sw_gpd and the skb attached on it */ + _hal_lightning_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, TRUE); + } + else + { + /* free only sw_gpd */ + _hal_lightning_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, FALSE); + } + + /* if NULL netdev, drop the skb */ + if (NULL == ptr_net_dev) + { + ptr_rx_cb->cnt.channel[channel].netdev_miss++; + osal_skb_free(ptr_skb); + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, find netdev failed\n", + unit, channel); + return; + } + + /* skb handling */ + ptr_skb->dev = ptr_net_dev; + ptr_skb->pkt_type = PACKET_HOST; /* this packet is for me */ + ptr_skb->ip_summed = CHECKSUM_UNNECESSARY; /* skip checksum */ + + /* send to linux */ + if (dest_type == HAL_LIGHTNING_PKT_DEST_NETDEV) + { + /* skip ethernet header only for Linux net interface*/ + ptr_skb->protocol = eth_type_trans(ptr_skb, ptr_net_dev); + osal_skb_recv(ptr_skb); +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0) + ptr_net_dev->last_rx = jiffies; +#endif + ptr_priv = netdev_priv(ptr_net_dev); + ptr_priv->stats.rx_packets++; + ptr_priv->stats.rx_bytes += total_len; + } +#if defined(NETIF_EN_NETLINK) + else + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "hit profile dest=netlink, name=%s, mcgrp=%s\n", + ((NETIF_NL_RX_DST_NETLINK_T *)ptr_dest)->name, + ((NETIF_NL_RX_DST_NETLINK_T *)ptr_dest)->mc_group_name); + netif_nl_rxSkb(unit, ptr_skb, ptr_dest); + } +#endif + } + else if (HAL_LIGHTNING_PKT_DEST_SDK == dest_type) + { + while (0 != _hal_lightning_pkt_enQueue(&ptr_rx_cb->sw_queue[channel], ptr_sw_gpd)) + { + ptr_rx_cb->cnt.channel[channel].enque_retry++; + HAL_LIGHTNING_PKT_RX_ENQUE_RETRY_SLEEP(); + } + ptr_rx_cb->cnt.channel[channel].enque_ok++; + + osal_triggerEvent(&ptr_rx_cb->sync_sema); + ptr_rx_cb->cnt.channel[channel].trig_event++; + } + else if (HAL_LIGHTNING_PKT_DEST_DROP == dest_type) + { + _hal_lightning_pkt_freeRxGpdList(unit, ptr_sw_first_gpd, TRUE); + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, invalid pkt dest=%d\n", + unit, channel, dest_type); + } +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_flushRxQueue( + const UI32_T unit, + HAL_LIGHTNING_PKT_SW_QUEUE_T *ptr_que) +{ + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd_knl = NULL; + CLX_ERROR_NO_T rc; + + while (1) + { + rc = _hal_lightning_pkt_deQueue(ptr_que, (void **)&ptr_sw_gpd_knl); + if (CLX_E_OK == rc) + { + _hal_lightning_pkt_freeRxGpdList(unit, ptr_sw_gpd_knl, TRUE); + } + else + { + break; + } + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_schedRxDeQueue + * PURPOSE: + * To dequeue the packets based on the configured algorithm. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dequeue the packets. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_schedRxDeQueue( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T ioctl_data; + HAL_LIGHTNING_PKT_IOCTL_RX_GPD_T ioctl_gpd; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd_knl = NULL; + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_first_gpd_knl = NULL; + UI32_T que_cnt = 0; + UI32_T queue = 0; + UI32_T idx = 0; + UI32_T gpd_idx = 0; + /* copy Rx sw_gpd */ + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0; + UI32_T buf_len = 0; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* normal process */ + if (TRUE == ptr_rx_cb->running) + { + /* get queue and count */ + for (idx = 0; idx < HAL_LIGHTNING_PKT_RX_QUEUE_NUM; idx++) + { + /* to gurantee the opportunity where each queue can be handler */ + queue = ((ptr_rx_cb->deque_idx + idx) % HAL_LIGHTNING_PKT_RX_QUEUE_NUM); + _hal_lightning_pkt_getQueueCount(&ptr_rx_cb->sw_queue[queue], &que_cnt); + if (que_cnt > 0) + { + ptr_rx_cb->deque_idx = ((queue + 1) % HAL_LIGHTNING_PKT_RX_QUEUE_NUM); + break; + } + } + + /* If all of the queues are empty, wait rxTask event */ + if (0 == que_cnt) + { + osal_waitEvent(&ptr_rx_cb->sync_sema); + + ptr_rx_cb->cnt.wait_event++; + + /* re-get queue and count */ + for (queue = 0; queue < HAL_LIGHTNING_PKT_RX_QUEUE_NUM; queue++) + { + _hal_lightning_pkt_getQueueCount(&ptr_rx_cb->sw_queue[queue], &que_cnt); + if (que_cnt > 0) + { + ptr_rx_cb->deque_idx = ((queue + 1) % HAL_LIGHTNING_PKT_RX_QUEUE_NUM); + break; + } + } + } + + /* deque */ + if ((que_cnt > 0) && (queue < HAL_LIGHTNING_PKT_RX_QUEUE_NUM)) + { + rc = _hal_lightning_pkt_deQueue(&ptr_rx_cb->sw_queue[queue], (void **)&ptr_sw_gpd_knl); + if (CLX_E_OK == rc) + { + ptr_rx_cb->cnt.channel[queue].deque_ok++; + ptr_sw_first_gpd_knl = ptr_sw_gpd_knl; + + osal_io_copyFromUser(&ioctl_data, ptr_cookie, sizeof(HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T)); + + while (NULL != ptr_sw_gpd_knl) + { + /* get the IOCTL GPD from user */ + osal_io_copyFromUser(&ioctl_gpd, + ((void *)((CLX_HUGE_T)ioctl_data.ioctl_gpd_addr)) + + gpd_idx*sizeof(HAL_LIGHTNING_PKT_IOCTL_RX_GPD_T), + sizeof(HAL_LIGHTNING_PKT_IOCTL_RX_GPD_T)); + + /* get knl buf addr */ + ptr_rx_gpd = &ptr_sw_gpd_knl->rx_gpd; + phy_addr = CLX_ADDR_32_TO_64(ptr_rx_gpd->data_buf_addr_hi, ptr_rx_gpd->data_buf_addr_lo); + + ptr_virt_addr = ptr_sw_gpd_knl->ptr_cookie; + osal_skb_unmapDma(phy_addr, ((struct sk_buff *)ptr_virt_addr)->len, DMA_FROM_DEVICE); + + buf_len = (HAL_LIGHTNING_PKT_CH_LAST_GPD == ptr_rx_gpd->ch)? + ptr_rx_gpd->cnsm_buf_len : ptr_rx_gpd->avbl_buf_len; + + /* overwrite whole rx_gpd to user + * the user should re-assign the correct value to data_buf_addr_hi, data_buf_addr_low + * after this IOCTL returns + */ + osal_io_copyToUser((void *)((CLX_HUGE_T)ioctl_gpd.hw_gpd_addr), + &ptr_sw_gpd_knl->rx_gpd, + sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + /* copy buf */ + /* DMA buf address allocated by the user is store in ptr_ioctl_data->gpd[idx].cookie */ + osal_io_copyToUser((void *)((CLX_HUGE_T)ioctl_gpd.dma_buf_addr), + ((struct sk_buff *)ptr_virt_addr)->data, buf_len); + ptr_sw_gpd_knl->ptr_cookie = ptr_virt_addr; + + /* next */ + ptr_sw_gpd_knl = ptr_sw_gpd_knl->ptr_next; + gpd_idx++; + } + + /* Must free kernel sw_gpd */ + _hal_lightning_pkt_freeRxGpdList(unit, ptr_sw_first_gpd_knl, TRUE); + } + else + { + ptr_rx_cb->cnt.channel[queue].deque_fail++; + } + } + else + { + /* it means that all queue's are flush -> rx stop flow */ + rc = CLX_E_OTHERS; + } + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_waitTxDone + * PURPOSE: + * To determine the next action after transfer the packet to HW. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * ptr_sw_gpd -- Pointer for the SW Tx GPD link list + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully perform the target action. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_waitTxDone( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + UI32_T last_gpd_idx = 0; + UI32_T loop_cnt = 0; + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + ; + } + else if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + osal_takeSemaphore(&ptr_tx_pdma->sync_intr_sema, HAL_LIGHTNING_PKT_PDMA_TX_INTR_TIMEOUT); + /* rc = _hal_lightning_pkt_invokeTxGpdCallback(unit, ptr_sw_gpd); */ + } + else if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_POLL == ptr_tx_cb->wait_mode) + { + last_gpd_idx = ptr_tx_pdma->free_idx + ptr_tx_pdma->used_gpd_num; + last_gpd_idx %= ptr_tx_pdma->gpd_num; + ptr_tx_gpd = HAL_LIGHTNING_PKT_GET_TX_GPD_PTR(unit, channel, last_gpd_idx); + + while (HAL_LIGHTNING_PKT_HWO_HW_OWN == ptr_tx_gpd->hwo) + { + osal_dma_invalidateCache((void *)ptr_tx_gpd, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + loop_cnt++; + if (0 == loop_cnt % HAL_LIGHTNING_PKT_PDMA_TX_POLL_MAX_LOOP) + { + ptr_tx_cb->cnt.channel[channel].poll_timeout++; + rc = CLX_E_OTHERS; + break; + } + } + if (HAL_LIGHTNING_PKT_ECC_ERROR_OCCUR == ptr_tx_gpd->ecce) + { + ptr_tx_cb->cnt.channel[channel].ecc_err++; + } + if (CLX_E_OK == rc) + { + ptr_tx_pdma->free_gpd_num += ptr_tx_pdma->used_gpd_num; + ptr_tx_pdma->used_gpd_num = 0; + ptr_tx_pdma->free_idx = ptr_tx_pdma->used_idx; + /* rc = _hal_lightning_pkt_invokeTxGpdCallback(unit, ptr_sw_gpd); */ + } + } + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_resumeAllIntf( + const UI32_T unit) +{ + struct net_device *ptr_net_dev = NULL; + UI32_T port; + + /* Unregister net devices by id */ + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + if (NULL != ptr_net_dev) + { + if (netif_queue_stopped(ptr_net_dev)) + { + netif_wake_queue(ptr_net_dev); + } + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_suspendAllIntf( + const UI32_T unit) +{ + struct net_device *ptr_net_dev = NULL; + UI32_T port; + + /* Unregister net devices by id */ + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + if (NULL != ptr_net_dev) + { + netif_stop_queue(ptr_net_dev); + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_stopAllIntf( + const UI32_T unit) +{ + struct net_device *ptr_net_dev = NULL; + UI32_T port; + + /* Unregister net devices by id */ + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + if (NULL != ptr_net_dev) + { + netif_tx_disable(ptr_net_dev); + } + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_sendGpd + * PURPOSE: + * To perform the packet transmission form CPU to the switch. + * INPUT: + * unit -- The unit ID + * channel -- The target TX channel + * ptr_sw_gpd -- Pointer for the SW Tx GPD link list + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully perform the transferring. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_sendGpd( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_first_gpd = ptr_sw_gpd; + UI32_T used_idx = 0; + UI32_T used_gpd_num = ptr_sw_gpd->gpd_num; + CLX_IRQ_FLAGS_T irq_flags; + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + + if (0 != (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_TASK)) + { + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irq_flags); + + /* If not PDMA error */ + if (FALSE == ptr_tx_pdma->err_flag) + { + /* Make Sure GPD is enough */ + if (ptr_tx_pdma->free_gpd_num >= used_gpd_num) + { + used_idx = ptr_tx_pdma->used_idx; + while (NULL != ptr_sw_gpd) + { + ptr_tx_gpd = HAL_LIGHTNING_PKT_GET_TX_GPD_PTR(unit, channel, used_idx); + osal_dma_invalidateCache((void *)ptr_tx_gpd, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + if (HAL_LIGHTNING_PKT_HWO_HW_OWN == ptr_tx_gpd->hwo) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, free gpd idx out-of-sync\n", + unit, channel); + rc = CLX_E_TABLE_FULL; + break; + } + + /* Fill in HW-GPD Ring */ + osal_memcpy((void *)ptr_tx_gpd, &ptr_sw_gpd->tx_gpd, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + osal_dma_flushCache((void *)ptr_tx_gpd, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + /* next */ + used_idx++; + used_idx %= ptr_tx_pdma->gpd_num; + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + } + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* Fill 1st GPD in SW-GPD Ring */ + ptr_tx_pdma->pptr_sw_gpd_ring[ptr_tx_pdma->used_idx] = ptr_sw_first_gpd; + } + + /* update Tx PDMA */ + ptr_tx_pdma->used_idx = used_idx; + ptr_tx_pdma->used_gpd_num += used_gpd_num; + ptr_tx_pdma->free_gpd_num -= used_gpd_num; + + _hal_lightning_pkt_resumeTxChannelReg(unit, channel, used_gpd_num); + ptr_tx_cb->cnt.channel[channel].send_ok++; + + _hal_lightning_pkt_waitTxDone(unit, channel, ptr_sw_first_gpd); + + /* reserve 1 packet buffer for each port in case that the suspension is too late */ +#define HAL_LIGHTNING_PKT_KNL_TX_RING_AVBL_GPD_LOW (HAL_LIGHTNING_PORT_NUM) + if (ptr_tx_pdma->free_gpd_num < HAL_LIGHTNING_PKT_KNL_TX_RING_AVBL_GPD_LOW) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "u=%u, txch=%u, tx avbl gpd < %d, suspend all netdev\n", + unit, channel, HAL_LIGHTNING_PKT_KNL_TX_RING_AVBL_GPD_LOW); + _hal_lightning_pkt_suspendAllIntf(unit); + } + } + else + { + rc = CLX_E_TABLE_FULL; + } + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma hw err\n", + unit, channel); + rc = CLX_E_OTHERS; + } + + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irq_flags); + } + else + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "Tx failed, task already deinit\n"); + rc = CLX_E_OTHERS; + } + return (rc); +} + +/* ----------------------------------------------------------------------------------- pkt_srv */ +/* ----------------------------------------------------------------------------------- Rx Init */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_rxStop( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CHANNEL_T channel = 0; + UI32_T idx; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = NULL; + + /* Check if Rx is already stopped*/ + if (0 == (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_RX_START)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rx stop failed, not started\n", unit); + return (CLX_E_OK); + } + + /* Check if PKT Drv/Task were de-init before stopping Rx */ + /* Currently, we help to stop Rx when deinit Drv/Task, so it shouldn't enter below logic */ + if ((0 == (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_TASK)) || + (0 == (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_DRV))) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rx stop failed, pkt task & pkt drv not init\n", unit); + return (CLX_E_OK); + } + + /* Deinit Rx PDMA and free buf for Rx GPD */ + for (channel = 0; channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; channel++) + { + ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + _hal_lightning_pkt_stopRxChannelReg(unit, channel); + rc = _hal_lightning_pkt_deinitRxPdmaRingBuf(unit, channel); + osal_giveSemaphore(&ptr_rx_pdma->sema); + } + + + /* flush packets in all queues since Rx task may be blocked in user space + * in this case it won't do ioctl to kernel to handle remaining packets + */ + for (idx = 0; idx < HAL_LIGHTNING_PKT_RX_QUEUE_NUM; idx++) + { + _hal_lightning_pkt_flushRxQueue(unit, &ptr_rx_cb->sw_queue[idx]); + } + + /* Return user thread */ + ptr_rx_cb->running = FALSE; + ptr_cb->init_flag &= (~HAL_LIGHTNING_PKT_INIT_RX_START); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rx stop done, init flag=0x%x\n", unit, ptr_cb->init_flag); + + osal_triggerEvent(&ptr_rx_cb->sync_sema); + + return (rc); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_rxStart( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CHANNEL_T channel = 0; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = NULL; + + if (0 != (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_RX_START)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rx start failed, already started\n", unit); + return (CLX_E_OK); + } + + /* init Rx PDMA and alloc buf for Rx GPD */ + for (channel = 0; channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; channel++) + { + ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + rc = _hal_lightning_pkt_initRxPdmaRingBuf(unit, channel); + if (CLX_E_OK == rc) + { + ptr_rx_pdma->cur_idx = 0; + _hal_lightning_pkt_startRxChannelReg(unit, channel, ptr_rx_pdma->gpd_num); + } + osal_giveSemaphore(&ptr_rx_pdma->sema); + } + + /* enable to dequeue rx packets */ + ptr_rx_cb->running = TRUE; + + /* set the flag to record init state */ + ptr_cb->init_flag |= HAL_LIGHTNING_PKT_INIT_RX_START; + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rx start done, init flag=0x%x\n", unit, ptr_cb->init_flag); + return (rc); +} + +/* FUNCTION NAME: hal_lightning_pkt_setRxKnlConfig + * PURPOSE: + * 1. To stop the Rx channel and deinit the Rx subsystem. + * 2. To init the Rx subsystem and start the Rx channel. + * 3. To restart the Rx subsystem + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the RX parameters. + * CLX_E_OTHERS -- Configure the parameter failed. + * NOTES: + * + */ +CLX_ERROR_NO_T +hal_lightning_pkt_setRxKnlConfig( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_T rx_type = HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_LAST; + + osal_io_copyFromUser(&rx_type, &ptr_cookie->rx_type, sizeof(HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_T)); + + if (HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_DEINIT == rx_type) + { + _hal_lightning_pkt_rxStop(unit); + } + if (HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_INIT == rx_type) + { + /* To prevent buffer size from being on-the-fly changed */ + if (0 != (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_RX_START)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rx stop failed, not started\n", unit); + return (CLX_E_OK); + } + + osal_io_copyFromUser(&ptr_rx_cb->buf_len, &ptr_cookie->buf_len, sizeof(UI32_T)); + _hal_lightning_pkt_rxStart(unit); + } + + return (rc); +} + +/* FUNCTION NAME: hal_lightning_pkt_getRxKnlConfig + * PURPOSE: + * To get the Rx subsystem configuration. + * INPUT: + * unit -- The unit ID + * ptr_cookie -- Pointer of the RX cookie + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure the RX parameters. + * CLX_E_OTHERS -- Configure the parameter failed. + * NOTES: + * + */ +CLX_ERROR_NO_T +hal_lightning_pkt_getRxKnlConfig( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + + osal_io_copyToUser(&ptr_cookie->buf_len, &ptr_rx_cb->buf_len, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Deinit */ +/* FUNCTION NAME: hal_lightning_pkt_deinitTask + * PURPOSE: + * To de-initialize the Task for packet module. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dinitialize the control block. + * CLX_E_OTHERS -- Initialize the control block failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_deinitTask( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + UI32_T channel = 0; + + /* to prevent net intf from Tx packet */ + ptr_tx_cb->net_tx_allowed = FALSE; + + /* In case that some undestroyed net intf keep Tx after task deinit */ + _hal_lightning_pkt_stopAllIntf(unit); + + if (0 == (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_TASK)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rx stop failed, not started\n", unit); + return (CLX_E_OK); + } + + /* Need to stop Rx before de-init Task */ + if (0 != (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_RX_START)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, pkt task deinit failed, rx not stop\n", unit); + + _hal_lightning_pkt_rxStop(unit); + } + + /* Make the Rx IOCTL from userspace return back*/ + osal_triggerEvent(&ptr_rx_cb->sync_sema); + + /* Destroy txTask */ + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + ptr_tx_cb->running = FALSE; + osal_triggerEvent(&ptr_tx_cb->sync_sema); + } + + /* Destroy handleRxDoneTask */ + for (channel = 0; channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; channel++) + { + osal_stopThread(&ptr_rx_cb->isr_task_id[channel]); + osal_triggerEvent(HAL_LIGHTNING_PKT_RCH_EVENT(unit, channel)); + osal_destroyThread(&ptr_rx_cb->isr_task_id[channel]); + } + + /* Destroy handleTxDoneTask */ + for (channel = 0; channel < HAL_LIGHTNING_PKT_TX_CHANNEL_LAST; channel++) + { + osal_stopThread(&ptr_tx_cb->isr_task_id[channel]); + osal_triggerEvent(HAL_LIGHTNING_PKT_TCH_EVENT(unit, channel)); + osal_destroyThread(&ptr_tx_cb->isr_task_id[channel]); + } + + /* Destroy handleErrorTask */ + osal_stopThread(&ptr_cb->err_task_id); + osal_triggerEvent(HAL_LIGHTNING_PKT_ERR_EVENT(unit)); + osal_destroyThread(&ptr_cb->err_task_id); + + /* Set the flag to record init state */ + ptr_cb->init_flag &= (~HAL_LIGHTNING_PKT_INIT_TASK); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, pkt task deinit done, init flag=0x%x\n", + unit, ptr_cb->init_flag); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitTxPdma + * PURPOSE: + * To de-initialize the Tx PDMA configuration of the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target Tx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Tx PDMA. + * CLX_E_OTHERS -- De-init the Tx PDMA failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitTxPdma( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + + _hal_lightning_pkt_stopTxChannelReg(unit, channel); + + /* Free DMA and flush queue */ + osal_dma_free(ptr_tx_pdma->ptr_gpd_start_addr); + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + osal_free(ptr_tx_pdma->pptr_sw_gpd_ring); + osal_free(ptr_tx_pdma->pptr_sw_gpd_bulk); + } + else if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + osal_destroySemaphore(&ptr_tx_pdma->sync_intr_sema); + } + + osal_destroyIsrLock(&ptr_tx_pdma->ring_lock); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitRxPdma + * PURPOSE: + * To de-initialize the Rx PDMA configuration of the specified channel. + * INPUT: + * unit -- The unit ID + * channel -- The target Rx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the Rx PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitRxPdma( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Free DMA */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + osal_dma_free(ptr_rx_pdma->ptr_gpd_start_addr); + osal_giveSemaphore(&ptr_rx_pdma->sema); + osal_destroySemaphore(&ptr_rx_pdma->sema); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitPktCb + * PURPOSE: + * To de-init the control block of Drv. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitPktCb( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + UI32_T idx = 0, vec = sizeof(_hal_lightning_pkt_intr_vec) / sizeof(HAL_LIGHTNING_PKT_INTR_VEC_T); + + for (idx = 0; idx < vec; idx++) + { + osal_destroyEvent(&_hal_lightning_pkt_intr_vec[idx].intr_event); + ptr_cb->intr_bitmap &= ~(_hal_lightning_pkt_intr_vec[idx].intr_reg); + } + + /* Unregister PKT interrupt functions */ + osal_mdc_registerIsr(unit, NULL, NULL); + osal_destroyIsrLock(&ptr_cb->intr_lock); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitPktTxCb + * PURPOSE: + * To de-init the control block of Tx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitPktTxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_CHANNEL_T channel = 0; + + /* Deinitialize TX PDMA sub-system.*/ + for (channel = 0; channel < HAL_LIGHTNING_PKT_TX_CHANNEL_LAST; channel++) + { + _hal_lightning_pkt_deinitTxPdma(unit, channel); + } + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* Destroy the sync semaphore of txTask */ + osal_destroyEvent(&ptr_tx_cb->sync_sema); + + /* Deinitialize Tx GPD-queue (of first SW-GPD) from handleTxDoneTask to txTask */ + osal_destroySemaphore(&ptr_tx_cb->sw_queue.sema); + osal_que_destroy(&ptr_tx_cb->sw_queue.que_id); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitPktRxCb + * PURPOSE: + * To de-init the control block of Rx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-init the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitPktRxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_CHANNEL_T channel = 0; + UI32_T queue = 0; + + /* Deinitialize RX PDMA sub-system */ + for (channel = 0; channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; channel++) + { + _hal_lightning_pkt_deinitRxPdma(unit, channel); + } + + /* Destroy the sync semaphore of rxTask */ + osal_destroyEvent(&ptr_rx_cb->sync_sema); + + /* Deinitialize Rx GPD-queue (of first SW-GPD) from handleRxDoneTask to rxTask */ + for (queue = 0; queue < HAL_LIGHTNING_PKT_RX_QUEUE_NUM; queue++) + { + osal_destroySemaphore(&ptr_rx_cb->sw_queue[queue].sema); + osal_que_destroy(&ptr_rx_cb->sw_queue[queue].que_id); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitL1Isr + * PURPOSE: + * To de-initialize the PDMA L1 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-initialize for the L1 ISR. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitL1Isr( + const UI32_T unit) +{ + UI32_T idx = 0, vec = sizeof(_hal_lightning_pkt_intr_vec) / sizeof(HAL_LIGHTNING_PKT_INTR_VEC_T); + + for (idx = 0; idx < vec; idx++) + { + _hal_lightning_pkt_maskIntr(unit, _hal_lightning_pkt_intr_vec[idx].intr_reg); + _hal_lightning_pkt_disableIntr(unit, _hal_lightning_pkt_intr_vec[idx].intr_reg); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_deinitL2Isr + * PURPOSE: + * To initialize the PDMA L2 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure for the L2 ISR. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_deinitL2Isr( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_L2_ISR_T isr_status = 0x0; + + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH0); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH1); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH2); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH3); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH0); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH1); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH2); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH3); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RX_QID_MAP_ERR); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RX_FRAME_ERR); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_MASK_SET), + &isr_status, sizeof(UI32_T)); + + isr_status = 0x0; + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_EN), + &isr_status, sizeof(UI32_T)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_deinitPktDrv + * PURPOSE: + * To invoke the functions to de-initialize the control block for each + * PDMA subsystem. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully de-initialize the control blocks. + * CLX_E_OTHERS -- De-initialize the control blocks failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_deinitPktDrv( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (0 == (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_DRV)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, pkt drv deinit failed, not inited\n", unit); + return (CLX_E_OK); + } + + rc = _hal_lightning_pkt_deinitL2Isr(unit); + + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_deinitL1Isr(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_deinitPktRxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_deinitPktTxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_deinitPktCb(unit); + } + + ptr_cb->init_flag &= (~HAL_LIGHTNING_PKT_INIT_DRV); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, + "u=%u, pkt drv deinit done, init flag=0x%x\n", + unit, ptr_cb->init_flag); + return (rc); +} + +/* ----------------------------------------------------------------------------------- Init */ +/* FUNCTION NAME: _hal_lightning_pkt_handleTxErrStat + * PURPOSE: + * To handle the TX flow control ISR. + * INPUT: + * unit -- The unit ID + * channel -- The target channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the interrpt. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_handleTxErrStat( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + CLX_IRQ_FLAGS_T irg_flags; + + if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + /* Notify the TX process to make it release the channel semaphore. */ + osal_giveSemaphore(&ptr_tx_pdma->sync_intr_sema); + } + + /* Set the error flag. */ + + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + ptr_tx_pdma->err_flag = TRUE; + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + + osal_triggerEvent(HAL_LIGHTNING_PKT_TCH_EVENT(unit, channel)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_handleRxErrStat + * PURPOSE: + * To handle the error which occurs in RX channels. + * INPUT: + * unit -- The unit ID + * channel -- The channel where the error occurs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the error situation. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_handleRxErrStat( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Set the error flag. */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + ptr_rx_pdma->err_flag = TRUE; + osal_giveSemaphore(&ptr_rx_pdma->sema); + + osal_triggerEvent(HAL_LIGHTNING_PKT_RCH_EVENT(unit, channel)); + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_handleTxL2Isr + * PURPOSE: + * To handle the TX L2 interrupt according to the ISR status. + * INPUT: + * unit -- The unit ID + * channel -- The channel where the interrupt occurs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the L2 interrupt. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_handleTxL2Isr( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_T isr_status = 0x0; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + + osal_mdc_readPciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_TCH_INT_STAT), channel), + &isr_status, sizeof(isr_status)); + + _hal_lightning_pkt_maskAllTxL2IsrReg(unit, channel); + + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd hwo err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_hwo_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd chksum err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_chksm_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd num overflow err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_no_ovfl_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd dma read err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_dma_read_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma buf size err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR); + ptr_tx_cb->cnt.channel[channel].buf_size_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "u=%u, txch=%u, pdma pkt runt\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR); + ptr_tx_cb->cnt.channel[channel].runt_err++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "u=%u, txch=%u, pdma pkt over size\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR); + ptr_tx_cb->cnt.channel[channel].ovsz_err++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma len mismatch err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR); + ptr_tx_cb->cnt.channel[channel].len_mismatch_err++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma pkt buf dma read err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR); + ptr_tx_cb->cnt.channel[channel].pktpl_dma_read_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_COS_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma tx cos err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_COS_ERROR); + ptr_tx_cb->cnt.channel[channel].cos_err++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma gpd num > 255 err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR); + ptr_tx_cb->cnt.channel[channel].gpd_gt255_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PFC)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "u=%u, txch=%u, pdma flow ctrl\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PFC); + ptr_tx_cb->cnt.channel[channel].pfc++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma credit underflow err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR); + ptr_tx_cb->cnt.channel[channel].credit_udfl_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_TX), + "u=%u, txch=%u, pdma dma write err\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR); + ptr_tx_cb->cnt.channel[channel].dma_write_err++; + _hal_lightning_pkt_handleTxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "u=%u, txch=%u, pdma stop done\n", unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + ptr_tx_cb->cnt.channel[channel].sw_issue_stop++; + } + if (0 != isr_status) + { + _hal_lightning_pkt_unmaskAllTxL2IsrReg(unit, channel); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_handleRxL2Isr + * PURPOSE: + * To handle the RX L2 interrupt according to the ISR status. + * INPUT: + * unit -- The unit ID + * channel -- The channel where the interrupt occurs + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully handle the L2 interrupt. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_handleRxL2Isr( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_T isr_status = 0x0; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + + osal_mdc_readPciReg(unit, + HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_RCH_INT_STAT), channel), + &isr_status, sizeof(isr_status)); + + _hal_lightning_pkt_maskAllRxL2IsrReg(unit, channel); + + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma avbl gpd low\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW); + ptr_rx_cb->cnt.channel[channel].avbl_gpd_low++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma avbl gpd empty\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY); + ptr_rx_cb->cnt.channel[channel].avbl_gpd_empty++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma avbl gpd err\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR); + ptr_rx_cb->cnt.channel[channel].avbl_gpd_err++; + _hal_lightning_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma gpd chksum err\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR); + ptr_rx_cb->cnt.channel[channel].gpd_chksm_err++; + _hal_lightning_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma dma read err\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR); + ptr_rx_cb->cnt.channel[channel].dma_read_err++; + _hal_lightning_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma dma write err\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR); + ptr_rx_cb->cnt.channel[channel].dma_write_err++; + _hal_lightning_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma stop done\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT); + ptr_rx_cb->cnt.channel[channel].sw_issue_stop++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma gpd num > 255 err\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR); + ptr_rx_cb->cnt.channel[channel].gpd_gt255_err++; + _hal_lightning_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma tod ununit err\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT); + ptr_rx_cb->cnt.channel[channel].tod_uninit++; + _hal_lightning_pkt_handleRxErrStat(unit, channel); + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP)) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_RX), + "u=%u, rxch=%u, pdma pkt err drop\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP); + ptr_rx_cb->cnt.channel[channel].pkt_err_drop++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma pkt under size\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP); + ptr_rx_cb->cnt.channel[channel].udsz_drop++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma pkt over size\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP); + ptr_rx_cb->cnt.channel[channel].ovsz_drop++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma cmdq overflow\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP); + ptr_rx_cb->cnt.channel[channel].cmdq_ovf_drop++; + } + if (0 != (isr_status & HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, pdma fifo overflow\n", unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP); + ptr_rx_cb->cnt.channel[channel].fifo_ovf_drop++; + } + if (0 != isr_status) + { + _hal_lightning_pkt_unmaskAllRxL2IsrReg(unit, channel); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_handleErrorTask + * PURPOSE: + * To invoke the corresponding handler for the L2 interrupts. + * INPUT: + * ptr_argv -- The unit ID + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_lightning_pkt_handleErrorTask( + void *ptr_argv) +{ + UI32_T unit = (UI32_T)((CLX_HUGE_T)ptr_argv); + HAL_LIGHTNING_PKT_L2_ISR_T isr_status = 0x0; + + osal_initRunThread(); + do + { + /* receive Error-ISR */ + osal_waitEvent(HAL_LIGHTNING_PKT_ERR_EVENT(unit)); + if (CLX_E_OK != osal_isRunThread()) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, + "u=%u, err task destroyed\n", unit); + break; /* deinit-thread */ + } + + osal_mdc_readPciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_STAT), + &isr_status, sizeof(UI32_T)); + + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_RCH0 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, rxch=0, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleRxL2Isr(unit, HAL_LIGHTNING_PKT_RX_CHANNEL_0); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_RCH1 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, rxch=1, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleRxL2Isr(unit, HAL_LIGHTNING_PKT_RX_CHANNEL_1); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_RCH2 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, rxch=2, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleRxL2Isr(unit, HAL_LIGHTNING_PKT_RX_CHANNEL_2); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_RCH3 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, rxch=3, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleRxL2Isr(unit, HAL_LIGHTNING_PKT_RX_CHANNEL_3); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_TCH0 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, txch=0, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleTxL2Isr(unit, HAL_LIGHTNING_PKT_TX_CHANNEL_0); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_TCH1 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, txch=1, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleTxL2Isr(unit, HAL_LIGHTNING_PKT_TX_CHANNEL_1); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_TCH2 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, txch=2, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleTxL2Isr(unit, HAL_LIGHTNING_PKT_TX_CHANNEL_2); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_TCH3 & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, txch=3, rcv err isr, status=0x%x\n", + unit, isr_status); + _hal_lightning_pkt_handleTxL2Isr(unit, HAL_LIGHTNING_PKT_TX_CHANNEL_3); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_RX_QID_MAP_ERR & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, rcv rx qid map err isr, status=0x%x\n", + unit, isr_status); + } + if (0 != (HAL_LIGHTNING_PKT_L2_ISR_RX_FRAME_ERR & isr_status)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, rcv rx frame err isr, status=0x%x\n", + unit, isr_status); + } + if (0 != isr_status) + { + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_CLR), + &isr_status, sizeof(UI32_T)); + + _hal_lightning_pkt_unmaskIntr(unit, HAL_LIGHTNING_PKT_ERR_REG(unit)); + } + + } while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +/* FUNCTION NAME: _hal_lightning_pkt_handleTxDoneTask + * PURPOSE: + * To handle the TX done interrupt for the specified TX channel. + * INPUT: + * ptr_argv -- The unit ID and channel ID + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_lightning_pkt_handleTxDoneTask( + void *ptr_argv) +{ + /* cookie or index */ + UI32_T unit = ((HAL_LIGHTNING_PKT_ISR_COOKIE_T *)ptr_argv)->unit; + HAL_LIGHTNING_PKT_TX_CHANNEL_T channel = (HAL_LIGHTNING_PKT_TX_CHANNEL_T) + ((HAL_LIGHTNING_PKT_ISR_COOKIE_T *)ptr_argv)->channel; + /* control block */ + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_TX_GPD_T *ptr_tx_gpd = NULL; + UI32_T first_gpd_idx = 0; /* To record the first GPD */ + UI32_T loop_cnt = 0; + CLX_IRQ_FLAGS_T irg_flags; + unsigned long timeout = 0; + UI32_T bulk_pkt_cnt = 0, idx; + + osal_initRunThread(); + do + { + /* receive Tx-Done-ISR */ + osal_waitEvent(HAL_LIGHTNING_PKT_TCH_EVENT(unit, channel)); + if (CLX_E_OK != osal_isRunThread()) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "u=%u, txch=%u, tx done task destroyed\n", unit, channel); + break; /* deinit-thread */ + } + + /* protect Tx PDMA + * for sync-intr, the sema is locked by sendGpd + */ + if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR != ptr_tx_cb->wait_mode) + { + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + } + + loop_cnt = ptr_tx_pdma->used_gpd_num; + while (loop_cnt > 0) + { + ptr_tx_gpd = HAL_LIGHTNING_PKT_GET_TX_GPD_PTR(unit, channel, ptr_tx_pdma->free_idx); + osal_dma_invalidateCache((void *)ptr_tx_gpd, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + /* If hwo=HW, it might be: + * 1. err_flag=TRUE -> HW breakdown -> enque and recover -> break + * 2. err_flag=FALSE -> HW busy -> break + */ + if (HAL_LIGHTNING_PKT_HWO_HW_OWN == ptr_tx_gpd->hwo) + { + if (TRUE == ptr_tx_pdma->err_flag) + { + /* flush the incomplete Tx packet */ + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + for (idx = 0; idx < ptr_tx_pdma->gpd_num; idx++) + { + if (NULL != ptr_tx_pdma->pptr_sw_gpd_ring[idx]) + { + ptr_tx_pdma->pptr_sw_gpd_bulk[bulk_pkt_cnt] + = ptr_tx_pdma->pptr_sw_gpd_ring[idx]; + ptr_tx_pdma->pptr_sw_gpd_ring[idx] = NULL; + bulk_pkt_cnt++; + } + } + } + + /* do error recover */ + first_gpd_idx = 0; + if (CLX_E_OK == _hal_lightning_pkt_recoverTxPdma(unit, channel)) + { + ptr_tx_pdma->err_flag = FALSE; + ptr_tx_cb->cnt.channel[channel].err_recover++; + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_TX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, txch=%u, err recover failed\n", + unit, channel); + } + } + else + { + } + break; + } + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* If hwo=SW and ch=0, record the head of sw gpd in bulk buf */ + if (HAL_LIGHTNING_PKT_CH_LAST_GPD == ptr_tx_gpd->ch) + { + ptr_tx_pdma->pptr_sw_gpd_bulk[bulk_pkt_cnt] + = ptr_tx_pdma->pptr_sw_gpd_ring[first_gpd_idx]; + + bulk_pkt_cnt++; + ptr_tx_pdma->pptr_sw_gpd_ring[first_gpd_idx] = NULL; + + /* next SW-GPD must be the head of another PKT->SW-GPD */ + first_gpd_idx = ptr_tx_pdma->free_idx + 1; + first_gpd_idx %= ptr_tx_pdma->gpd_num; + } + } + + if (HAL_LIGHTNING_PKT_ECC_ERROR_OCCUR == ptr_tx_gpd->ecce) + { + ptr_tx_cb->cnt.channel[channel].ecc_err++; + } + + /* update Tx PDMA */ + ptr_tx_pdma->free_idx++; + ptr_tx_pdma->free_idx %= ptr_tx_pdma->gpd_num; + ptr_tx_pdma->used_gpd_num--; + ptr_tx_pdma->free_gpd_num++; + loop_cnt--; + } + + /* let the netdev resume Tx */ + _hal_lightning_pkt_resumeAllIntf(unit); + + /* update ISR and counter */ + ptr_tx_cb->cnt.channel[channel].tx_done++; + + _hal_lightning_pkt_unmaskIntr(unit, HAL_LIGHTNING_PKT_TCH_REG(unit, channel)); + + if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR != ptr_tx_cb->wait_mode) + { + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + } + else + { + osal_giveSemaphore(&ptr_tx_pdma->sync_intr_sema); + } + + /* enque packet after releasing the spinlock */ + _hal_lightning_pkt_txEnQueueBulk(unit, channel, bulk_pkt_cnt); + bulk_pkt_cnt = 0; + + /* prevent this task from executing too long */ + if (!(time_before(jiffies, timeout))) + { + schedule(); + timeout = jiffies + 1; /* continuously free tx descriptor for 1 tick */ + } + + } while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +/* FUNCTION NAME: _hal_lightning_pkt_handleRxDoneTask + * PURPOSE: + * To handle the RX done interrupt for the specified RX channel. + * INPUT: + * ptr_argv -- The unit ID and channel ID + * OUTPUT: + * None + * RETURN: + * None + * NOTES: + * None + */ +static void +_hal_lightning_pkt_handleRxDoneTask( + void *ptr_argv) +{ + /* cookie or index */ + UI32_T unit = ((HAL_LIGHTNING_PKT_ISR_COOKIE_T *)ptr_argv)->unit; + HAL_LIGHTNING_PKT_RX_CHANNEL_T channel = (HAL_LIGHTNING_PKT_RX_CHANNEL_T) + ((HAL_LIGHTNING_PKT_ISR_COOKIE_T *)ptr_argv)->channel; + + /* control block */ + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + volatile HAL_LIGHTNING_PKT_RX_GPD_T *ptr_rx_gpd = NULL; + + BOOL_T first = TRUE; + BOOL_T last = FALSE; + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_gpd = NULL; + HAL_LIGHTNING_PKT_RX_SW_GPD_T *ptr_sw_first_gpd = NULL; + UI32_T loop_cnt = 0; + unsigned long timeout = 0; + + osal_initRunThread(); + do + { + /* receive Rx-Done-ISR */ + osal_waitEvent(HAL_LIGHTNING_PKT_RCH_EVENT(unit, channel)); + if (CLX_E_OK != osal_isRunThread()) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_RX, + "u=%u, rxch=%u, rx done task destroyed\n", unit, channel); + break; /* deinit-thread */ + } + + /* check if Rx-system is inited */ + if (0 == ptr_rx_cb->buf_len) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rxch=%u, rx gpd buf len=0\n", + unit, channel); + continue; + } + + /* protect Rx PDMA */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + loop_cnt = ptr_rx_pdma->gpd_num; + while (loop_cnt > 0) + { + ptr_rx_gpd = HAL_LIGHTNING_PKT_GET_RX_GPD_PTR(unit, channel, ptr_rx_pdma->cur_idx); + osal_dma_invalidateCache((void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + /* If hwo=HW, it might be: + * 1. err_flag=TRUE -> HW breakdown -> enque and recover -> break + * 2. err_flag=FALSE -> HW busy -> break + */ + if (HAL_LIGHTNING_PKT_HWO_HW_OWN == ptr_rx_gpd->hwo) + { + if (TRUE == ptr_rx_pdma->err_flag) + { + /* free the last incomplete Rx packet */ + if ((NULL != ptr_sw_first_gpd) && + (NULL != ptr_sw_gpd)) + { + ptr_sw_gpd->ptr_next = NULL; + ptr_sw_first_gpd->rx_complete = FALSE; + _hal_lightning_pkt_rxEnQueue(unit, channel, ptr_sw_first_gpd); + ptr_sw_first_gpd = NULL; + } + + /* do error recover */ + first = TRUE; + last = FALSE; + if (CLX_E_OK == _hal_lightning_pkt_recoverRxPdma(unit, channel)) + { + ptr_rx_pdma->err_flag = FALSE; + ptr_rx_cb->cnt.channel[channel].err_recover++; + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rxch=%u, err recover failed\n", + unit, channel); + } + } + else + { + } + break; + } + + /* Move HW-GPD to SW-GPD and append to a link-list */ + if (TRUE == first) + { + ptr_sw_first_gpd = (HAL_LIGHTNING_PKT_RX_SW_GPD_T *)osal_alloc(sizeof(HAL_LIGHTNING_PKT_RX_SW_GPD_T)); + ptr_sw_gpd = ptr_sw_first_gpd; + if (NULL != ptr_sw_gpd) + { + memcpy(&ptr_sw_gpd->rx_gpd, (void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + first = FALSE; + } + else + { + ptr_rx_cb->cnt.no_memory++; + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rxch=%u, alloc 1st sw gpd failed, size=%zu\n", + unit, channel, sizeof(HAL_LIGHTNING_PKT_RX_SW_GPD_T)); + break; + } + } + else + { + ptr_sw_gpd->ptr_next = (HAL_LIGHTNING_PKT_RX_SW_GPD_T *)osal_alloc(sizeof(HAL_LIGHTNING_PKT_RX_SW_GPD_T)); + ptr_sw_gpd = ptr_sw_gpd->ptr_next; + if (NULL != ptr_sw_gpd) + { + memcpy(&ptr_sw_gpd->rx_gpd, (void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + } + else + { + ptr_rx_cb->cnt.no_memory++; + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_RX | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, rxch=%u, alloc mid sw gpd failed, size=%zu\n", + unit, channel, sizeof(HAL_LIGHTNING_PKT_RX_SW_GPD_T)); + break; + } + } + + ptr_sw_gpd->ptr_cookie = ptr_rx_pdma->pptr_skb_ring[ptr_rx_pdma->cur_idx]; + + /* If hwo=SW and ch=0, enque SW-GPD and signal rxTask */ + if (HAL_LIGHTNING_PKT_CH_LAST_GPD == ptr_rx_gpd->ch) + { + last = TRUE; + } + + /* If hwo=SW and ch=*, re-alloc-buf and resume */ + while (CLX_E_OK != _hal_lightning_pkt_allocRxPayloadBuf(unit, channel, ptr_rx_pdma->cur_idx)) + { + ptr_rx_cb->cnt.no_memory++; + HAL_LIGHTNING_PKT_ALLOC_MEM_RETRY_SLEEP(); + } + ptr_rx_gpd->ioc = HAL_LIGHTNING_PKT_IOC_HAS_INTR; + ptr_rx_gpd->hwo = HAL_LIGHTNING_PKT_HWO_HW_OWN; + osal_dma_flushCache((void *)ptr_rx_gpd, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + /* Enque the SW-GPD to rxTask */ + if (TRUE == last) + { + ptr_sw_gpd->ptr_next = NULL; + ptr_sw_first_gpd->rx_complete = TRUE; + _hal_lightning_pkt_rxEnQueue(unit, channel, ptr_sw_first_gpd); + ptr_sw_first_gpd = NULL; + + /* To rebuild the SW GPD link list */ + first = TRUE; + last = FALSE; + } + + _hal_lightning_pkt_resumeRxChannelReg(unit, channel, 1); + + /* update Rx PDMA */ + ptr_rx_pdma->cur_idx++; + ptr_rx_pdma->cur_idx %= ptr_rx_pdma->gpd_num; + loop_cnt--; + } + + osal_giveSemaphore(&ptr_rx_pdma->sema); + + /* update ISR and counter */ + ptr_rx_cb->cnt.channel[channel].rx_done++; + + _hal_lightning_pkt_unmaskIntr(unit, HAL_LIGHTNING_PKT_RCH_REG(unit, channel)); + + /* prevent this task from executing too long */ + if (!(time_before(jiffies, timeout))) + { + schedule(); + timeout = jiffies + 1; /* continuously rx for 1 tick */ + } + + } while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +static void +_hal_lightning_pkt_net_dev_tx_callback( + const UI32_T unit, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd, + struct sk_buff *ptr_skb) +{ + CLX_ADDR_T phy_addr = 0; + + /* unmap dma */ + phy_addr = CLX_ADDR_32_TO_64(ptr_sw_gpd->tx_gpd.data_buf_addr_hi, ptr_sw_gpd->tx_gpd.data_buf_addr_lo); + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_TO_DEVICE); + + /* free skb */ + osal_skb_free(ptr_skb); + + /* free gpd */ + osal_free(ptr_sw_gpd); +} + +/* FUNCTION NAME: hal_lightning_pkt_initTask + * PURPOSE: + * To initialize the Task for packet module. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully dinitialize the control block. + * CLX_E_OTHERS -- Initialize the control block failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_initTask( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + UI32_T channel = 0; + + if (0 != (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_TASK)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, pkt task init failed, not inited\n", unit); + return (rc); + } + + /* Init handleErrorTask */ + rc = osal_createThread("ERROR", HAL_DFLT_CFG_PKT_ERROR_ISR_THREAD_STACK, + HAL_DFLT_CFG_PKT_ERROR_ISR_THREAD_PRI, _hal_lightning_pkt_handleErrorTask, + (void *)((CLX_HUGE_T)unit), &ptr_cb->err_task_id); + + /* Init handleTxDoneTask */ + for (channel = 0; ((channel < HAL_LIGHTNING_PKT_TX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + ptr_tx_cb->isr_task_cookie[channel].unit = unit; + ptr_tx_cb->isr_task_cookie[channel].channel = channel; + + rc = osal_createThread("TX_ISR", HAL_DFLT_CFG_PKT_TX_ISR_THREAD_STACK, + HAL_DFLT_CFG_PKT_TX_ISR_THREAD_PRI, _hal_lightning_pkt_handleTxDoneTask, + (void *)&ptr_tx_cb->isr_task_cookie[channel], + &ptr_tx_cb->isr_task_id[channel]); + } + + /* Init handleRxDoneTask */ + for (channel = 0; ((channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + ptr_rx_cb->isr_task_cookie[channel].unit = unit; + ptr_rx_cb->isr_task_cookie[channel].channel = channel; + + rc = osal_createThread("RX_ISR", HAL_DFLT_CFG_PKT_RX_ISR_THREAD_STACK, + HAL_DFLT_CFG_PKT_RX_ISR_THREAD_PRI, _hal_lightning_pkt_handleRxDoneTask, + (void *)&ptr_rx_cb->isr_task_cookie[channel], + &ptr_rx_cb->isr_task_id[channel]); + } + + /* Init txTask */ + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + ptr_tx_cb->running = TRUE; + } + + ptr_cb->init_flag |= HAL_LIGHTNING_PKT_INIT_TASK; + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, + "u=%u, pkt task init done, init flag=0x%x\n", unit, ptr_cb->init_flag); + + /* For some specail case in warmboot, the netifs are not destroyed during sdk deinit + * but stopped, here we need to resume them with the original carrier status + */ + _hal_lightning_pkt_resumeAllIntf(unit); + + ptr_tx_cb->net_tx_allowed = TRUE; + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initTxPdma + * PURPOSE: + * To initialize the TX PDMA. + * INPUT: + * unit -- The unit ID + * channel -- The target Tx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the TX PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initTxPdma( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_PDMA_T *ptr_tx_pdma = HAL_LIGHTNING_PKT_GET_TX_PDMA_PTR(unit, channel); + CLX_IRQ_FLAGS_T irg_flags; + + /* Isr lock to protect Tx PDMA */ + osal_createIsrLock("TCH_LCK", &ptr_tx_pdma->ring_lock); + + if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR == ptr_tx_cb->wait_mode) + { + /* Sync semaphore to signal sendTxPacket */ + osal_createSemaphore("TCH_SYN", CLX_SEMAPHORE_SYNC, &ptr_tx_pdma->sync_intr_sema); + } + + /* Reset Tx PDMA */ + osal_takeIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + + ptr_tx_pdma->used_idx = 0; + ptr_tx_pdma->free_idx = 0; + ptr_tx_pdma->used_gpd_num = 0; + ptr_tx_pdma->free_gpd_num = HAL_DFLT_CFG_PKT_TX_GPD_NUM; + ptr_tx_pdma->gpd_num = HAL_DFLT_CFG_PKT_TX_GPD_NUM; + + /* Prepare the HW-GPD ring */ + ptr_tx_pdma->ptr_gpd_start_addr = (HAL_LIGHTNING_PKT_TX_GPD_T *)osal_dma_alloc( + (ptr_tx_pdma->gpd_num + 1) * sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + if (NULL != ptr_tx_pdma->ptr_gpd_start_addr) + { + osal_memset(ptr_tx_pdma->ptr_gpd_start_addr, 0x0, + (ptr_tx_pdma->gpd_num + 1) * sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + ptr_tx_pdma->ptr_gpd_align_start_addr = (HAL_LIGHTNING_PKT_TX_GPD_T *)HAL_LIGHTNING_PKT_PDMA_ALIGN_ADDR( + (CLX_HUGE_T)ptr_tx_pdma->ptr_gpd_start_addr, sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + rc = _hal_lightning_pkt_initTxPdmaRing(unit, channel); + if (CLX_E_OK == rc) + { + _hal_lightning_pkt_startTxChannelReg(unit, channel, 0); + } + } + else + { + ptr_tx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + if (CLX_E_OK == rc) + { + /* Prepare the SW-GPD ring */ + ptr_tx_pdma->pptr_sw_gpd_ring = (HAL_LIGHTNING_PKT_TX_SW_GPD_T **)osal_alloc( + ptr_tx_pdma->gpd_num * sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T *)); + + if (NULL != ptr_tx_pdma->pptr_sw_gpd_ring) + { + osal_memset(ptr_tx_pdma->pptr_sw_gpd_ring, 0x0, + ptr_tx_pdma->gpd_num * sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T *)); + } + else + { + ptr_tx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + + /* a temp buffer to store the 1st sw gpd for each packet to be enque + * we cannot enque packet before release a spinlock + */ + ptr_tx_pdma->pptr_sw_gpd_bulk = (HAL_LIGHTNING_PKT_TX_SW_GPD_T **)osal_alloc( + ptr_tx_pdma->gpd_num * sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T *)); + + if (NULL != ptr_tx_pdma->pptr_sw_gpd_bulk) + { + osal_memset(ptr_tx_pdma->pptr_sw_gpd_bulk, 0x0, + ptr_tx_pdma->gpd_num * sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T *)); + } + else + { + ptr_tx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + } + } + + osal_giveIsrLock(&ptr_tx_pdma->ring_lock, &irg_flags); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initRxPdma + * PURPOSE: + * To initialize the RX PDMA. + * INPUT: + * unit -- The unit ID + * channel -- The target Rx channel + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the RX PDMA. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initRxPdma( + const UI32_T unit, + const HAL_LIGHTNING_PKT_RX_CHANNEL_T channel) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_PDMA_T *ptr_rx_pdma = HAL_LIGHTNING_PKT_GET_RX_PDMA_PTR(unit, channel); + + /* Binary semaphore to protect Rx PDMA */ + osal_createSemaphore("RCH_LCK", CLX_SEMAPHORE_BINARY, &ptr_rx_pdma->sema); + + /* Reset Rx PDMA */ + osal_takeSemaphore(&ptr_rx_pdma->sema, CLX_SEMAPHORE_WAIT_FOREVER); + ptr_rx_pdma->cur_idx = 0; + ptr_rx_pdma->gpd_num = HAL_DFLT_CFG_PKT_RX_GPD_NUM; + + /* Prepare the HW-GPD ring */ + ptr_rx_pdma->ptr_gpd_start_addr = (HAL_LIGHTNING_PKT_RX_GPD_T *)osal_dma_alloc( + (ptr_rx_pdma->gpd_num + 1) * sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + if (NULL != ptr_rx_pdma->ptr_gpd_start_addr) + { + osal_memset(ptr_rx_pdma->ptr_gpd_start_addr, 0, + (ptr_rx_pdma->gpd_num + 1) * sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + ptr_rx_pdma->ptr_gpd_align_start_addr = (HAL_LIGHTNING_PKT_RX_GPD_T *)HAL_LIGHTNING_PKT_PDMA_ALIGN_ADDR( + (CLX_HUGE_T)ptr_rx_pdma->ptr_gpd_start_addr, sizeof(HAL_LIGHTNING_PKT_RX_GPD_T)); + + /* will initRxPdmaRingBuf and start RCH after setRxConfig */ + rc = _hal_lightning_pkt_initRxPdmaRing(unit, channel); + } + else + { + ptr_rx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + + if (CLX_E_OK == rc) + { + /* Prepare the SKB ring */ + ptr_rx_pdma->pptr_skb_ring = (struct sk_buff **)osal_alloc( + ptr_rx_pdma->gpd_num * sizeof(struct sk_buff *)); + + if (NULL != ptr_rx_pdma->pptr_skb_ring) + { + osal_memset(ptr_rx_pdma->pptr_skb_ring, 0x0, + ptr_rx_pdma->gpd_num * sizeof(struct sk_buff *)); + } + else + { + ptr_rx_cb->cnt.no_memory++; + rc = CLX_E_NO_MEMORY; + } + } + + osal_giveSemaphore(&ptr_rx_pdma->sema); + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initPktCb + * PURPOSE: + * To initialize the control block of Drv. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control block. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initPktCb( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + UI32_T idx = 0, vec = sizeof(_hal_lightning_pkt_intr_vec) / sizeof(HAL_LIGHTNING_PKT_INTR_VEC_T); + + osal_memset(ptr_cb, 0x0, sizeof(HAL_LIGHTNING_PKT_DRV_CB_T)); + + /* Register PKT interrupt functions */ + osal_createIsrLock("ISR_LOCK", &ptr_cb->intr_lock); + osal_mdc_registerIsr(unit, _hal_lightning_pkt_dispatcher, (void *)((CLX_HUGE_T)unit)); + + for (idx = 0; idx < vec; idx++) + { + osal_createEvent("ISR_EVENT", &_hal_lightning_pkt_intr_vec[idx].intr_event); + ptr_cb->intr_bitmap |= (_hal_lightning_pkt_intr_vec[idx].intr_reg); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initPktTxCb + * PURPOSE: + * To initialize the control block of Rx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control block. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initPktTxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + HAL_LIGHTNING_PKT_TX_CHANNEL_T channel = 0; + + osal_memset(ptr_tx_cb, 0x0, sizeof(HAL_LIGHTNING_PKT_TX_CB_T)); + + ptr_tx_cb->wait_mode = HAL_LIGHTNING_PKT_TX_WAIT_MODE; + + if (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC == ptr_tx_cb->wait_mode) + { + /* Sync semaphore to signal txTask */ + osal_createEvent("TX_SYNC", &ptr_tx_cb->sync_sema); + + /* Initialize Tx GPD-queue (of first SW-GPD) from handleTxDoneTask to txTask */ + ptr_tx_cb->sw_queue.len = HAL_DFLT_CFG_PKT_TX_QUEUE_LEN; + ptr_tx_cb->sw_queue.weight = 0; + + osal_createSemaphore("TX_QUE", CLX_SEMAPHORE_BINARY, &ptr_tx_cb->sw_queue.sema); + osal_que_create(&ptr_tx_cb->sw_queue.que_id, ptr_tx_cb->sw_queue.len); + } + else if (HAL_LIGHTNING_PKT_TX_WAIT_SYNC_POLL == ptr_tx_cb->wait_mode) + { + /* Disable TX done ISR. */ + for (channel = 0; channel < HAL_LIGHTNING_PKT_TX_CHANNEL_LAST; channel++) + { + _hal_lightning_pkt_disableIntr(unit, HAL_LIGHTNING_PKT_TCH_REG(unit, channel)); + } + } + + /* Init Tx PDMA */ + for (channel = 0; ((channel < HAL_LIGHTNING_PKT_TX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + rc = _hal_lightning_pkt_initTxPdma(unit, channel); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initPktRxCb + * PURPOSE: + * To initialize the control block of Rx PDMA. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control block. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initPktRxCb( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + HAL_LIGHTNING_PKT_RX_CB_T *ptr_rx_cb = HAL_LIGHTNING_PKT_GET_RX_CB_PTR(unit); + HAL_LIGHTNING_PKT_RX_CHANNEL_T channel = 0; + UI32_T queue = 0; + + osal_memset(ptr_rx_cb, 0x0, sizeof(HAL_LIGHTNING_PKT_RX_CB_T)); + + ptr_rx_cb->sched_mode = HAL_DFLT_CFG_PKT_RX_SCHED_MODE; + + /* Sync semaphore to signal rxTask */ + osal_createEvent("RX_SYNC", &ptr_rx_cb->sync_sema); + + /* Initialize Rx GPD-queue (of first SW-GPD) from handleRxDoneTask to rxTask */ + for (queue = 0; ((queue < HAL_LIGHTNING_PKT_RX_QUEUE_NUM) && (CLX_E_OK == rc)); queue++) + { + ptr_rx_cb->sw_queue[queue].len = HAL_DFLT_CFG_PKT_RX_QUEUE_LEN; + ptr_rx_cb->sw_queue[queue].weight = HAL_DFLT_CFG_PKT_RX_QUEUE_WEIGHT; + + osal_createSemaphore("RX_QUE", CLX_SEMAPHORE_BINARY, &ptr_rx_cb->sw_queue[queue].sema); + osal_que_create(&ptr_rx_cb->sw_queue[queue].que_id, ptr_rx_cb->sw_queue[queue].len); + } + + /* Init Rx PDMA */ + for (channel = 0; ((channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST) && (CLX_E_OK == rc)); channel++) + { + rc = _hal_lightning_pkt_initRxPdma(unit, channel); + } + + return (rc); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initL1Isr + * PURPOSE: + * To initialize the PDMA L1 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the L1 ISR. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initL1Isr( + const UI32_T unit) +{ + UI32_T idx = 0, vec = sizeof(_hal_lightning_pkt_intr_vec) / sizeof(HAL_LIGHTNING_PKT_INTR_VEC_T); + + for (idx = 0; idx < vec; idx++) + { + _hal_lightning_pkt_enableIntr(unit, _hal_lightning_pkt_intr_vec[idx].intr_reg); + _hal_lightning_pkt_unmaskIntr(unit, _hal_lightning_pkt_intr_vec[idx].intr_reg); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: _hal_lightning_pkt_initL2Isr + * PURPOSE: + * To initialize the PDMA L2 ISR configuration. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully configure for the L2 ISR. + * CLX_E_OTHERS -- Configure failed. + * NOTES: + * None + */ +static CLX_ERROR_NO_T +_hal_lightning_pkt_initL2Isr( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_L2_ISR_T isr_status = 0x0; + + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH0); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH1); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH2); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RCH3); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH0); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH1); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH2); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_TCH3); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RX_QID_MAP_ERR); + HAL_LIGHTNING_PKT_SET_BITMAP(isr_status, HAL_LIGHTNING_PKT_L2_ISR_RX_FRAME_ERR); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_EN), + &isr_status, sizeof(UI32_T)); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_MASK_SET), + &isr_status, sizeof(UI32_T)); + + return (CLX_E_OK); + +} + +CLX_ERROR_NO_T +_hal_lightning_pkt_resetIosCreditCfg( + const UI32_T unit) +{ +#define HAL_LIGHTNING_PKT_PDMA_CREDIT_CFG_RESET_OFFSET (16) + + UI32_T credit_cfg = 0x0; + UI32_T idx; + + for (idx=0; idxptr_profile = ptr_new_profile; + + /* Create the 1st node in the interface profile list */ + if (NULL == *pptr_profile_list) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "prof list empty\n"); + *pptr_profile_list = ptr_new_prof_node; + ptr_new_prof_node->ptr_next_node = NULL; + } + else + { + ptr_prev_node = *pptr_profile_list; + ptr_curr_node = *pptr_profile_list; + + while (ptr_curr_node != NULL) + { + if (ptr_curr_node->ptr_profile->priority <= ptr_new_profile->priority) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "find prof id=%d (%s) higher priority=%d, search next\n", + ptr_curr_node->ptr_profile->id, + ptr_curr_node->ptr_profile->name, + ptr_curr_node->ptr_profile->priority); + /* Search the next node */ + ptr_prev_node = ptr_curr_node; + ptr_curr_node = ptr_curr_node->ptr_next_node; + } + else + { + /* Insert intermediate node */ + ptr_new_prof_node->ptr_next_node = ptr_curr_node; + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "insert prof id=%d (%s) before prof id=%d (%s) (priority=%d >= %d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_curr_node->ptr_profile->id, + ptr_curr_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority, + ptr_curr_node->ptr_profile->priority); + + if (ptr_prev_node == ptr_curr_node) + { + /* There is no previous node: change the root */ + *pptr_profile_list = ptr_new_prof_node; + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "insert prof id=%d (%s) to head (priority=%d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority); + } + else + { + ptr_prev_node->ptr_next_node = ptr_new_prof_node; + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "insert prof id=%d (%s) after prof id=%d (%s) (priority=%d <= %d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_prev_node->ptr_profile->id, + ptr_prev_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority, + ptr_prev_node->ptr_profile->priority); + } + + return (CLX_E_OK); + } + } + + /* Insert node to the tail of list */ + ptr_prev_node->ptr_next_node = ptr_new_prof_node; + ptr_new_prof_node->ptr_next_node = NULL; + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "insert prof id=%d (%s) to tail, after prof id=%d (%s) (priority=%d <= %d)\n", + ptr_new_prof_node->ptr_profile->id, + ptr_new_prof_node->ptr_profile->name, + ptr_prev_node->ptr_profile->id, + ptr_prev_node->ptr_profile->name, + ptr_new_prof_node->ptr_profile->priority, + ptr_prev_node->ptr_profile->priority); + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_addProfToAllIntf( + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_new_profile) +{ + UI32_T port; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + /* Shall we check if the interface is ever created on the port?? */ + /* if (NULL != ptr_port_db->ptr_net_dev) */ + if (1) + { + _hal_lightning_pkt_addProfToList(ptr_new_profile, &ptr_port_db->ptr_profile_list); + } + } + + return (CLX_E_OK); +} + +static HAL_LIGHTNING_PKT_NETIF_PROFILE_T * +_hal_lightning_pkt_delProfFromListById( + const UI32_T id, + HAL_LIGHTNING_PKT_PROFILE_NODE_T **pptr_profile_list) +{ + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_temp_node; + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_curr_node, *ptr_prev_node; + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile = NULL;; + + if (NULL != *pptr_profile_list) + { + /* Check the 1st node */ + if (id == (*pptr_profile_list)->ptr_profile->id) + { + ptr_profile = (*pptr_profile_list)->ptr_profile; + ptr_temp_node = (*pptr_profile_list); + (*pptr_profile_list) = ptr_temp_node->ptr_next_node; + + if (NULL != ptr_temp_node->ptr_next_node) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "choose prof id=%d (%s) as new head\n", + ptr_temp_node->ptr_next_node->ptr_profile->id, + ptr_temp_node->ptr_next_node->ptr_profile->name); + } + else + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "prof list is empty\n"); + } + + + osal_free(ptr_temp_node); + } + else + { + ptr_prev_node = *pptr_profile_list; + ptr_curr_node = ptr_prev_node->ptr_next_node; + + while (NULL != ptr_curr_node) + { + if (id != ptr_curr_node->ptr_profile->id) + { + ptr_prev_node = ptr_curr_node; + ptr_curr_node = ptr_curr_node->ptr_next_node; + } + else + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "find prof id=%d, free done\n", id); + + ptr_profile = ptr_curr_node->ptr_profile; + ptr_prev_node->ptr_next_node = ptr_curr_node->ptr_next_node; + osal_free(ptr_curr_node); + break; + } + } + } + } + + if (NULL == ptr_profile) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_PROFILE | HAL_LIGHTNING_PKT_DBG_ERR), + "find prof failed, id=%d\n", id); + } + + return (ptr_profile); +} + + +static CLX_ERROR_NO_T +_hal_lightning_pkt_delProfFromAllIntfById( + const UI32_T id) +{ + UI32_T port; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + /* Shall we check if the interface is ever created on the port?? */ + /* if (NULL != ptr_port_db->ptr_net_dev) */ + if (1) + { + _hal_lightning_pkt_delProfFromListById(id, &ptr_port_db->ptr_profile_list); + } + } + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_allocProfEntry( + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile) +{ + UI32_T idx; + + for (idx=0; idxid = idx; + return (CLX_E_OK); + } + } + return (CLX_E_TABLE_FULL); +} + +static HAL_LIGHTNING_PKT_NETIF_PROFILE_T * +_hal_lightning_pkt_freeProfEntry( + const UI32_T id) +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile = NULL; + + if (id < HAL_LIGHTNING_PKT_NET_PROFILE_NUM_MAX) + { + ptr_profile = _ptr_hal_lightning_pkt_profile_entry[id]; + _ptr_hal_lightning_pkt_profile_entry[id] = NULL; + } + + return (ptr_profile); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_destroyAllIntf( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + + /* Unregister net devices by id, although the "id" is now relavent to "port" we still perform a search */ + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, + "u=%u, find intf %s (id=%d) on phy port=%d, destroy done\n", + unit, + ptr_port_db->meta.name, + ptr_port_db->meta.port, + ptr_port_db->meta.port); + + netif_tx_disable(ptr_port_db->ptr_net_dev); + unregister_netdev(ptr_port_db->ptr_net_dev); + free_netdev(ptr_port_db->ptr_net_dev); + + /* Don't need to remove profiles on this port. + * In fact, the profile is binding to "port" not "intf". + */ + /* _hal_lightning_pkt_destroyProfList(ptr_port_db->ptr_profile_list); */ + + osal_memset(ptr_port_db, 0x0, sizeof(HAL_LIGHTNING_PKT_NETIF_PORT_DB_T)); + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_delProfListOnAllIntf( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_curr_node, *ptr_next_node; + + /* Unregister net devices by id, although the "id" is now relavent to "port" we still perform a search */ + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_profile_list) /* valid intf */ + { + ptr_curr_node = ptr_port_db->ptr_profile_list; + while (NULL != ptr_curr_node) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "u=%u, del prof id=%d on phy port=%d\n", + unit, ptr_curr_node->ptr_profile->id, port); + + ptr_next_node = ptr_curr_node->ptr_next_node; + osal_free(ptr_curr_node); + ptr_curr_node = ptr_next_node; + } + } + } + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_destroyAllProfile( + const UI32_T unit) +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile; + UI32_T prof_id; + + _hal_lightning_pkt_delProfListOnAllIntf(unit); + + for (prof_id=0; prof_idid, + ptr_profile->name, + ptr_profile->priority, + ptr_profile->flags); + osal_free(ptr_profile); + } + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: hal_lightning_pkt_initPktDrv + * PURPOSE: + * To invoke the functions to initialize the control block for each + * PDMA subsystem. + * INPUT: + * unit -- The unit ID + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successfully initialize the control blocks. + * CLX_E_OTHERS -- Initialize the control blocks failed. + * NOTES: + * None + */ +CLX_ERROR_NO_T +hal_lightning_pkt_initPktDrv( + const UI32_T unit) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T channel = 0; + UI32_T flush_intr = 0x0; + UI32_T clear_intr = 0xffffffff; + HAL_LIGHTNING_PKT_DRV_CB_T *ptr_cb = HAL_LIGHTNING_PKT_GET_DRV_CB_PTR(unit); + + /* There's a case that PDMA Tx is on-going when doing chip reset, + * where PDMA may hang and be not programmable since current Tx packet + * stucks due to IOS credit too low. + * Thus, we always reset IOS credit value before progrmming Tx PDMA. + */ + _hal_lightning_pkt_resetIosCreditCfg(unit); + + /* Since the users may kill SDK application without a de-init flow, + * we help to detect if NETIF is ever init before, and perform deinit. + * (Because the users cannot perform Task init bypassing Drv init, this + * check is required only in here) + */ + if (0 != (ptr_cb->init_flag & HAL_LIGHTNING_PKT_INIT_DRV)) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, init pkt drv failed, inited\n", unit); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, stop rx pkt\n", unit); + _hal_lightning_pkt_rxStop(unit); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, stop all intf\n", unit); + _hal_lightning_pkt_stopAllIntf(unit); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, deinit pkt task\n", unit); + + hal_lightning_pkt_deinitTask(unit); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, deinit pkt drv\n", unit); + hal_lightning_pkt_deinitPktDrv(unit); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, destroy all prof\n", unit); + _hal_lightning_pkt_destroyAllProfile(unit); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, + "u=%u, destroy all intf\n", unit); + _hal_lightning_pkt_destroyAllIntf(unit); + } + + /* [cold-boot] 1. stop DMA channel + * 2. disable/mask/clear the interrupt status. + */ + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_EN), + &flush_intr, sizeof(UI32_T)); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_MASK_SET), + &clear_intr, sizeof(UI32_T)); + + osal_mdc_writePciReg(unit, + HAL_LIGHTNING_PKT_GET_MMIO(HAL_LIGHTNING_PKT_PDMA_ERR_INT_CLR), + &clear_intr, sizeof(UI32_T)); + + for (channel = 0; channel < HAL_LIGHTNING_PKT_TX_CHANNEL_LAST; channel++) + { + _hal_lightning_pkt_stopTxChannelReg(unit, channel); + _hal_lightning_pkt_maskAllTxL2IsrReg(unit, channel); + _hal_lightning_pkt_clearTxL2IsrStatusReg(unit, channel, clear_intr); + } + + for (channel = 0; channel < HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; channel++) + { + _hal_lightning_pkt_stopRxChannelReg(unit, channel); + _hal_lightning_pkt_maskAllRxL2IsrReg(unit, channel); + _hal_lightning_pkt_clearRxL2IsrStatusReg(unit, channel, clear_intr); + } + + rc = _hal_lightning_pkt_initPktCb(unit); + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_initPktTxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_initPktRxCb(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_initL1Isr(unit); + } + if (CLX_E_OK == rc) + { + rc = _hal_lightning_pkt_initL2Isr(unit); + } + + /* Set the flag to record init state */ + ptr_cb->init_flag |= HAL_LIGHTNING_PKT_INIT_DRV; + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, + "u=%u, pkt drv init done, init flag=0x%x\n", unit, ptr_cb->init_flag); + + return (rc); +} + +/* ----------------------------------------------------------------------------------- Init: I/O */ +CLX_ERROR_NO_T +hal_lightning_pkt_getNetDev( + const UI32_T unit, + const UI32_T port, + struct net_device **pptr_net_dev) +{ + *pptr_net_dev = HAL_LIGHTNING_PKT_GET_PORT_NETDEV(port); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +_hal_lightning_pkt_isProtocolPkt(struct sk_buff *skb) +{ + struct ethhdr *ether = eth_hdr(skb); + struct iphdr *ip_header = ip_hdr(skb); + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + struct udphdr *udp_header = udp_hdr(skb); + struct tcphdr *tcp_header = tcp_hdr(skb); + unsigned int src_ip = (unsigned int)ip_header->saddr; + unsigned int dest_ip = (unsigned int)ip_header->daddr; + unsigned int src_port = 0; + unsigned int dest_port = 0; + u8 lacp_addr[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x02 }; + u8 udld_addr[6] = { 0x01, 0x00, 0x0c, 0xcc, 0xcc, 0xcc }; + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "queue_mapping=%u skbaddr=%p vlan_tagged=%d vlan_proto=0x%04x vlan_tci=0x%04x protocol=0x%04x ip_summed=%d len=%u data_len=%u", + skb->queue_mapping, skb, + skb_vlan_tag_present(skb), ntohs(skb->vlan_proto), skb_vlan_tag_get(skb), + ntohs(skb->protocol), skb->ip_summed, skb->len, + skb->data_len); + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, "Source: %x:%x:%x:%x:%x:%x\n", + ether->h_source[0], ether->h_source[1], ether->h_source[2], ether->h_source[3], ether->h_source[4], ether->h_source[5]); + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, "Destination: %x:%x:%x:%x:%x:%x\n", + ether->h_dest[0], ether->h_dest[1], ether->h_dest[2], ether->h_dest[3], ether->h_dest[4], ether->h_dest[5]); + + if (ip_header->protocol == IPPROTO_UDP) { + udp_header = (struct udphdr *)skb_transport_header(skb); + src_port = (unsigned int)ntohs(udp_header->source); + dest_port = (unsigned int)ntohs(udp_header->dest); + } else if (ip_header->protocol == IPPROTO_TCP) { + tcp_header = (struct tcphdr *)skb_transport_header(skb); + src_port = (unsigned int)ntohs(tcp_header->source); + dest_port = (unsigned int)ntohs(tcp_header->dest); + } + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, + "OUT packet info: src ip: %u, src port: %u; dest ip: %u, dest port: %u; proto: %u\n", + src_ip, src_port, dest_ip, dest_port, ip_header->protocol); + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, "IPv6 protocol: %d\n", ip6h->nexthdr); + + //UDLD + if (ether_addr_equal(ether->h_dest, udld_addr)){ + return 1; + } + + switch(ntohs(skb->protocol)){ + //IP + case ETH_P_IP: + if ((ip_header->protocol == IPPROTO_ICMP) || + (ip_header->protocol == IPPROTO_IGMP) || + (ip_header->protocol == IPPROTO_PIM) || + //OSPF + (ip_header->protocol == 89) || + (ip_header->protocol == IPPROTO_EGP)) { + return 1; + } + + if (ip_header->protocol == IPPROTO_UDP) { + src_port = (unsigned int)ntohs(udp_header->source); + dest_port = (unsigned int)ntohs(udp_header->dest); + } else if (ip_header->protocol == IPPROTO_TCP) { + src_port = (unsigned int)ntohs(tcp_header->source); + dest_port = (unsigned int)ntohs(tcp_header->dest); + } else { + return 0; + } + + if ((ip_header->protocol == IPPROTO_TCP) && ( + //BGP + (dest_port == 179) || + //SSH + (dest_port == 22))){ + return 1; + } + + if ((ip_header->protocol == IPPROTO_UDP) && ( + //Sflow + (dest_port == 6343) || + //DHCP + (dest_port == 67) || + (dest_port == 68) || + //BFD + (dest_port == 3784) || + (dest_port == 4784) || + //SNMP + (dest_port == 161) || + (dest_port == 162))){ + return 1; + } + + break; + + //IPv6 + case ETH_P_IPV6: + if (ip6h->nexthdr == IPPROTO_ICMPV6) { + return 1; + } + udp_header = (struct udphdr *)((void *)ip6h + sizeof(struct ipv6hdr)); + tcp_header = (struct tcphdr *)((void *)ip6h + sizeof(struct ipv6hdr)); + + if (ip_header->protocol == IPPROTO_UDP) { + src_port = (unsigned int)ntohs(udp_header->source); + dest_port = (unsigned int)ntohs(udp_header->dest); + } else if (ip_header->protocol == IPPROTO_TCP) { + src_port = (unsigned int)ntohs(tcp_header->source); + dest_port = (unsigned int)ntohs(tcp_header->dest); + } else { + return 0; + } + + if ((ip6h->nexthdr == IPPROTO_UDP) && + //DHCPv6 + ((dest_port == 547) || (dest_port == 546) || + //BFDv6 + (dest_port == 3784) || + (dest_port == 4784))){ + return 1; + } + + if ((ip6h->nexthdr == IPPROTO_TCP) && + //BGPv6 and ssh + ((dest_port == 179) || (dest_port == 22))){ + return 1; + } + + //OSPFv6 + if (ip6h->nexthdr == 89){ + return 1; + } + break; + case ETH_P_ARP: + case ETH_P_RARP: + case 0x88cc: //LLDP + return 1; + break; + + case ETH_P_SLOW: + if (ether_addr_equal(ether->h_dest, lacp_addr)){ + return 1; + } + break; + default: + return 0; + break; + } + + return 0; +} + + +CLX_ERROR_NO_T +hal_lightning_pkt_prepareGpd( + const UI32_T unit, + const CLX_ADDR_T phy_addr, + const struct sk_buff *ptr_skb, + const UI32_T port, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd) +{ + /* fill up tx_gpd */ + ptr_sw_gpd->tx_gpd.data_buf_addr_hi = CLX_ADDR_64_HI(phy_addr); + ptr_sw_gpd->tx_gpd.data_buf_addr_lo = CLX_ADDR_64_LOW(phy_addr); + ptr_sw_gpd->tx_gpd.data_buf_size = ptr_skb->len; + ptr_sw_gpd->tx_gpd.chksum = 0x0; + ptr_sw_gpd->tx_gpd.ipc = 0; /* Raw mode, sent to plane 0 */ + ptr_sw_gpd->tx_gpd.prg = HAL_LIGHTNING_PKT_PRG_PROCESS_GPD; + ptr_sw_gpd->tx_gpd.hwo = HAL_LIGHTNING_PKT_HWO_HW_OWN; + ptr_sw_gpd->tx_gpd.ch = HAL_LIGHTNING_PKT_CH_LAST_GPD; + ptr_sw_gpd->tx_gpd.ioc = HAL_LIGHTNING_PKT_IOC_HAS_INTR; + ptr_sw_gpd->tx_gpd.pkt_len = ptr_skb->len; + + /* fill up cpu header */ + ptr_sw_gpd->tx_gpd.itmh_eth.skip_ipp = 1; + ptr_sw_gpd->tx_gpd.itmh_eth.skip_epp = 1; + ptr_sw_gpd->tx_gpd.itmh_eth.color = 0; /* Green */ + ptr_sw_gpd->tx_gpd.itmh_eth.tc = 15; /* Max tc */ + ptr_sw_gpd->tx_gpd.itmh_eth.igr_phy_port = 0; + + ptr_sw_gpd->tx_gpd.pph_l2.mrk_pcp_val = 7; /* Max pcp */ + ptr_sw_gpd->tx_gpd.pph_l2.mrk_pcp_dei_en = 1; + + /* + if (!_hal_lightning_pkt_isProtocolPkt(ptr_skb)){ + ptr_sw_gpd->tx_gpd.itmh_eth.tc = 0; + ptr_sw_gpd->tx_gpd.pph_l2.mrk_pcp_val = 0; + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_TX, "Set TC and PCP to 0\n"); + } + */ + + /* destination index + * 1. to local ETH port + * 2. to remote ETH port + * 3. to remote CPU + */ + ptr_sw_gpd->tx_gpd.itmh_eth.dst_idx = port; + + /* [CL8570] we should set all-1 for the following fields to skip some tm-logic */ + + /* TM header */ + ptr_sw_gpd->tx_gpd.itmh_eth.src_idx = 0x7fff; + ptr_sw_gpd->tx_gpd.itmh_eth.intf_fdid = 0x3fff; + ptr_sw_gpd->tx_gpd.itmh_eth.src_supp_tag = 0x1f; + ptr_sw_gpd->tx_gpd.itmh_eth.nvo3_mgid = 0x6fff; + ptr_sw_gpd->tx_gpd.itmh_eth.nvo3_src_supp_tag_w0 = 0x1; + ptr_sw_gpd->tx_gpd.itmh_eth.nvo3_src_supp_tag_w1 = 0xf; + + /* PP header */ + ptr_sw_gpd->tx_gpd.pph_l2.nvo3_encap_idx = HAL_INVALID_NVO3_ENCAP_IDX; + ptr_sw_gpd->tx_gpd.pph_l2.nvo3_adj_idx = HAL_INVALID_NVO3_ADJ_IDX; + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Init: net_dev_ops */ +static int +_hal_lightning_pkt_net_dev_init( + struct net_device *ptr_net_dev) +{ + return 0; +} + +static int +_hal_lightning_pkt_net_dev_open( + struct net_device *ptr_net_dev) +{ + netif_start_queue(ptr_net_dev); + +#if defined(PERF_EN_TEST) + /* Tx (len, tx_channel, rx_channel, test_skb) */ + perf_test(64, 1, 0, FALSE); + perf_test(64, 2, 0, FALSE); + perf_test(64, 4, 0, FALSE); + + perf_test(1518, 1, 0, FALSE); + perf_test(1518, 2, 0, FALSE); + perf_test(1518, 4, 0, FALSE); + + perf_test(9216, 1, 0, FALSE); + perf_test(9216, 2, 0, FALSE); + perf_test(9216, 4, 0, FALSE); + + /* Rx (len, tx_channel, rx_channel, test_skb) */ + perf_test(64, 0, 1, FALSE); + perf_test(64, 0, 3, FALSE); + perf_test(64, 0, 4, FALSE); + + perf_test(1518, 0, 1, FALSE); + perf_test(1518, 0, 3, FALSE); + perf_test(1518, 0, 4, FALSE); + + perf_test(9216, 0, 1, FALSE); + perf_test(9216, 0, 3, FALSE); + perf_test(9216, 0, 4, FALSE); +#endif + + return 0; +} + +static int +_hal_lightning_pkt_net_dev_stop( + struct net_device *ptr_net_dev) +{ + netif_stop_queue(ptr_net_dev); + return 0; +} + +static int +_hal_lightning_pkt_net_dev_ioctl( + struct net_device *ptr_net_dev, + struct ifreq *ptr_ifreq, + int cmd) +{ + return 0; +} + +static netdev_tx_t +_hal_lightning_pkt_net_dev_tx( + struct sk_buff *ptr_skb, + struct net_device *ptr_net_dev) +{ + struct net_device_priv *ptr_priv = netdev_priv(ptr_net_dev); + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb; + /* chip meta */ + unsigned int unit; + unsigned int channel = 0; + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd = NULL; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0x0; + + if (NULL == ptr_priv) + { + /* in case that the netdev has been freed/reset somewhere */ + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, "get netdev_priv failed\n"); + return -EFAULT; + } + + /* check skb */ + if (NULL == ptr_skb) + { + ptr_priv->stats.tx_errors++; + return -EFAULT; + } + + unit = ptr_priv->unit; + + ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + + /* for warm de-init procedure, if any net intf not destroyed, it is possible + * that kernel still has packets to send causing segmentation fault + */ + if (FALSE == ptr_tx_cb->net_tx_allowed) { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, "net tx during sdk de-init\n"); + ptr_priv->stats.tx_dropped++; + osal_skb_free(ptr_skb); + return NETDEV_TX_OK; + } + + /* pad to 60-bytes if skb_len < 60, see: eth_skb_pad(skb) */ + if (ptr_skb->len < ETH_ZLEN) + { + skb_pad(ptr_skb, ETH_ZLEN - ptr_skb->len); + skb_set_tail_pointer(ptr_skb, ETH_ZLEN); + ptr_skb->len = ETH_ZLEN; + } + + /* pad 4-bytes for chip-crc */ + skb_pad(ptr_skb, ETH_FCS_LEN); + skb_set_tail_pointer(ptr_skb, ETH_FCS_LEN); + ptr_skb->len += ETH_FCS_LEN; + + /* alloc gpd */ + ptr_sw_gpd = osal_alloc(sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T)); + if (NULL == ptr_sw_gpd) + { + ptr_priv->stats.tx_errors++; + osal_skb_free(ptr_skb); + } + else + { + /* map skb to dma */ + ptr_virt_addr = ptr_skb->data; + phy_addr = osal_skb_mapDma(ptr_skb, DMA_TO_DEVICE); + if (0x0 == phy_addr) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_ERR, "u=%u, txch=%u, skb dma map err\n", + unit, channel); + ptr_priv->stats.tx_errors++; + osal_skb_free(ptr_skb); + osal_free(ptr_sw_gpd); + } + else + { + /* trans skb to gpd */ + memset(ptr_sw_gpd, 0x0, sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T)); + ptr_sw_gpd->callback = (void *)_hal_lightning_pkt_net_dev_tx_callback; + ptr_sw_gpd->ptr_cookie = (void *)ptr_skb; + ptr_sw_gpd->gpd_num = 1; + ptr_sw_gpd->ptr_next = NULL; + ptr_sw_gpd->channel = channel; + /* prepare gpd */ + hal_lightning_pkt_prepareGpd(unit, phy_addr, ptr_skb, ptr_priv->port, ptr_sw_gpd); + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(4,6,7) + ptr_net_dev->trans_start = jiffies; +#else + netdev_get_tx_queue(ptr_net_dev, 0)->trans_start = jiffies; +#endif + /* send gpd */ + if (CLX_E_OK == hal_lightning_pkt_sendGpd(unit, channel, ptr_sw_gpd)) + { + ptr_priv->stats.tx_packets++; + ptr_priv->stats.tx_bytes += ptr_skb->len; + } + else + { + ptr_priv->stats.tx_fifo_errors++; /* to record the extreme cases where packets are dropped */ + ptr_priv->stats.tx_dropped++; + + osal_skb_unmapDma(phy_addr, ptr_skb->len, DMA_TO_DEVICE); + osal_skb_free(ptr_skb); + osal_free(ptr_sw_gpd); + } + } + } + + return NETDEV_TX_OK; +} +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,10,0) +static void +_hal_lightning_pkt_net_dev_tx_timeout( + struct net_device *ptr_net_dev, + unsigned int txqueue) +#else +static void +_hal_lightning_pkt_net_dev_tx_timeout( + struct net_device *ptr_net_dev) +#endif +{ + netif_stop_queue(ptr_net_dev); + osal_sleepThread(1000); + netif_wake_queue(ptr_net_dev); +} + +static struct net_device_stats * +_hal_lightning_pkt_net_dev_get_stats( + struct net_device *ptr_net_dev) +{ + struct net_device_priv *ptr_priv = netdev_priv(ptr_net_dev); + + return (&ptr_priv->stats); +} + +static int +_hal_lightning_pkt_net_dev_set_mtu( + struct net_device *ptr_net_dev, + int new_mtu) +{ + if (new_mtu < 64 || new_mtu > 9216) + { + return -EINVAL; + } + ptr_net_dev->mtu = new_mtu; /* This mtu need to be synced to chip's */ + return 0; +} + +static int +_hal_lightning_pkt_net_dev_set_mac( + struct net_device *ptr_net_dev, + void *ptr_mac_addr) +{ + struct sockaddr *ptr_addr = ptr_mac_addr; + + memcpy(ptr_net_dev->dev_addr, ptr_addr->sa_data, ptr_net_dev->addr_len); + return 0; +} + +static void +_hal_lightning_pkt_net_dev_set_rx_mode( + struct net_device *ptr_dev) +{ + if (ptr_dev->flags & IFF_PROMISC) + { + } + else + { + if (ptr_dev->flags & IFF_ALLMULTI) + { + } + else + { + if (netdev_mc_empty(ptr_dev)) + { + return; + } + } + } +} + +static struct net_device_ops _hal_lightning_pkt_net_dev_ops = +{ + .ndo_init = _hal_lightning_pkt_net_dev_init, + .ndo_open = _hal_lightning_pkt_net_dev_open, + .ndo_stop = _hal_lightning_pkt_net_dev_stop, + .ndo_do_ioctl = _hal_lightning_pkt_net_dev_ioctl, + .ndo_start_xmit = _hal_lightning_pkt_net_dev_tx, + .ndo_tx_timeout = _hal_lightning_pkt_net_dev_tx_timeout, + .ndo_get_stats = _hal_lightning_pkt_net_dev_get_stats, + .ndo_change_mtu = _hal_lightning_pkt_net_dev_set_mtu, + .ndo_set_mac_address = _hal_lightning_pkt_net_dev_set_mac, + .ndo_set_rx_mode = _hal_lightning_pkt_net_dev_set_rx_mode, +}; + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) +static int +_hal_lightning_pkt_net_dev_ethtool_get( + struct net_device *ptr_dev, + struct ethtool_cmd *ptr_cmd) +{ + struct net_device_priv *ptr_priv; + + ptr_cmd->supported = SUPPORTED_1000baseT_Full | SUPPORTED_FIBRE; + ptr_cmd->port = PORT_FIBRE; + ptr_cmd->duplex = DUPLEX_FULL; + + ptr_priv = netdev_priv(ptr_dev); + ethtool_cmd_speed_set(ptr_cmd, ptr_priv->speed); + + return 0; +} +#endif + +static struct ethtool_ops _hal_lightning_pkt_net_dev_ethtool_ops = +{ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + .get_settings = _hal_lightning_pkt_net_dev_ethtool_get, +#endif + .get_link = ethtool_op_get_link, +}; + +static void +_hal_lightning_pkt_setup( + struct net_device *ptr_net_dev) +{ + struct net_device_priv *ptr_priv = netdev_priv(ptr_net_dev); + + /* setup net device */ + ether_setup(ptr_net_dev); + ptr_net_dev->netdev_ops = &_hal_lightning_pkt_net_dev_ops; + ptr_net_dev->ethtool_ops = &_hal_lightning_pkt_net_dev_ethtool_ops; + ptr_net_dev->watchdog_timeo = HAL_LIGHTNING_PKT_TX_TIMEOUT; + ptr_net_dev->mtu = HAL_LIGHTNING_PKT_MAX_ETH_FRAME_SIZE; /* This mtu need to be synced to chip's */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,19,0) + ptr_net_dev->min_mtu = 64; + ptr_net_dev->max_mtu = 65535; +#endif + random_ether_addr(ptr_net_dev->dev_addr); /* Please use the mac-addr of interface. */ + + /* setup private data */ + ptr_priv->ptr_net_dev = ptr_net_dev; + memset(&ptr_priv->stats, 0, sizeof(struct net_device_stats)); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_createIntf( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_INTF_T net_intf = {0}; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + struct net_device *ptr_net_dev = NULL; + struct net_device_priv *ptr_priv = NULL; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* Lock all Rx tasks to avoid any access to the intf during packet processing */ + /* Only Rx tasks are locked since Tx action is performed under a spinlock protection */ + _hal_lightning_pkt_lockRxChannelAll(unit); + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, "u=%u, create intf name=%s, phy port=%d\n", + unit, net_intf.name, net_intf.port); + + /* To check if the interface with the same name exists in kernel */ + ptr_net_dev = dev_get_by_name(&init_net, net_intf.name); + if (NULL != ptr_net_dev) + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_ERR | HAL_LIGHTNING_PKT_DBG_INTF), + "u=%u, create intf failed, exist same name=%s\n", + unit, net_intf.name); + + dev_put(ptr_net_dev); + +#if defined(HAL_LIGHTNING_PKT_FORCR_REMOVE_DUPLICATE_NETDEV) + ptr_net_dev->operstate = IF_OPER_DOWN; + netif_carrier_off(ptr_net_dev); + netif_tx_disable(ptr_net_dev); + unregister_netdev(ptr_net_dev); + free_netdev(ptr_net_dev); +#endif + _hal_lightning_pkt_unlockRxChannelAll(unit); + return (CLX_E_ENTRY_EXISTS); + } + + /* Bind the net dev and intf meta data to internel port-based array */ + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(net_intf.port); + if (ptr_port_db->ptr_net_dev == NULL) + { + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0) + ptr_net_dev = alloc_netdev(sizeof(struct net_device_priv), + net_intf.name, NET_NAME_UNKNOWN, _hal_lightning_pkt_setup); +#else + ptr_net_dev = alloc_netdev(sizeof(struct net_device_priv), + net_intf.name, _hal_lightning_pkt_setup); +#endif + memcpy(ptr_net_dev->dev_addr, net_intf.mac, ptr_net_dev->addr_len); + + ptr_priv = netdev_priv(ptr_net_dev); + + /* Port info will be used when packet sent from this netdev */ + ptr_priv->port = net_intf.port; + ptr_priv->id = net_intf.port; + ptr_priv->unit = unit; + + register_netdev(ptr_net_dev); + + netif_carrier_off(ptr_net_dev); + + net_intf.id = net_intf.port; /* Currently, id is 1-to-1 mapped to port */ + osal_memcpy(&ptr_port_db->meta, &net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + + ptr_port_db->ptr_net_dev = ptr_net_dev; + + /* Copy the intf-id to user space */ + osal_io_copyToUser(&ptr_cookie->net_intf, &net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_INTF | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, create intf failed, exist on phy port=%d\n", + unit, net_intf.port); + /* The user needs to delete the existing intf binding to the same port */ + rc = CLX_E_ENTRY_EXISTS; + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_destroyIntf( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_INTF_T net_intf = {0}; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + /* Lock all Rx tasks to avoid any access to the intf during packet processing */ + /* Only Rx tasks are locked since Tx action is performed under a spinlock protection */ + _hal_lightning_pkt_lockRxChannelAll(unit); + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + + /* Unregister net devices by id, although the "id" is now relavent to "port" we still perform a search */ + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, + "u=%u, find intf %s (id=%d) on phy port=%d, destroy done\n", + unit, + ptr_port_db->meta.name, + ptr_port_db->meta.id, + ptr_port_db->meta.port); + + netif_carrier_off(ptr_port_db->ptr_net_dev); + netif_tx_disable(ptr_port_db->ptr_net_dev); + unregister_netdev(ptr_port_db->ptr_net_dev); + free_netdev(ptr_port_db->ptr_net_dev); + + /* Don't need to remove profiles on this port. + * In fact, the profile is binding to "port" not "intf". + */ + /* _hal_lightning_pkt_destroyProfList(ptr_port_db->ptr_profile_list); */ + + osal_memset(ptr_port_db, 0x0, sizeof(HAL_LIGHTNING_PKT_NETIF_PORT_DB_T)); + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_traverseProfList( + UI32_T intf_id, + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_prof_list) +{ + HAL_LIGHTNING_PKT_PROFILE_NODE_T *ptr_curr_node; + + ptr_curr_node = ptr_prof_list; + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, "intf id=%d, prof list=", intf_id); + while(NULL != ptr_curr_node) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, "%s (%d) => ", + ptr_curr_node->ptr_profile->name, + ptr_curr_node->ptr_profile->priority); + ptr_curr_node = ptr_curr_node->ptr_next_node; + } + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, "null\n"); + return (CLX_E_OK); +} + + +static CLX_ERROR_NO_T +_hal_lightning_pkt_getIntf( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_INTF_T net_intf = {0}; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_INTF, "u=%u, find intf id=%d\n", unit, net_intf.id); + _hal_lightning_pkt_traverseProfList(net_intf.id, ptr_port_db->ptr_profile_list); + osal_io_copyToUser(&ptr_cookie->net_intf, &ptr_port_db->meta, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +static HAL_LIGHTNING_PKT_NETIF_PROFILE_T * +_hal_lightning_pkt_getProfEntry( + const UI32_T id) +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile = NULL; + + if (id < HAL_LIGHTNING_PKT_NET_PROFILE_NUM_MAX) + { + if (NULL != _ptr_hal_lightning_pkt_profile_entry[id]) + { + ptr_profile = _ptr_hal_lightning_pkt_profile_entry[id]; + } + } + + return (ptr_profile); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_createProfile( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + CLX_ERROR_NO_T rc; + + /* Lock all Rx tasks to avoid profiles being refered during packet processing */ + /* Need to lock all Rx tasks since packets from all Rx channels do profile lookup */ + _hal_lightning_pkt_lockRxChannelAll(unit); + + ptr_profile = osal_alloc(sizeof(HAL_LIGHTNING_PKT_NETIF_PROFILE_T)); + osal_io_copyFromUser(ptr_profile, &ptr_cookie->net_profile, + sizeof(HAL_LIGHTNING_PKT_NETIF_PROFILE_T)); + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "u=%u, create prof name=%s, priority=%d, flag=0x%x\n", + unit, + ptr_profile->name, + ptr_profile->priority, + ptr_profile->flags); + + /* Save the profile to the profile array and assign the index to ptr_profile->id */ + rc = _hal_lightning_pkt_allocProfEntry(ptr_profile); + if (CLX_E_OK == rc) + { + /* Insert the profile to the corresponding (port) interface */ + if ((ptr_profile->flags & HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PORT) != 0) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "u=%u, bind prof to phy port=%d\n", unit, ptr_profile->port); + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(ptr_profile->port); + _hal_lightning_pkt_addProfToList(ptr_profile, &ptr_port_db->ptr_profile_list); + } + else + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "u=%u, bind prof to all intf\n", unit); + _hal_lightning_pkt_addProfToAllIntf(ptr_profile); + } + + /* Copy the ptr_profile->id to user space */ + osal_io_copyToUser(&ptr_cookie->net_profile, ptr_profile, sizeof(HAL_LIGHTNING_PKT_NETIF_PROFILE_T)); + } + else + { + HAL_LIGHTNING_PKT_DBG((HAL_LIGHTNING_PKT_DBG_PROFILE | HAL_LIGHTNING_PKT_DBG_ERR), + "u=%u, alloc prof entry failed, tbl full\n", unit); + osal_free(ptr_profile); + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_destroyProfile( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T profile = {0}; + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* Lock all Rx tasks to avoid profiles being refered during packet processing */ + /* Need to lock all Rx tasks since packets from all Rx channels do profile lookup */ + _hal_lightning_pkt_lockRxChannelAll(unit); + + osal_io_copyFromUser(&profile, &ptr_cookie->net_profile, + sizeof(HAL_LIGHTNING_PKT_NETIF_PROFILE_T)); + + /* Remove the profile from corresponding interface (port) */ + _hal_lightning_pkt_delProfFromAllIntfById(profile.id); + + ptr_profile = _hal_lightning_pkt_freeProfEntry(profile.id); + if (NULL != ptr_profile) + { + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_PROFILE, + "u=%u, destroy prof id=%d, name=%s, priority=%d, flag=0x%x\n", + unit, + ptr_profile->id, + ptr_profile->name, + ptr_profile->priority, + ptr_profile->flags); + osal_free(ptr_profile); + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + _hal_lightning_pkt_unlockRxChannelAll(unit); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_getProfile( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T profile = {0}; + HAL_LIGHTNING_PKT_NETIF_PROFILE_T *ptr_profile; + CLX_ERROR_NO_T rc = CLX_E_OK; + + osal_io_copyFromUser(&profile, &ptr_cookie->net_profile, sizeof(HAL_LIGHTNING_PKT_NETIF_PROFILE_T)); + + ptr_profile = _hal_lightning_pkt_getProfEntry(profile.id); + if (NULL != ptr_profile) + { + osal_io_copyToUser(&ptr_cookie->net_profile, ptr_profile, sizeof(HAL_LIGHTNING_PKT_NETIF_PROFILE_T)); + } + else + { + rc = CLX_E_ENTRY_NOT_FOUND; + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_getIntfCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_INTF_T net_intf = {0}; + HAL_LIGHTNING_PKT_NETIF_INTF_CNT_T intf_cnt = {0}; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + struct net_device_priv *ptr_priv; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + ptr_priv = netdev_priv(ptr_port_db->ptr_net_dev); + intf_cnt.rx_pkt = ptr_priv->stats.rx_packets; + intf_cnt.tx_pkt = ptr_priv->stats.tx_packets; + intf_cnt.tx_error = ptr_priv->stats.tx_errors; + intf_cnt.tx_queue_full = ptr_priv->stats.tx_fifo_errors; + + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->cnt, &intf_cnt, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_CNT_T)); + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_hal_lightning_pkt_clearIntfCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *ptr_cookie) +{ + HAL_LIGHTNING_PKT_NETIF_INTF_T net_intf = {0}; + HAL_LIGHTNING_PKT_NETIF_PORT_DB_T *ptr_port_db; + struct net_device_priv *ptr_priv; + UI32_T port = 0; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + osal_io_copyFromUser(&net_intf, &ptr_cookie->net_intf, sizeof(HAL_LIGHTNING_PKT_NETIF_INTF_T)); + + for (port = 0; port < HAL_LIGHTNING_PKT_MAX_PORT_NUM; port++) + { + ptr_port_db = HAL_LIGHTNING_PKT_GET_PORT_DB(port); + if (NULL != ptr_port_db->ptr_net_dev) /* valid intf */ + { + if (ptr_port_db->meta.id == net_intf.id) + { + ptr_priv = netdev_priv(ptr_port_db->ptr_net_dev); + ptr_priv->stats.rx_packets = 0; + ptr_priv->stats.tx_packets = 0; + ptr_priv->stats.tx_errors = 0; + ptr_priv->stats.tx_fifo_errors = 0; + + rc = CLX_E_OK; + break; + } + } + } + + osal_io_copyToUser(&ptr_cookie->rc, &rc, sizeof(CLX_ERROR_NO_T)); + + return (CLX_E_OK); +} + +/* ----------------------------------------------------------------------------------- Init: dev_ops */ +static void +_hal_lightning_pkt_dev_tx_callback( + const UI32_T unit, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd_usr) +{ + UI32_T channel = ptr_sw_gpd->channel; + HAL_LIGHTNING_PKT_TX_CB_T *ptr_tx_cb = HAL_LIGHTNING_PKT_GET_TX_CB_PTR(unit); + + while (0 != _hal_lightning_pkt_enQueue(&ptr_tx_cb->sw_queue, ptr_sw_gpd)) + { + ptr_tx_cb->cnt.channel[channel].enque_retry++; + HAL_LIGHTNING_PKT_TX_ENQUE_RETRY_SLEEP(); + } + ptr_tx_cb->cnt.channel[channel].enque_ok++; + + osal_triggerEvent(&ptr_tx_cb->sync_sema); + ptr_tx_cb->cnt.channel[channel].trig_event++; +} + +ssize_t +hal_lightning_pkt_dev_tx( + struct file *file, + const char __user *buf, + size_t count, + loff_t *pos) +{ + int ret = 0; + int idx = 0; + unsigned int unit = 0; + unsigned int channel = 0; + HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T tx_cookie; + HAL_LIGHTNING_PKT_IOCTL_TX_GPD_T ioctl_gpd; + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd_knl = NULL; + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_first_sw_gpd_knl = NULL; + + /* copy the tx-cookie */ + osal_io_copyFromUser(&tx_cookie, (void *)buf, sizeof(HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T)); + + unit = tx_cookie.unit; + channel = tx_cookie.channel; + + ptr_sw_gpd_knl = osal_alloc(sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T)); + ptr_first_sw_gpd_knl = ptr_sw_gpd_knl; + + /* create SW GPD based on the content of each IOCTL GPD */ + while (1) + { + osal_io_copyFromUser(&ioctl_gpd, + ((void *)((CLX_HUGE_T)tx_cookie.ioctl_gpd_addr)) + +idx*sizeof(HAL_LIGHTNING_PKT_IOCTL_TX_GPD_T), + sizeof(HAL_LIGHTNING_PKT_IOCTL_TX_GPD_T)); + + ptr_sw_gpd_knl->channel = ioctl_gpd.channel; + ptr_sw_gpd_knl->gpd_num = ioctl_gpd.gpd_num; + ptr_sw_gpd_knl->ptr_cookie = (void *)ioctl_gpd.cookie; + + /* directly copy user's HW GPD */ + osal_io_copyFromUser(&ptr_sw_gpd_knl->tx_gpd, + (void *)((CLX_HUGE_T)ioctl_gpd.hw_gpd_addr), + sizeof(HAL_LIGHTNING_PKT_TX_GPD_T)); + + /* replace the callback */ + ptr_sw_gpd_knl->callback = (void *)_hal_lightning_pkt_dev_tx_callback; + + /* save the first SW GPD address from userspace since + * we have replaced the original callback + */ + ptr_sw_gpd_knl->ptr_cookie = (void *)ioctl_gpd.sw_gpd_addr; + + if (HAL_LIGHTNING_PKT_CH_LAST_GPD == ptr_sw_gpd_knl->tx_gpd.ch) + { + ptr_sw_gpd_knl->ptr_next = NULL; + break; + } + else + { + ptr_sw_gpd_knl->ptr_next = (HAL_LIGHTNING_PKT_TX_SW_GPD_T *)osal_alloc( + sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T)); + ptr_sw_gpd_knl = ptr_sw_gpd_knl->ptr_next; + idx++; + } + } + + ret = hal_lightning_pkt_sendGpd(unit, channel, ptr_first_sw_gpd_knl); + if (CLX_E_OK != ret) + { + _hal_lightning_pkt_freeTxGpdList(unit, ptr_first_sw_gpd_knl); + } + + /* return 0 if success */ + return (ret); +} + +long +hal_lightning_pkt_dev_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + int ret = 0; + + /* cmd */ + HAL_LIGHTNING_PKT_IOCTL_CMD_T *ptr_cmd = (HAL_LIGHTNING_PKT_IOCTL_CMD_T *)&cmd; + unsigned int unit = ptr_cmd->field.unit; + HAL_LIGHTNING_PKT_IOCTL_TYPE_T type = ptr_cmd->field.type; + + HAL_LIGHTNING_PKT_DBG(HAL_LIGHTNING_PKT_DBG_COMMON, "u=%u, ioctl type=%u, cmd=%u\n", + unit, type, cmd); + + switch (type) + { + /* network interface */ + case HAL_LIGHTNING_PKT_IOCTL_TYPE_CREATE_INTF: + ret = _hal_lightning_pkt_createIntf(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_DESTROY_INTF: + ret = _hal_lightning_pkt_destroyIntf(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_INTF: + ret = _hal_lightning_pkt_getIntf(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_CREATE_PROFILE: + ret = _hal_lightning_pkt_createProfile(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_DESTROY_PROFILE: + ret = _hal_lightning_pkt_destroyProfile(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_PROFILE: + ret = _hal_lightning_pkt_getProfile(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_INTF_CNT: + ret = _hal_lightning_pkt_getIntfCnt(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_CLEAR_INTF_CNT: + ret = _hal_lightning_pkt_clearIntfCnt(unit, (HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T *)arg); + break; + + /* driver */ + case HAL_LIGHTNING_PKT_IOCTL_TYPE_WAIT_RX_FREE: + ret = _hal_lightning_pkt_schedRxDeQueue(unit, (HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_WAIT_TX_FREE: + ret = _hal_lightning_pkt_strictTxDeQueue(unit, (HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_SET_RX_CFG: + ret = hal_lightning_pkt_setRxKnlConfig(unit, (HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_RX_CFG: + ret = hal_lightning_pkt_getRxKnlConfig(unit, (HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_DEINIT_TASK: + ret = hal_lightning_pkt_deinitTask(unit); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_DEINIT_DRV: + ret = hal_lightning_pkt_deinitPktDrv(unit); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_INIT_TASK: + ret = hal_lightning_pkt_initTask(unit); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_INIT_DRV: + ret = hal_lightning_pkt_initPktDrv(unit); + break; + + /* counter */ + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_TX_CNT: + ret = hal_lightning_pkt_getTxKnlCnt(unit, (HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_RX_CNT: + ret = hal_lightning_pkt_getRxKnlCnt(unit, (HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_CLEAR_TX_CNT: + ret = hal_lightning_pkt_clearTxKnlCnt(unit, (HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_CLEAR_RX_CNT: + ret = hal_lightning_pkt_clearRxKnlCnt(unit, (HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_SET_PORT_ATTR: + ret = hal_lightning_pkt_setPortAttr(unit, (HAL_LIGHTNING_PKT_IOCTL_PORT_COOKIE_T *)arg); + break; + + case HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_PORT_ATTR: + ret = hal_lightning_pkt_getPortAttr(unit, (HAL_LIGHTNING_PKT_IOCTL_PORT_COOKIE_T *)arg); + break; + +#if defined(NETIF_EN_NETLINK) + case HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_SET_INTF_PROPERTY: + ret = _hal_lightning_pkt_setIntfProperty(unit, (HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_GET_INTF_PROPERTY: + ret = _hal_lightning_pkt_getIntfProperty(unit, (HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_CREATE_NETLINK: + ret = _hal_lightning_pkt_createNetlink(unit, (HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_DESTROY_NETLINK: + ret = _hal_lightning_pkt_destroyNetlink(unit, (HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *)arg); + break; + case HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_GET_NETLINK: + ret = _hal_lightning_pkt_getNetlink(unit, (HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T *)arg); + break; +#endif + + default: + ret = -1; + break; + } + + return (ret); +} + +/* ----------------------------------------------------------------------------------- Init/Deinit */ +CLX_ERROR_NO_T +hal_lightning_pkt_init( + const UI32_T unit) +{ + /* Init Thread */ + osal_init(); + + /* Reset all database*/ + osal_memset(_hal_lightning_pkt_port_db, 0x0, + (HAL_LIGHTNING_PKT_MAX_PORT_NUM * sizeof(HAL_LIGHTNING_PKT_NETIF_PORT_DB_T))); + osal_memset(_hal_lightning_pkt_rx_cb, 0x0, + CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM*sizeof(HAL_LIGHTNING_PKT_RX_CB_T)); + osal_memset(_hal_lightning_pkt_tx_cb, 0x0, + CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM*sizeof(HAL_LIGHTNING_PKT_TX_CB_T)); + osal_memset(_hal_lightning_pkt_drv_cb, 0x0, + CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM*sizeof(HAL_LIGHTNING_PKT_DRV_CB_T)); + +#if defined(NETIF_EN_NETLINK) + netif_nl_init(); +#endif + + return (0); +} + +CLX_ERROR_NO_T +hal_lightning_pkt_exit( + const UI32_T unit) +{ + /* 1st. Stop all netdev (if any) to prevent kernel from Tx new packets */ + _hal_lightning_pkt_stopAllIntf(unit); + + /* 2nd. Stop Rx HW DMA and free all the DMA buffer hooked on the ring */ + _hal_lightning_pkt_rxStop(unit); + + /* 3rd. Need to wait Rx done task process all the availavle packets on GPD ring */ + + /* 4th. Stop all the internal tasks (if any) */ + hal_lightning_pkt_deinitTask(unit); + + /* 5th. Deinit pkt driver for common database/interrupt source (if required) */ + hal_lightning_pkt_deinitPktDrv(unit); + + /* 6th. Clean up those intf/profiles not been destroyed */ + _hal_lightning_pkt_destroyAllProfile(unit); + _hal_lightning_pkt_destroyAllIntf(unit); + + osal_deinit(); + + return (0); +} diff --git a/platform/clounix/clounix-modules/modules/src/clx_netif/netif_knl.c b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_knl.c new file mode 100755 index 000000000000..5a6eedaf7b7a --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_knl.c @@ -0,0 +1,304 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_knl.c + * PURPOSE: + * To provide operations registered to kernel callback and + * dispatch the operations to different chip drivers. + * + * NOTES: + * + */ + +/***************************************************************************** + * INCLUDE FILE DECLARATIONS + ***************************************************************************** + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#if defined(CLX_EN_LIGHTNING) && defined(CLX_EN_DAWN) +#define NETIF_KNL_SUPPORT_CHIP "Lightning/Dawn" +#elif defined(CLX_EN_LIGHTNING) +#define NETIF_KNL_SUPPORT_CHIP "Lightning" +#else +#define NETIF_KNL_SUPPORT_CHIP "Dawn" +#endif + +#define NETIF_KNL_MODULE_DESC "NETIF Kernel Module (" NETIF_KNL_SUPPORT_CHIP ")" + +#define NETIF_KNL_DRIVER_MINOR_NUM (252) /* DO NOT use MISC_DYNAMIC_MINOR */ +#define NETIF_KNL_DRIVER_NAME "clx_netif" + +#define NETIF_KNL_IO_ERROR_RC (-1) + +typedef ssize_t +(*NETIF_KNL_DEV_TX_FUNC_T)( + struct file *file, + const char __user *buf, + size_t count, + loff_t *pos); + +typedef long +(*NETIF_KNL_DEV_IOCTL_FUNC_T)( + struct file *filp, + unsigned int cmd, + unsigned long arg); + +typedef CLX_ERROR_NO_T +(*NETIF_KNL_DEV_INIT_T)( + const UI32_T unit); + +typedef CLX_ERROR_NO_T +(*NETIF_KNL_DEV_EXIT_T)( + const UI32_T unit); + +typedef struct +{ + NETIF_KNL_DEV_IOCTL_FUNC_T ioctl; + NETIF_KNL_DEV_TX_FUNC_T tx; + NETIF_KNL_DEV_INIT_T init; + NETIF_KNL_DEV_EXIT_T exit; +} NETIF_KNL_DEV_OPS_T; + +typedef struct +{ + UI16_T dev_id; + NETIF_KNL_DEV_OPS_T ops; + +} NETIF_KNL_CB_T; + +extern struct pci_dev *_ptr_ext_pci_dev; +static NETIF_KNL_CB_T _netif_knl_cb; +UI32_T ext_dbg_flag = 0; + +#define NETIF_KNL_DEVICE_IS_LIGHTNING(__dev_id__) (HAL_DEVICE_ID_CL8500 == (__dev_id__ & 0xFF00)) +#define NETIF_KNL_DEVICE_IS_DAWN(__dev_id__) (HAL_DEVICE_ID_CL8300 == (__dev_id__ & 0xFF00)) + +#define NETIF_KNL_DBG_FLAG_COMMON (0x1UL << 5) + +#define NETIF_KNL_DBG(__flag__, ...) do \ +{ \ + if (0 != ((__flag__) & (ext_dbg_flag))) \ + { \ + osal_printf(__VA_ARGS__); \ + } \ +}while (0) + +static CLX_ERROR_NO_T +_netif_knl_initDevOps( + const UI16_T dev_id, + NETIF_KNL_DEV_OPS_T *ptr_ops) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { +#if defined(CLX_EN_LIGHTNING) + NETIF_KNL_DBG(NETIF_KNL_DBG_FLAG_COMMON, + "lightning ops hooked\n"); + ptr_ops->init = hal_lightning_pkt_init; + ptr_ops->exit = hal_lightning_pkt_exit; + ptr_ops->tx = hal_lightning_pkt_dev_tx; + ptr_ops->ioctl = hal_lightning_pkt_dev_ioctl; +#else + NETIF_KNL_DBG(NETIF_KNL_DBG_FLAG_COMMON, + "lightning detected, but ops not support\n"); +#endif + } + else if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { +#if defined(CLX_EN_DAWN) + NETIF_KNL_DBG(NETIF_KNL_DBG_FLAG_COMMON, + "dawn ops hooked\n"); + ptr_ops->init = hal_dawn_pkt_init; + ptr_ops->exit = hal_dawn_pkt_exit; + ptr_ops->tx = hal_dawn_pkt_dev_tx; + ptr_ops->ioctl = hal_dawn_pkt_dev_ioctl; +#else + NETIF_KNL_DBG(NETIF_KNL_DBG_FLAG_COMMON, + "dawn detected, but ops not support\n"); +#endif + } + else + { + NETIF_KNL_DBG(NETIF_KNL_DBG_FLAG_COMMON, + "unknown chip family, dev_id=0x%x\n", + dev_id); + rc = CLX_E_OTHERS; + } + + return (rc); +} + +static CLX_ERROR_NO_T +_netif_knl_getDevId( + UI16_T *ptr_dev_id) +{ + pci_read_config_word(_ptr_ext_pci_dev, PCI_DEVICE_ID, ptr_dev_id); + return (CLX_E_OK); +} + +static int +_netif_knl_dev_open( + struct inode *inode, + struct file *file) +{ + UI32_T unit = 0; + CLX_ERROR_NO_T rc; + + _netif_knl_getDevId(&_netif_knl_cb.dev_id); + + rc = _netif_knl_initDevOps(_netif_knl_cb.dev_id, + &_netif_knl_cb.ops); + if (CLX_E_OK == rc) + { + if (_netif_knl_cb.ops.init != NULL) + { + _netif_knl_cb.ops.init(unit); + } + } + + return (0); +} + +static int +_netif_knl_dev_close( + struct inode *inode, + struct file *file) +{ + return (0); +} + +static ssize_t +_netif_knl_dev_tx( + struct file *file, + const char __user *buf, + size_t count, + loff_t *pos) +{ + long ret = NETIF_KNL_IO_ERROR_RC; + + if (_netif_knl_cb.ops.tx != NULL) + { + ret = _netif_knl_cb.ops.tx(file, buf, count, pos); + } + + return (ret); +} + +static ssize_t +_netif_knl_dev_rx( + struct file *file, + char __user *buf, + size_t count, + loff_t *pos) +{ + return (0); +} + +static long +_netif_knl_dev_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + long ret = NETIF_KNL_IO_ERROR_RC; + + if (_netif_knl_cb.ops.ioctl != NULL) + { + ret = _netif_knl_cb.ops.ioctl(filp, cmd, arg); + } + + return (ret); +} + +#ifdef CONFIG_COMPAT +static long +_netif_knl_dev_compat_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + return _netif_knl_dev_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + +static struct file_operations _netif_knl_dev_ops = +{ + .owner = THIS_MODULE, + .open = _netif_knl_dev_open, + .release = _netif_knl_dev_close, + .write = _netif_knl_dev_tx, + .read = _netif_knl_dev_rx, + .unlocked_ioctl = _netif_knl_dev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = _netif_knl_dev_compat_ioctl, +#endif +}; + +static struct miscdevice _netif_knl_dev = +{ + .minor = NETIF_KNL_DRIVER_MINOR_NUM, + .name = NETIF_KNL_DRIVER_NAME, + .fops = &_netif_knl_dev_ops, +}; + +static int __init +netif_knl_init(void) +{ + misc_register(&_netif_knl_dev); + + osal_memset(&_netif_knl_cb, 0x0, sizeof(NETIF_KNL_CB_T)); + + return (0); +} + +static void __exit +netif_knl_exit(void) +{ + UI32_T unit = 0; + + if (_netif_knl_cb.ops.exit != NULL) + { + _netif_knl_cb.ops.exit(unit); + } + + misc_deregister(&_netif_knl_dev); +} + +module_init(netif_knl_init); +module_exit(netif_knl_exit); + +module_param(ext_dbg_flag, uint, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(ext_dbg_flag, "bit0:error, bit1:tx, bit2:rx, bit3:intf, bit4:profile, " \ + "bit5:common, bit6:netlink"); +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Clounix"); +MODULE_DESCRIPTION(NETIF_KNL_MODULE_DESC); diff --git a/platform/clounix/clounix-modules/modules/src/clx_netif/netif_nl.c b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_nl.c new file mode 100755 index 000000000000..0764972eeaa4 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_nl.c @@ -0,0 +1,812 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_xxx.c + * PURPOSE: + * It provide xxx API. + * NOTES: + */ +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +extern UI32_T ext_dbg_flag; + +#define NETIF_NL_DBG(__flag__, ...) do \ +{ \ + if (0 != ((__flag__) & (ext_dbg_flag))) \ + { \ + osal_printf(__VA_ARGS__); \ + } \ +}while (0) + +#define NETIF_NL_DBG_NETLINK (0x1UL << 6) + +#define NETIF_NL_FAMILY_NUM_MAX (256) +#define NETIF_NL_INTF_NUM_MAX (256) + +#define NETIF_NL_GET_FAMILY_META(__idx__) &(_netif_nl_cb.fam_entry[__idx__].meta) +#define NETIF_NL_GET_INTF_IGR_SAMPLE_RATE(__inft_id__) (_netif_nl_cb.intf_entry[__inft_id__].igr_sample_rate) + +#define NETIF_NL_FAMILY_IS_PSAMPLE(__ptr_family__) (0 == strncmp(__ptr_family__->name, \ + NETIF_NL_PSAMPLE_FAMILY_NAME, \ + NETIF_NL_NETLINK_NAME_LEN)) ? 1 : 0 + +/* porting part */ +#define NETIF_NL_VER_NUM (1) +#define NETIF_NL_PSAMPLE_MAX_ATTR_NUM (NETIF_NL_PSAMPLE_ATTR_LAST) +#define NETIF_NL_REGISTER_FAMILY(__family__) genl_register_family(__family__) + +#define NETIF_NL_UNREGISTER_FAMILY(__family__) genl_unregister_family(__family__) +#define NETIF_NL_ALLOC_SKB(__len__) genlmsg_new(__len__, GFP_ATOMIC) +#define NETIF_NL_FREE_SKB(__ptr_skb__) nlmsg_free(__ptr_skb__) + +#define NETIF_NL_SEND_PKT(__ptr_family__, __mcgrp_id__, __ptr_skb__) \ + genlmsg_multicast_netns(__ptr_family__, \ + &init_net, \ + __ptr_skb__, \ + 0, /* pid, avoid loop */ \ + __mcgrp_id__, \ + GFP_ATOMIC) +#define NETIF_NL_SET_SKB_ATTR_HDR(__skb__, __family__, __hdr_len__, __cmd__) \ + genlmsg_put(__skb__, 0, 0, __family__, \ + __hdr_len__, __cmd__) +#define NETIF_NL_END_SKB_ATTR_HDR(__skb__, __hdr__) genlmsg_end(__skb__, __hdr__) + +#define NETIF_NL_SET_16_BIT_ATTR(__skb__, __attr__, __data__) nla_put_u16(__skb__, __attr__, __data__) +#define NETIF_NL_SET_32_BIT_ATTR(__skb__, __attr__, __data__) nla_put_u32(__skb__, __attr__, __data__) + + +/* + * <----------- nla_total_size(payload) -------------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * + * + * <-------- nla_attr_size(payload) ----------> + * +------------------+- - -+- - - - - - - - - +- - -+ + * | Attribute Header | Pad | Payload | Pad | + * +------------------+- - -+- - - - - - - - - +- - -+ + * + */ +/* total size = attr data size + attr header size */ +#define NETIF_NL_GET_ATTR_TOTAL_SIZE(__data_size__) nla_total_size(__data_size__) +#define NETIF_NL_GET_ATTR_SIZE(__data_size__) nla_attr_size(__data_size__) /* without padding */ + + +/* psample's family and group parameter */ +#define NETIF_NL_PSAMPLE_FAMILY_NAME "psample" +#define NETIF_NL_PSAMPLE_MC_GROUP_NAME_DATA "packets" +#define NETIF_NL_PSAMPLE_MC_GROUP_NAME_CFG "config" +#define NETIF_NL_PSAMPLE_MC_GROUP_NUM (NETIF_NL_PSAMPLE_MC_GROUP_ID_LAST) +#define NETIF_NL_DEFAULT_MC_GROUP_NUM (1) + +#define NETIF_NL_PSAMPLE_PKT_LEN_MAX (9216) +#define NETIF_NL_PSAMPLE_DFLT_USR_GROUP_ID (1) + +typedef enum +{ + NETIF_NL_PSAMPLE_MC_GROUP_ID_CONFIG = 0, + NETIF_NL_PSAMPLE_MC_GROUP_ID_SAMPLE, + NETIF_NL_PSAMPLE_MC_GROUP_ID_LAST, +} NETIF_NL_PSAMPLE_MC_GROUP_ID_T; + +typedef enum +{ + NETIF_NL_PSAMPLE_ATTR_IIFINDEX = 0, + NETIF_NL_PSAMPLE_ATTR_OIFINDEX, + NETIF_NL_PSAMPLE_ATTR_ORIGSIZE, + NETIF_NL_PSAMPLE_ATTR_SAMPLE_GROUP, + NETIF_NL_PSAMPLE_ATTR_GROUP_SEQ, + NETIF_NL_PSAMPLE_ATTR_SAMPLE_RATE, + NETIF_NL_PSAMPLE_ATTR_DATA, + NETIF_NL_PSAMPLE_ATTR_LAST +} NETIF_NL_PSAMPLE_ATTR_ID_T; + + +typedef struct genl_multicast_group NETIF_NL_MC_GROUP_T; +typedef struct genl_family NETIF_NL_FAMILY_T; + +static NETIF_NL_MC_GROUP_T _netif_nl_psample_mc_group[NETIF_NL_PSAMPLE_MC_GROUP_ID_LAST]; +static C8_T *_ptr_netif_nl_psample_mc_group_name[NETIF_NL_PSAMPLE_MC_GROUP_ID_LAST] = + { + NETIF_NL_PSAMPLE_MC_GROUP_NAME_CFG, + NETIF_NL_PSAMPLE_MC_GROUP_NAME_DATA + }; + +static NETIF_NL_MC_GROUP_T _netif_nl_default_mc_group[NETIF_NL_DEFAULT_MC_GROUP_NUM]; +static C8_T *_ptr_netif_nl_default_mc_group_name[NETIF_NL_DEFAULT_MC_GROUP_NUM] = + { + "default", + }; + +typedef struct +{ + NETIF_NL_FAMILY_T meta; + BOOL_T valid; + +} NETIF_NL_FAMILY_ENTRY_T; + +typedef struct +{ + UI32_T igr_sample_rate; + UI32_T egr_sample_rate; + UI32_T trunc_size; +} NETIF_NL_INTF_ENTRY_T; + +typedef struct +{ + NETIF_NL_FAMILY_ENTRY_T fam_entry[NETIF_NL_FAMILY_NUM_MAX]; + NETIF_NL_INTF_ENTRY_T intf_entry[NETIF_NL_INTF_NUM_MAX]; /* sorted in intf_id */ + UI32_T seq_num; +} NETIF_NL_CB_T; + +static NETIF_NL_CB_T _netif_nl_cb; + +/* should extract to common */ +struct net_device_priv +{ + struct net_device *ptr_net_dev; + struct net_device_stats stats; + UI32_T unit; + UI32_T id; + UI32_T port; + UI16_T vlan; + UI32_T speed; +}; + +static CLX_ERROR_NO_T +_netif_nl_setIntfIgrSampleRate( + const UI32_T unit, + const UI32_T id, + const UI32_T rate) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + + ptr_cb->intf_entry[id].igr_sample_rate = rate; + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_netif_nl_setIntfEgrSampleRate( + const UI32_T unit, + const UI32_T id, + const UI32_T rate) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + + ptr_cb->intf_entry[id].egr_sample_rate = rate; + + return (CLX_E_OK); +} + + +CLX_ERROR_NO_T +netif_nl_setIntfProperty( + const UI32_T unit, + const UI32_T id, + const NETIF_NL_INTF_PROPERTY_T property, + const UI32_T param0, + const UI32_T param1) +{ + CLX_ERROR_NO_T rc = CLX_E_BAD_PARAMETER; + + if (NETIF_NL_INTF_PROPERTY_IGR_SAMPLING_RATE == property) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "receive set igr sample rate req, id=%d, property=%d, param0=%d, param=%d\n", + id, property, param0, param1); + rc = _netif_nl_setIntfIgrSampleRate(unit, id, param0); + } + else if (NETIF_NL_INTF_PROPERTY_EGR_SAMPLING_RATE == property) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "receive set egr sample rate req, id=%d, property=%d, param0=%d, param=%d\n", + id, property, param0, param1); + rc = _netif_nl_setIntfEgrSampleRate(unit, id, param0); + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[error] unknown property, property=%d\n", property); + } + + return (rc); +} + +static CLX_ERROR_NO_T +_netif_nl_getIntfIgrSampleRate( + const UI32_T unit, + const UI32_T id, + UI32_T *ptr_rate) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + + *ptr_rate = ptr_cb->intf_entry[id].igr_sample_rate; + + return (CLX_E_OK); +} + +static CLX_ERROR_NO_T +_netif_nl_getIntfEgrSampleRate( + const UI32_T unit, + const UI32_T id, + UI32_T *ptr_rate) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + + *ptr_rate = ptr_cb->intf_entry[id].egr_sample_rate; + + return (CLX_E_OK); +} + + +CLX_ERROR_NO_T +netif_nl_getIntfProperty( + const UI32_T unit, + const UI32_T id, + const NETIF_NL_INTF_PROPERTY_T property, + UI32_T *ptr_param0, + UI32_T *ptr_param1) +{ + CLX_ERROR_NO_T rc = CLX_E_BAD_PARAMETER; + + if (NETIF_NL_INTF_PROPERTY_IGR_SAMPLING_RATE == property) + { + rc = _netif_nl_getIntfIgrSampleRate(unit, id, ptr_param0); + } + else if (NETIF_NL_INTF_PROPERTY_EGR_SAMPLING_RATE == property) + { + rc = _netif_nl_getIntfEgrSampleRate(unit, id, ptr_param0); + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[error] unknown property, property=%d\n", + property); + } + + return (rc); +} + +CLX_ERROR_NO_T +_netif_nl_allocNlFamilyEntry( + NETIF_NL_CB_T *ptr_cb, + UI32_T *ptr_index) +{ + UI32_T idx; + CLX_ERROR_NO_T rc = CLX_E_TABLE_FULL; + + for (idx = 0; idx < NETIF_NL_FAMILY_NUM_MAX; idx++) + { + if (FALSE == ptr_cb->fam_entry[idx].valid) + { + *ptr_index = idx; + ptr_cb->fam_entry[idx].valid = TRUE; + rc = CLX_E_OK; + break; + } + } + + return (rc); +} + +void +_netif_nl_freeNlFamilyEntry( + NETIF_NL_CB_T *ptr_cb, + const UI32_T index) +{ + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] free netlink family entry, idx=%d\n", + index); + ptr_cb->fam_entry[index].valid = FALSE; +} + +CLX_ERROR_NO_T +_netif_nl_setNlMcgroupPsample( + NETIF_NL_FAMILY_T *ptr_nl_family) +{ + NETIF_NL_MC_GROUP_T *ptr_nl_mc_group = _netif_nl_psample_mc_group; + UI32_T idx; + + /* init the mc group and hook the group to family */ + osal_memset(ptr_nl_mc_group, 0x0, + (NETIF_NL_PSAMPLE_MC_GROUP_NUM * sizeof(NETIF_NL_MC_GROUP_T))); + + for (idx = 0; idx < NETIF_NL_PSAMPLE_MC_GROUP_ID_LAST; idx++) + { + osal_memcpy(ptr_nl_mc_group[idx].name, + _ptr_netif_nl_psample_mc_group_name[idx], + osal_strlen(_ptr_netif_nl_psample_mc_group_name[idx])); + } + ptr_nl_family->n_mcgrps = NETIF_NL_PSAMPLE_MC_GROUP_NUM; + ptr_nl_family->mcgrps = ptr_nl_mc_group; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +_netif_nl_setNlMcgroupDefault( + NETIF_NL_FAMILY_T *ptr_nl_family) +{ + NETIF_NL_MC_GROUP_T *ptr_nl_mc_group = _netif_nl_default_mc_group; + UI32_T idx; + + /* init the mc group and hook the group to family */ + osal_memset(ptr_nl_mc_group, 0x0, + (NETIF_NL_DEFAULT_MC_GROUP_NUM * sizeof(NETIF_NL_MC_GROUP_T))); + + for (idx = 0; idx < NETIF_NL_DEFAULT_MC_GROUP_NUM; idx++) + { + osal_memcpy(ptr_nl_mc_group[idx].name, + _ptr_netif_nl_default_mc_group_name[idx], + osal_strlen(_ptr_netif_nl_default_mc_group_name[idx])); + } + ptr_nl_family->n_mcgrps = NETIF_NL_DEFAULT_MC_GROUP_NUM; + ptr_nl_family->mcgrps = ptr_nl_mc_group; + + return (CLX_E_OK); +} + +#define NETIF_NL_IS_FAMILY_ENTRY_VALID(__idx__) \ + (TRUE == _netif_nl_cb.fam_entry[__idx__].valid) ? (TRUE) : (FALSE) +CLX_ERROR_NO_T +netif_nl_createNetlink( + const UI32_T unit, + NETIF_NL_NETLINK_T *ptr_netlink, + UI32_T *ptr_netlink_id) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + UI32_T entry_id; + NETIF_NL_FAMILY_T *ptr_nl_family; + NETIF_NL_MC_GROUP_T *ptr_nl_mcgrp; + UI32_T idx; + int ret; + CLX_ERROR_NO_T rc; + + rc = _netif_nl_allocNlFamilyEntry(ptr_cb, &entry_id); + if (CLX_E_OK == rc) + { + ptr_nl_family = NETIF_NL_GET_FAMILY_META(entry_id); + + /* fill in the meta data for that netlink family */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 10, 0) + ptr_nl_family->id = GENL_ID_GENERATE; /* family id can be ignored since linux 4.10 */ +#endif + ptr_nl_family->version = NETIF_NL_VER_NUM; + ptr_nl_family->maxattr = NETIF_NL_PSAMPLE_MAX_ATTR_NUM; + ptr_nl_family->netnsok = true; + osal_memcpy(ptr_nl_family->name, ptr_netlink->name, NETIF_NL_NETLINK_NAME_LEN); + + /* fill in the mc group info */ + ptr_nl_mcgrp = osal_alloc(sizeof(NETIF_NL_MC_GROUP_T)*ptr_netlink->mc_group_num); + if (NULL != ptr_nl_mcgrp) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, "[DBG] create mc group:\n"); + for (idx = 0; idx < ptr_netlink->mc_group_num; idx++) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] - mcgrp%d: %s\n", idx, ptr_netlink->mc_group[idx].name); + osal_memcpy(ptr_nl_mcgrp[idx].name, ptr_netlink->mc_group[idx].name, + NETIF_NL_NETLINK_NAME_LEN); + } + ptr_nl_family->n_mcgrps = ptr_netlink->mc_group_num; + ptr_nl_family->mcgrps = ptr_nl_mcgrp; + + /* register the family to kernel */ + ret = NETIF_NL_REGISTER_FAMILY(ptr_nl_family); + if (0 == ret) + { + *ptr_netlink_id = entry_id; + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] create netlink family, name=%s, entry_idx=%d, mcgrp_num=%d\n", + ptr_netlink->name, entry_id, ptr_nl_family->n_mcgrps); + rc = CLX_E_OK; + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] register netlink family failed, name=%s, ret=%d\n", + ptr_netlink->name, ret); + osal_free(ptr_nl_mcgrp); + _netif_nl_freeNlFamilyEntry(ptr_cb, entry_id); + rc = CLX_E_OTHERS; + } + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, "[DBG] alloc mcgrp failed\n"); + rc = CLX_E_NO_MEMORY; + } + } + + return (rc); +} + +CLX_ERROR_NO_T +netif_nl_destroyNetlink( + const UI32_T unit, + const UI32_T netlink_id) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + UI32_T entry_idx = netlink_id; + NETIF_NL_FAMILY_T *ptr_nl_family; + int ret; + CLX_ERROR_NO_T rc; + + if (TRUE == NETIF_NL_IS_FAMILY_ENTRY_VALID(entry_idx)) + { + ptr_nl_family = NETIF_NL_GET_FAMILY_META(entry_idx); + ret = NETIF_NL_UNREGISTER_FAMILY(ptr_nl_family); + if (0 == ret) + { + osal_free(ptr_nl_family->mcgrps); + _netif_nl_freeNlFamilyEntry(ptr_cb, entry_idx); + rc = CLX_E_OK; + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] unregister netlink family failed, name=%s, ret=%d\n", + ptr_nl_family->name, ret); + rc = CLX_E_OTHERS; + } + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] destroy netlink failed, invalid netlink_id %d\n", + netlink_id); + rc = CLX_E_ENTRY_NOT_FOUND; + } + + return (rc); +} + +CLX_ERROR_NO_T +netif_nl_getNetlink( + const UI32_T unit, + const UI32_T netlink_id, + NETIF_NL_NETLINK_T *ptr_netlink) +{ + UI32_T entry_idx = netlink_id; + NETIF_NL_FAMILY_T *ptr_meta; + UI32_T grp_idx; + CLX_ERROR_NO_T rc = CLX_E_OK; + + if (TRUE == NETIF_NL_IS_FAMILY_ENTRY_VALID(entry_idx)) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] get valid netlink, id=%d\n", netlink_id); + + ptr_netlink->id = netlink_id; + ptr_meta = NETIF_NL_GET_FAMILY_META(entry_idx); + + ptr_netlink->mc_group_num = ptr_meta->n_mcgrps; + osal_memcpy(ptr_netlink->name, ptr_meta->name, NETIF_NL_NETLINK_NAME_LEN); + + for (grp_idx = 0; grp_idx < ptr_meta->n_mcgrps; grp_idx++) + { + osal_memcpy(ptr_netlink->mc_group[grp_idx].name, + ptr_meta->mcgrps[grp_idx].name, + NETIF_NL_NETLINK_NAME_LEN); + } + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] get netlink failed, invalid netlink_id %d\n", + netlink_id); + rc = CLX_E_ENTRY_NOT_FOUND; + } + + return (rc); +} + + +CLX_ERROR_NO_T +_netif_nl_getFamilyByName( + NETIF_NL_CB_T *ptr_cb, + const C8_T *ptr_name, + NETIF_NL_FAMILY_T **pptr_nl_family) +{ + UI32_T idx; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + for (idx = 0; idx < NETIF_NL_FAMILY_NUM_MAX; idx++) + { + if ((TRUE == ptr_cb->fam_entry[idx].valid) && + (0 == strncmp(ptr_cb->fam_entry[idx].meta.name, + ptr_name, + NETIF_NL_NETLINK_NAME_LEN))) + { + *pptr_nl_family = &(ptr_cb->fam_entry[idx].meta); + rc = CLX_E_OK; + break; + } + } + + if (CLX_E_ENTRY_NOT_FOUND == rc) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] find family failed, name=%s\n", + ptr_name); + } + + return (rc); +} + +CLX_ERROR_NO_T +_netif_nl_getMcgrpIdByName( + NETIF_NL_FAMILY_T *ptr_nl_family, + const C8_T *ptr_mcgrp_name, + UI32_T *ptr_mcgrp_id) +{ + UI32_T idx; + CLX_ERROR_NO_T rc = CLX_E_ENTRY_NOT_FOUND; + + for (idx = 0; idx < ptr_nl_family->n_mcgrps; idx++) + { + if ((0 == strncmp(ptr_nl_family->mcgrps[idx].name, + ptr_mcgrp_name, + NETIF_NL_NETLINK_NAME_LEN))) + { + *ptr_mcgrp_id = idx; + rc = CLX_E_OK; + break; + } + } + + if (CLX_E_OK != rc) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] find mcgrp %s failed in family %s\n", + ptr_mcgrp_name, ptr_nl_family->name); + } + + return (rc); +} + +CLX_ERROR_NO_T +_netif_nl_allocPsampleSkb( + NETIF_NL_CB_T *ptr_cb, + NETIF_NL_FAMILY_T *ptr_nl_family, + struct sk_buff *ptr_ori_skb, + struct sk_buff **pptr_nl_skb) +{ + UI32_T msg_hdr_len; + UI32_T data_len; + struct sk_buff *ptr_nl_skb; + UI16_T igr_intf_idx; + struct net_device_priv *ptr_priv; + UI32_T rate; + UI32_T intf_id; + void *ptr_nl_hdr = NULL; + struct nlattr *ptr_nl_attr; + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* make sure the total len (original pkt len + hdr msg) < PSAMPLE_MAX_PACKET_SIZE */ + + msg_hdr_len = NETIF_NL_GET_ATTR_TOTAL_SIZE(sizeof(UI16_T)) + /* PSAMPLE_ATTR_IIFINDEX */ + NETIF_NL_GET_ATTR_TOTAL_SIZE(sizeof(UI32_T)) + /* PSAMPLE_ATTR_SAMPLE_RATE */ + NETIF_NL_GET_ATTR_TOTAL_SIZE(sizeof(UI32_T)) + /* PSAMPLE_ATTR_ORIGSIZE */ + NETIF_NL_GET_ATTR_TOTAL_SIZE(sizeof(UI32_T)) + /* PSAMPLE_ATTR_SAMPLE_GROUP */ + NETIF_NL_GET_ATTR_TOTAL_SIZE(sizeof(UI32_T)); /* PSAMPLE_ATTR_GROUP_SEQ */ + + data_len = NETIF_NL_GET_ATTR_TOTAL_SIZE(ptr_ori_skb->len); + + if ((msg_hdr_len + NETIF_NL_GET_ATTR_TOTAL_SIZE(ptr_ori_skb->len)) > NETIF_NL_PSAMPLE_PKT_LEN_MAX) + { + data_len = NETIF_NL_PSAMPLE_PKT_LEN_MAX - msg_hdr_len - NLA_HDRLEN - NLA_ALIGNTO; + } + else + { + data_len = ptr_ori_skb->len; + } + + ptr_nl_skb = NETIF_NL_ALLOC_SKB(NETIF_NL_GET_ATTR_TOTAL_SIZE(data_len) + msg_hdr_len); + if (NULL != ptr_nl_skb) + { + /* to create a netlink msg header (cmd=0) */ + ptr_nl_hdr = NETIF_NL_SET_SKB_ATTR_HDR(ptr_nl_skb, ptr_nl_family, 0, 0); + if (NULL != ptr_nl_hdr) + { + /* obtain the intf index for the igr_port */ + igr_intf_idx = ptr_ori_skb->dev->ifindex; + NETIF_NL_SET_16_BIT_ATTR(ptr_nl_skb, NETIF_NL_PSAMPLE_ATTR_IIFINDEX, + (UI16_T)igr_intf_idx); + + /* meta header */ + /* use the igr port id as the index for the database to get sample rate */ + ptr_priv = netdev_priv(ptr_ori_skb->dev); + intf_id = ptr_priv->port; + rate = NETIF_NL_GET_INTF_IGR_SAMPLE_RATE(intf_id); + NETIF_NL_SET_32_BIT_ATTR(ptr_nl_skb, NETIF_NL_PSAMPLE_ATTR_SAMPLE_RATE, rate); + NETIF_NL_SET_32_BIT_ATTR(ptr_nl_skb, NETIF_NL_PSAMPLE_ATTR_ORIGSIZE, data_len); + NETIF_NL_SET_32_BIT_ATTR(ptr_nl_skb, NETIF_NL_PSAMPLE_ATTR_SAMPLE_GROUP, + NETIF_NL_PSAMPLE_DFLT_USR_GROUP_ID); + NETIF_NL_SET_32_BIT_ATTR(ptr_nl_skb, NETIF_NL_PSAMPLE_ATTR_GROUP_SEQ, ptr_cb->seq_num); + ptr_cb->seq_num++; + + /* data */ + ptr_nl_attr = (struct nlattr *)skb_put(ptr_nl_skb, NETIF_NL_GET_ATTR_TOTAL_SIZE(data_len)); + ptr_nl_attr->nla_type = NETIF_NL_PSAMPLE_ATTR_DATA; + /* get the attr size without padding, since it's the last one */ + ptr_nl_attr->nla_len = NETIF_NL_GET_ATTR_SIZE(data_len); + skb_copy_bits(ptr_ori_skb, 0, nla_data(ptr_nl_attr), data_len); + + NETIF_NL_END_SKB_ATTR_HDR(ptr_nl_skb, ptr_nl_hdr); + } + else + { + rc = CLX_E_OTHERS; + } + } + else + { + rc = CLX_E_OTHERS; + } + + *pptr_nl_skb = ptr_nl_skb; + + return (rc); +} + +CLX_ERROR_NO_T +_netif_nl_allocNetlinkSkb( + NETIF_NL_CB_T *ptr_cb, + NETIF_NL_FAMILY_T *ptr_nl_family, + struct sk_buff *ptr_ori_skb, + struct sk_buff **pptr_nl_skb) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + + /* need to fill specific skb header format */ + if (NETIF_NL_FAMILY_IS_PSAMPLE(ptr_nl_family)) + { + rc = _netif_nl_allocPsampleSkb(ptr_cb, ptr_nl_family, + ptr_ori_skb, pptr_nl_skb); + if (CLX_E_OK != rc) + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] alloc netlink skb failed\n"); + } + } + else + { + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "[DBG] unknown netlink family\n"); + rc = CLX_E_OTHERS; + } + + return (rc); +} + +CLX_ERROR_NO_T +_netif_nl_sendNetlinkSkb( + NETIF_NL_FAMILY_T *ptr_nl_family, + UI32_T nl_mcgrp_id, + struct sk_buff *ptr_nl_skb) +{ + int ret; + CLX_ERROR_NO_T rc; + + ret = NETIF_NL_SEND_PKT(ptr_nl_family, nl_mcgrp_id, ptr_nl_skb); + if (0 == ret) + { + rc = CLX_E_OK; + } + else + { + /* in errno_base.h, #define ESRCH 3 : No such process */ + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, + "send skb to mc group failed, ret=%d\n", ret); + rc = CLX_E_OTHERS; + } + + return (rc); +} + +void +_netif_nl_freeNetlinkSkb( + struct sk_buff *ptr_nl_skb) +{ + NETIF_NL_DBG(NETIF_NL_DBG_NETLINK, "[DBG] free nl skb\n"); + NETIF_NL_FREE_SKB(ptr_nl_skb); +} + +CLX_ERROR_NO_T +_netif_nl_forwardPkt( + NETIF_NL_CB_T *ptr_cb, + NETIF_NL_RX_DST_NETLINK_T *ptr_nl_dest, + struct sk_buff *ptr_ori_skb) +{ + struct sk_buff *ptr_nl_skb = NULL; + NETIF_NL_FAMILY_T *ptr_nl_family; + UI32_T nl_mcgrp_id; + CLX_ERROR_NO_T rc; + + rc = _netif_nl_getFamilyByName(ptr_cb, ptr_nl_dest->name, + &ptr_nl_family); + if (CLX_E_OK == rc) + { + rc = _netif_nl_getMcgrpIdByName(ptr_nl_family, ptr_nl_dest->mc_group_name, + &nl_mcgrp_id); + if (CLX_E_OK == rc) + { + rc = _netif_nl_allocNetlinkSkb(ptr_cb, ptr_nl_family, + ptr_ori_skb, &ptr_nl_skb); + if (CLX_E_OK == rc) + { + rc = _netif_nl_sendNetlinkSkb(ptr_nl_family, nl_mcgrp_id, + ptr_nl_skb); + if (CLX_E_OK != rc) + { + /* _netif_nl_freeNetlinkSkb(ptr_nl_skb); */ + } + } + } + } + + return (rc); +} + +CLX_ERROR_NO_T +netif_nl_rxSkb( + const UI32_T unit, + struct sk_buff *ptr_skb, + void *ptr_cookie) +{ + NETIF_NL_CB_T *ptr_cb = &_netif_nl_cb; + + NETIF_NL_RX_DST_NETLINK_T *ptr_nl_dest; + CLX_ERROR_NO_T rc; + + ptr_nl_dest = (NETIF_NL_RX_DST_NETLINK_T *)ptr_cookie; + + /* send the packet to netlink mcgroup */ + rc = _netif_nl_forwardPkt(ptr_cb, ptr_nl_dest, ptr_skb); + + /* need to free the original skb anyway */ + osal_skb_free(ptr_skb); + + return (rc); +} + +CLX_ERROR_NO_T +netif_nl_init(void) +{ + osal_memset(&_netif_nl_cb, 0x0, sizeof(NETIF_NL_CB_T)); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +netif_nl_deinit(void) +{ + return (CLX_E_OK); +} + diff --git a/platform/clounix/clounix-modules/modules/src/clx_netif/netif_osal.c b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_osal.c new file mode 100755 index 000000000000..8472425266b3 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_osal.c @@ -0,0 +1,755 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_osal.c + * PURPOSE: + * It provide customer linux API. + * NOTES: + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0) +#include +#endif +#include + +/* ----------------------------------------------------------------------------------- macro value */ +#define OSAL_US_PER_SECOND (1000000) /* macro second per second */ +#define OSAL_NS_PER_USECOND (1000) /* nano second per macro second */ + +/* ----------------------------------------------------------------------------------- macro function */ +#define OSAL_LOG_ERR(msg, ...) \ + osal_printf("\033[31m\033[0m"msg, __LINE__, ##__VA_ARGS__) + +/* ----------------------------------------------------------------------------------- struct */ +extern struct pci_dev *_ptr_ext_pci_dev; + +static linux_thread_t _osal_thread_head = {{0}}; + +/* ----------------------------------------------------------------------------------- function */ +/* general */ +void * +osal_memset( + void *ptr_mem, + const I32_T value, + const UI32_T num) +{ + return memset(ptr_mem, value, num); +} + +void * +osal_memcpy( + void *ptr_dst, + const void *ptr_src, + const UI32_T num) +{ + return memcpy(ptr_dst, ptr_src, num); +} + +UI32_T +osal_strlen( + const C8_T *ptr_str) +{ + return strlen(ptr_str); +} + +void +osal_printf( + const C8_T *ptr_fmt, + ...) +{ + va_list ap; + char buf[OSAL_PRN_BUF_SZ]; + + if (NULL != ptr_fmt) + { + va_start(ap, ptr_fmt); + vsnprintf(buf, OSAL_PRN_BUF_SZ, ptr_fmt, ap); + va_end(ap); + + printk("%s", buf); + } +} + +void * +osal_alloc( + const UI32_T size) +{ + return kmalloc(size, GFP_ATOMIC); +} + +void +osal_free( + const void *ptr_mem) +{ + kfree(ptr_mem); +} + +/* thread */ +CLX_ERROR_NO_T +osal_init(void) +{ + linux_thread_t *ptr_thread_head = &_osal_thread_head; + + memset(ptr_thread_head, 0x0, sizeof(linux_thread_t)); + + /* init */ + ptr_thread_head->ptr_prev = ptr_thread_head; + ptr_thread_head->ptr_next = ptr_thread_head; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_deinit(void) +{ + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_createThread( + const C8_T *ptr_thread_name, + const UI32_T stack_size, + const UI32_T priority, + void (function)(void*), + void *ptr_arg, + CLX_THREAD_ID_T *ptr_thread_id) +{ + char dft_name[OSAL_THREAD_NAME_LEN + 1] = OSAL_THREAD_DFT_NAME; + linux_thread_t *ptr_thread_head = &_osal_thread_head; + linux_thread_t *ptr_thread_node = osal_alloc(sizeof(linux_thread_t)); + + /* process name */ + osal_memcpy(ptr_thread_node->name, (0 == osal_strlen(ptr_thread_name))? + dft_name : ptr_thread_name, OSAL_THREAD_NAME_LEN); + ptr_thread_node->name[OSAL_THREAD_NAME_LEN] = '\0'; + + /* init */ + ptr_thread_node->ptr_task = kthread_create((int(*)(void *))function, ptr_arg, ptr_thread_name); + ptr_thread_node->ptr_task->policy = SCHED_RR; + ptr_thread_node->ptr_task->rt_priority = priority; + ptr_thread_node->is_stop = FALSE; + + *ptr_thread_id = (CLX_THREAD_ID_T)ptr_thread_node; + + wake_up_process(ptr_thread_node->ptr_task); + + /* append the thread_node */ + ptr_thread_node->ptr_prev = ptr_thread_head->ptr_prev; + ptr_thread_head->ptr_prev->ptr_next = ptr_thread_node; + ptr_thread_node->ptr_next = ptr_thread_head; + ptr_thread_head->ptr_prev = ptr_thread_node; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_stopThread( + CLX_THREAD_ID_T *ptr_thread_id) +{ + linux_thread_t *ptr_thread_node = (linux_thread_t *)(*ptr_thread_id); + + ptr_thread_node->is_stop = TRUE; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_destroyThread( + CLX_THREAD_ID_T *ptr_thread_id) +{ + linux_thread_t *ptr_thread_node = (linux_thread_t *)(*ptr_thread_id); + + kthread_stop(ptr_thread_node->ptr_task); + + /* remove the thread_node */ + ptr_thread_node->ptr_next->ptr_prev = ptr_thread_node->ptr_prev; + ptr_thread_node->ptr_prev->ptr_next = ptr_thread_node->ptr_next; + + osal_free(ptr_thread_node); + *ptr_thread_id = 0; + + return (CLX_E_OK); +} + +void +osal_initRunThread(void) +{ + /* for reboot or shutdown without stopping kthread */ + allow_signal(SIGTERM); +} + +CLX_ERROR_NO_T +osal_isRunThread(void) +{ + linux_thread_t *ptr_thread_node = _osal_thread_head.ptr_next; + + while (1) + { + if (ptr_thread_node == &_osal_thread_head) + { + OSAL_LOG_ERR("Cannot find task %p.\n", current); + break; + } + if (ptr_thread_node->ptr_task == current) + { + break; + } + ptr_thread_node = ptr_thread_node->ptr_next; + } + + if ((TRUE == ptr_thread_node->is_stop) || (signal_pending(current))) + { + return (CLX_E_OTHERS); + } + + return (CLX_E_OK); +} + +void +osal_exitRunThread(void) +{ + while (!kthread_should_stop() && !signal_pending(current)) + { + osal_sleepThread(OSAL_NS_PER_USECOND); + } +} + +/* semaphore */ +CLX_ERROR_NO_T +osal_createSemaphore( + const C8_T *ptr_sema_name, + const UI32_T sema_count, + CLX_SEMAPHORE_ID_T *ptr_semaphore_id) +{ + char dft_name[OSAL_SEMA_NAME_LEN + 1] = OSAL_SEMA_DFT_NAME; + linux_sema_t *ptr_sema = osal_alloc(sizeof(linux_sema_t)); + + /* process name */ + osal_memcpy(ptr_sema->name, (0 == osal_strlen(ptr_sema_name))? + dft_name : ptr_sema_name, OSAL_SEMA_NAME_LEN); + ptr_sema->name[OSAL_SEMA_NAME_LEN] = '\0'; + + /* init */ + sema_init(&ptr_sema->lock, CLX_SEMAPHORE_BINARY); + + *ptr_semaphore_id = (CLX_SEMAPHORE_ID_T)ptr_sema; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_takeSemaphore( + CLX_SEMAPHORE_ID_T *ptr_semaphore_id, + UI32_T time_out) +{ + linux_sema_t *ptr_sema = (linux_sema_t *)(*ptr_semaphore_id); + + if (in_interrupt()) + { + return (CLX_E_OTHERS); + } + + if (!down_interruptible(&ptr_sema->lock)) + { + return (CLX_E_OK); + } + + return (CLX_E_OTHERS); +} + +CLX_ERROR_NO_T +osal_giveSemaphore( + CLX_SEMAPHORE_ID_T *ptr_semaphore_id) +{ + linux_sema_t *ptr_sema = (linux_sema_t *)(*ptr_semaphore_id); + + up(&ptr_sema->lock); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_destroySemaphore( + CLX_SEMAPHORE_ID_T *ptr_semaphore_id) +{ + linux_sema_t *ptr_sema = (linux_sema_t *)(*ptr_semaphore_id); + + osal_free(ptr_sema); + *ptr_semaphore_id = 0; + + return (CLX_E_OK); +} + +/* event */ +CLX_ERROR_NO_T +osal_createEvent( + const C8_T *ptr_event_name, + CLX_SEMAPHORE_ID_T *ptr_event_id) +{ + char dft_name[OSAL_EVENT_NAME_LEN + 1] = OSAL_EVENT_DFT_NAME; + linux_event_t *ptr_event = osal_alloc(sizeof(linux_event_t)); + + /* process name */ + osal_memcpy(ptr_event->name, (0 == osal_strlen(ptr_event_name))? + dft_name : ptr_event_name, OSAL_EVENT_NAME_LEN); + ptr_event->name[OSAL_EVENT_NAME_LEN] = '\0'; + + /* init */ + ptr_event->condition = FALSE; + init_waitqueue_head(&ptr_event->wait_que); + + *ptr_event_id = (CLX_SEMAPHORE_ID_T)ptr_event; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_waitEvent( + CLX_SEMAPHORE_ID_T *ptr_event_id) +{ + linux_event_t *ptr_event = (linux_event_t *)(*ptr_event_id); + + if (!wait_event_interruptible(ptr_event->wait_que, ptr_event->condition)) + { + ptr_event->condition = FALSE; + + return (CLX_E_OK); + } + + return (CLX_E_OTHERS); +} + +CLX_ERROR_NO_T +osal_triggerEvent( + CLX_SEMAPHORE_ID_T *ptr_event_id) +{ + linux_event_t *ptr_event = (linux_event_t *)(*ptr_event_id); + + ptr_event->condition = TRUE; + wake_up_interruptible(&ptr_event->wait_que); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_destroyEvent( + CLX_SEMAPHORE_ID_T *ptr_event_id) +{ + linux_event_t *ptr_event = (linux_event_t *)(*ptr_event_id); + + osal_free(ptr_event); + *ptr_event_id = 0; + + return (CLX_E_OK); +} + +/* isr_lock */ +CLX_ERROR_NO_T +osal_createIsrLock( + const C8_T *ptr_isrlock_name, + CLX_ISRLOCK_ID_T *ptr_isrlock_id) +{ + char dft_name[OSAL_SPIN_NAME_LEN + 1] = OSAL_SPIN_DFT_NAME; + linux_isrlock_t *ptr_isrlock = osal_alloc(sizeof(linux_isrlock_t)); + + /* process name */ + osal_memcpy(ptr_isrlock->name, (0 == osal_strlen(ptr_isrlock_name))? + dft_name : ptr_isrlock_name, OSAL_SPIN_NAME_LEN); + ptr_isrlock->name[OSAL_SPIN_NAME_LEN] = '\0'; + + /* init */ + spin_lock_init(&ptr_isrlock->spinlock); + + *ptr_isrlock_id = (CLX_ISRLOCK_ID_T)ptr_isrlock; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_takeIsrLock( + CLX_ISRLOCK_ID_T *ptr_isrlock_id, + CLX_IRQ_FLAGS_T *ptr_irq_flags) +{ + linux_isrlock_t *ptr_isrlock = (linux_isrlock_t *)(*ptr_isrlock_id); + unsigned long flags = 0; + + spin_lock_irqsave(&ptr_isrlock->spinlock, flags); + *ptr_irq_flags = (CLX_IRQ_FLAGS_T)flags; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_giveIsrLock( + CLX_ISRLOCK_ID_T *ptr_isrlock_id, + CLX_IRQ_FLAGS_T *ptr_irq_flags) +{ + linux_isrlock_t *ptr_isrlock = (linux_isrlock_t *)(*ptr_isrlock_id); + unsigned long flags = 0; + + flags = (unsigned long)(*ptr_irq_flags); + spin_unlock_irqrestore(&ptr_isrlock->spinlock, flags); + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_destroyIsrLock( + CLX_ISRLOCK_ID_T *ptr_isrlock_id) +{ + linux_isrlock_t *ptr_isrlock = (linux_isrlock_t *)(*ptr_isrlock_id); + + osal_free(ptr_isrlock); + *ptr_isrlock_id = 0; + + return (CLX_E_OK); +} + +/* time */ +CLX_ERROR_NO_T +osal_sleepThread( + const UI32_T usecond) +{ + UI32_T tick_usec; /* how many usec per second */ + UI32_T jiffies; + + if (0 != usecond) + { + /* HZ : times/sec, tick = 1/HZ */ + tick_usec = OSAL_TICKS_PER_SEC / HZ; + if (in_interrupt() || (usecond < tick_usec)) + { + return (-1); + } + else + { + DECLARE_WAIT_QUEUE_HEAD(suspend_queue); + + if (usecond > 0xFFFFFFFF - (tick_usec - 1)) + { + jiffies = 0xFFFFFFFF / tick_usec; + } + else + { + jiffies = (usecond + (tick_usec - 1)) / tick_usec; + } + + return wait_event_interruptible_timeout(suspend_queue, 0, jiffies); + } + } + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_getTime( + CLX_TIME_T *ptr_time) +{ + struct timespec64 usec_time; + + ktime_get_real_ts64(&usec_time); + *(CLX_TIME_T *)ptr_time = (usec_time.tv_sec * OSAL_US_PER_SECOND) + usec_time.tv_nsec; + + return (CLX_E_OK); +} + +/* queue */ +CLX_ERROR_NO_T +osal_que_create( + CLX_HUGE_T *ptr_queue_id, + UI32_T capacity) +{ + linux_queue_t *ptr_queue = osal_alloc(sizeof(linux_queue_t)); + + ptr_queue->head = 0; + ptr_queue->tail = 0; + ptr_queue->wr_cnt = 0; + ptr_queue->rd_cnt = 0; + ptr_queue->capacity = capacity; + ptr_queue->ptr_entry = osal_alloc(sizeof(linux_queue_entry_t) * capacity); + memset(ptr_queue->ptr_entry, 0x0, sizeof(linux_queue_entry_t) * capacity); + + *ptr_queue_id = (CLX_HUGE_T)ptr_queue; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_que_enque( + CLX_HUGE_T *ptr_queue_id, + void *ptr_data) +{ + linux_queue_t *ptr_queue = (linux_queue_t *)(*ptr_queue_id); + + if (ptr_queue->wr_cnt - ptr_queue->rd_cnt >= ptr_queue->capacity) + { + return (CLX_E_OTHERS); + } + + /* save data to the tail */ + ptr_queue->ptr_entry[ptr_queue->tail].ptr_data = ptr_data; + + /* calculate tail and wr_cnt */ + ptr_queue->tail++; + if (ptr_queue->tail >= ptr_queue->capacity) + { + ptr_queue->tail = 0; + } + + ptr_queue->wr_cnt++; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_que_deque( + CLX_HUGE_T *ptr_queue_id, + void **pptr_data) +{ + linux_queue_t *ptr_queue = (linux_queue_t *)(*ptr_queue_id); + + if (ptr_queue->wr_cnt == ptr_queue->rd_cnt) + { + return (CLX_E_OTHERS); + } + + /* get data from head */ + *pptr_data = ptr_queue->ptr_entry[ptr_queue->head].ptr_data; + ptr_queue->ptr_entry[ptr_queue->head].ptr_data = NULL; + + /* calculate head and rd_cnt */ + ptr_queue->head++; + if (ptr_queue->head >= ptr_queue->capacity) + { + ptr_queue->head = 0; + } + + ptr_queue->rd_cnt++; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_que_destroy( + CLX_HUGE_T *ptr_queue_id) +{ + linux_queue_t *ptr_queue = (linux_queue_t *)(*ptr_queue_id); + + osal_free(ptr_queue->ptr_entry); + osal_free(ptr_queue); + *ptr_queue_id = 0; + + return (CLX_E_OK); +} + +CLX_ERROR_NO_T +osal_que_getCount( + CLX_HUGE_T *ptr_queue_id, + unsigned int *ptr_count) +{ + linux_queue_t *ptr_queue = (linux_queue_t *)(*ptr_queue_id); + + *ptr_count = ptr_queue->wr_cnt - ptr_queue->rd_cnt; + + return (CLX_E_OK); +} + +/* IO */ +int +osal_io_copyToUser( + void *ptr_usr_buf, + void *ptr_knl_buf, + unsigned int size) +{ + return copy_to_user(ptr_usr_buf, ptr_knl_buf, size); +} + +int +osal_io_copyFromUser( + void *ptr_knl_buf, + void *ptr_usr_buf, + unsigned int size) +{ + return copy_from_user(ptr_knl_buf, ptr_usr_buf, size); +} + +/* dma */ +void * +osal_dma_alloc( + const UI32_T size) +{ + struct device *ptr_dev = &_ptr_ext_pci_dev->dev; + linux_dma_t *ptr_dma_node = NULL; + dma_addr_t phy_addr = 0x0; + + ptr_dma_node = dma_alloc_coherent(ptr_dev, sizeof(linux_dma_t) + size, &phy_addr, GFP_ATOMIC); + ptr_dma_node->size = sizeof(linux_dma_t) + size; + ptr_dma_node->phy_addr = phy_addr; + + return (void *)ptr_dma_node->data; +} + +CLX_ERROR_NO_T +osal_dma_free( + void *ptr_dma_mem) +{ + struct device *ptr_dev = &_ptr_ext_pci_dev->dev; + linux_dma_t *ptr_dma_node = (linux_dma_t *)(ptr_dma_mem - sizeof(linux_dma_t)); + + dma_free_coherent(ptr_dev, ptr_dma_node->size, ptr_dma_node, ptr_dma_node->phy_addr); + + return (CLX_E_OK); +} + +dma_addr_t +osal_dma_convertVirtToPhy( + void *ptr_virt_addr) +{ + return virt_to_phys(ptr_virt_addr); +} + +void * +osal_dma_convertPhyToVirt( + const dma_addr_t phy_addr) +{ + return phys_to_virt(phy_addr); +} + +int +osal_dma_flushCache( + void *ptr_virt_addr, + const unsigned int size) +{ +#if defined(CONFIG_NOT_COHERENT_CACHE) || defined(CONFIG_DMA_NONCOHERENT) +#if defined(dma_cache_wback_inv) + dma_cache_wback_inv((CLX_HUGE_T)ptr_virt_addr, size); +#else + dma_cache_sync(NULL, ptr_virt_addr, size, DMA_TO_DEVICE); +#endif +#endif + return (0); +} + +int +osal_dma_invalidateCache( + void *ptr_virt_addr, + const unsigned int size) +{ +#if defined(CONFIG_NOT_COHERENT_CACHE) || defined(CONFIG_DMA_NONCOHERENT) +#if defined(dma_cache_wback_inv) + dma_cache_wback_inv((CLX_HUGE_T)ptr_virt_addr, size); +#else + dma_cache_sync(NULL, ptr_virt_addr, size, DMA_FROM_DEVICE); +#endif +#endif + return (0); +} + +/* skb */ +struct sk_buff * +osal_skb_alloc( + UI32_T size) +{ + struct sk_buff *ptr_skb = NULL; + + /* + * 1. alloc_skb (len, flag) : GFP_KERNEL + * 2. netdev_alloc_skb (dev, len) : GFP_ATOMIC + * 3. dev_alloc_skb (len) : GFP_ATOMIC + * 4. netdev_alloc_skb_ip_align (dev, len) : GFP_ATOMIC + * + * note: Eth header is 14-bytes, we reservd 2-bytes to alignment Ip header + */ + ptr_skb = dev_alloc_skb(size + NET_IP_ALIGN); + skb_reserve(ptr_skb, NET_IP_ALIGN); + skb_put(ptr_skb, size); + + return (ptr_skb); +} + +void +osal_skb_free( + struct sk_buff *ptr_skb) +{ + /* + * 1. dev_kfree_skb (*skb) : release in process context + * 2. dev_kfree_skb_irq (*skb) : release in interrupt context + * 3. dev_kfree_skb_any (*skb) : release in any context + */ + dev_kfree_skb_any(ptr_skb); +} + +dma_addr_t +osal_skb_mapDma( + struct sk_buff *ptr_skb, + enum dma_data_direction dir) +{ + struct device *ptr_dev = &_ptr_ext_pci_dev->dev; + dma_addr_t phy_addr = 0x0; + + phy_addr = dma_map_single(ptr_dev, ptr_skb->data, ptr_skb->len, dir); + if (dma_mapping_error(ptr_dev, phy_addr)) + { + phy_addr = 0x0; + } + + return (phy_addr); +} + +void +osal_skb_unmapDma( + const dma_addr_t phy_addr, + UI32_T size, + enum dma_data_direction dir) +{ + struct device *ptr_dev = &_ptr_ext_pci_dev->dev; + + dma_unmap_single(ptr_dev, phy_addr, size, dir); +} + +void +osal_skb_send( + struct sk_buff *ptr_skb) +{ + dev_queue_xmit(ptr_skb); +} + +void +osal_skb_recv( + struct sk_buff *ptr_skb) +{ + /* 1. netif_rx() : handle skb in process context + * 2. netif_rx_ni() : handle skb in interrupt context + * 3. netif_receive_skb() : for NAPI + */ + netif_rx(ptr_skb); +} + diff --git a/platform/clounix/clounix-modules/modules/src/clx_netif/netif_perf.c b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_perf.c new file mode 100755 index 000000000000..8a24771b78fb --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/clx_netif/netif_perf.c @@ -0,0 +1,803 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_perf.c + * PURPOSE: + * It provide customer performance test API. + * NOTES: + */ +#include +#include + +#include +#include + +#include + +#if defined (CLX_EN_DAWN) +#include +#endif + +#if defined (CLX_EN_LIGHTNING) +#include +#endif + +/* -------------------------------------------------------------- switch */ +#define PERF_TX_CHANNEL_NUM_MAX (HAL_LIGHTNING_PKT_TX_CHANNEL_LAST) +#define PERF_RX_CHANNEL_NUM_MAX (HAL_LIGHTNING_PKT_RX_CHANNEL_LAST) + +#define NETIF_KNL_DEVICE_IS_LIGHTNING(__dev_id__) (HAL_DEVICE_ID_CL8500 == (__dev_id__ & 0xFF00)) +#define NETIF_KNL_DEVICE_IS_DAWN(__dev_id__) (HAL_DEVICE_ID_CL8300 == (__dev_id__ & 0xFF00)) + +static UI32_T perf_tx_channel_num = HAL_LIGHTNING_PKT_TX_CHANNEL_LAST; +static UI32_T perf_rx_channel_num = HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; + +extern struct pci_dev *_ptr_ext_pci_dev; +static UI16_T dev_id = 0; + +/* -------------------------------------------------------------- common */ +#define PERF_TX_PERF_NUM (1000000) /* max: 4294967 */ +#define PERF_TX_PERF_MESG (50000) +#define PERF_TX_PERF_FAIL (10000) +#define PERF_RX_PERF_NUM (1000000) /* max: 4294967 */ +#define PERF_RX_PERF_MESG (50000) +#define PERF_RX_PERF_FAIL (10000) + +/* -------------------------------------------------------------- callbacks for chip dependency */ +/* Tx */ +typedef CLX_ERROR_NO_T +(*PERF_TX_GET_INTR_T)( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt); + +typedef CLX_ERROR_NO_T +(*PERF_TX_GET_NETDEV_T)( + const UI32_T unit, + const UI32_T port, + struct net_device **pptr_net_dev); + +typedef CLX_ERROR_NO_T +(*PERF_TX_PREPARE_GPD_T)( + const UI32_T unit, + const CLX_ADDR_T phy_addr, + const UI32_T len, + const UI32_T port, + void *ptr_sw_gpd); + +typedef CLX_ERROR_NO_T +(*PERF_TX_SEND_GPD_T)( + const UI32_T unit, + const UI32_T channel, + void *ptr_sw_gpd); + +/* Rx */ +typedef CLX_ERROR_NO_T +(*PERF_RX_GET_INTR_T)( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt); + +/* -------------------------------------------------------------- structs */ +typedef enum +{ + PERF_DIR_TX = 0, + PERF_DIR_RX, + PERF_DIR_LAST, + +} PERF_DIR_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; + UI32_T len; + UI32_T num; + UI32_T port; + BOOL_T test_skb; + +} PERF_COOKIE_T; + +typedef struct +{ + /* netif-only */ + PERF_COOKIE_T tx_cookie [PERF_TX_CHANNEL_NUM_MAX]; + + CLX_THREAD_ID_T tx_task [PERF_TX_CHANNEL_NUM_MAX]; + CLX_SEMAPHORE_ID_T start_sync [PERF_TX_CHANNEL_NUM_MAX]; + CLX_SEMAPHORE_ID_T end_sync [PERF_TX_CHANNEL_NUM_MAX]; + UI32_T send_ok [PERF_TX_CHANNEL_NUM_MAX]; + UI32_T send_fail [PERF_TX_CHANNEL_NUM_MAX]; + + /* chip dependent callbacks */ + PERF_TX_GET_INTR_T get_intr_cnt; + PERF_TX_GET_NETDEV_T get_netdev; + PERF_TX_PREPARE_GPD_T prepare_gpd; + PERF_TX_SEND_GPD_T send_gpd; + +} PERF_TX_PERF_CB_T; + +typedef struct +{ + /* netif-only */ + BOOL_T rx_test; + + CLX_SEMAPHORE_ID_T start_sync; + CLX_SEMAPHORE_ID_T end_sync; + UI32_T target_num; + UI32_T target_len; + UI32_T recv_pass; + UI32_T recv_fail; + + /* duplicate packets */ + UI32_T rch_qid_map_lo [PERF_RX_CHANNEL_NUM_MAX]; + UI32_T rch_qid_map_hi [PERF_RX_CHANNEL_NUM_MAX]; + + /* chip dependent callbacks */ + PERF_RX_GET_INTR_T get_intr_cnt; + +} PERF_RX_PERF_CB_T; + +CLX_ERROR_NO_T +hal_perf_pkt_getTxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt) +{ + CLX_ERROR_NO_T ret; + + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + ret = hal_dawn_pkt_getTxIntrCnt(unit,channel,ptr_intr_cnt); + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + ret = hal_lightning_pkt_getTxIntrCnt(unit,channel,ptr_intr_cnt); + } + else + { + osal_printf("unknown chip family, dev_id=0x%x\n",dev_id); + ret = CLX_E_OTHERS; + } + return ret; +} +CLX_ERROR_NO_T +hal_perf_pkt_getNetDev( + const UI32_T unit, + const UI32_T port, + struct net_device **pptr_net_dev) +{ + CLX_ERROR_NO_T ret; + + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + ret = hal_dawn_pkt_getNetDev(unit,port,pptr_net_dev); + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + ret = hal_lightning_pkt_getNetDev(unit,port,pptr_net_dev); + } + else + { + osal_printf("unknown chip family, dev_id=0x%x\n",dev_id); + ret = CLX_E_OTHERS; + } + return ret; +} +CLX_ERROR_NO_T +hal_perf_pkt_prepareGpd( + const UI32_T unit, + const CLX_ADDR_T phy_addr, + const UI32_T len, + const UI32_T port, + void *ptr_sw_gpd) +{ + CLX_ERROR_NO_T ret; + + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + ret = hal_dawn_pkt_prepareGpd(unit,phy_addr,len,port,(HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd); + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + ret = hal_lightning_pkt_prepareGpd(unit,phy_addr,len,port,(HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd); + } + else + { + osal_printf("unknown chip family, dev_id=0x%x\n",dev_id); + ret = CLX_E_OTHERS; + } + return ret; +} +CLX_ERROR_NO_T +hal_perf_pkt_sendGpd( + const UI32_T unit, + const UI32_T channel, + void *ptr_sw_gpd) +{ + CLX_ERROR_NO_T ret; + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + ret = hal_dawn_pkt_sendGpd(unit,channel,(HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd); + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + ret = hal_lightning_pkt_sendGpd(unit,channel,(HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd); + } + else + { + osal_printf("unknown chip family, dev_id=0x%x\n",dev_id); + ret = CLX_E_OTHERS; + } + return ret; +} +CLX_ERROR_NO_T +hal_perf_pkt_getRxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt) +{ + CLX_ERROR_NO_T ret; + + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + ret = hal_dawn_pkt_getRxIntrCnt(unit,channel,ptr_intr_cnt); + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + ret = hal_lightning_pkt_getRxIntrCnt(unit,channel,ptr_intr_cnt); + } + else + { + osal_printf("unknown chip family, dev_id=0x%x\n",dev_id); + ret = CLX_E_OTHERS; + } + return ret; +} + +/* -------------------------------------------------------------- statics */ +static PERF_TX_PERF_CB_T _perf_tx_perf_cb = +{ + .get_intr_cnt = hal_perf_pkt_getTxIntrCnt, + .get_netdev = hal_perf_pkt_getNetDev, /* test_skb = TRUE */ + .prepare_gpd = hal_perf_pkt_prepareGpd, /* test_skb = FALSE */ + .send_gpd = hal_perf_pkt_sendGpd, /* test_skb = FALSE */ +}; + +static PERF_RX_PERF_CB_T _perf_rx_perf_cb = +{ + .get_intr_cnt = hal_perf_pkt_getRxIntrCnt, +}; + +/* -------------------------------------------------------------- functions */ +static void +_perf_duplicateRxPacket( + const UI32_T unit, + const UI32_T rx_channel, + const BOOL_T enable) +{ + ; +} + +static void +_perf_showPerf( + PERF_DIR_T dir, + UI32_T channel, + UI32_T len, + UI32_T num, + UI32_T intr, + UI32_T duration) +{ + UI32_T tx_channel = 0; + UI32_T tx_fail = 0; + + if (duration < 1000) + { + osal_printf("***Error***, %d packets cost < 1000 us.\n", num); + return ; + } + + osal_printf("\n"); + + if (PERF_DIR_TX == dir) + { + osal_printf("Tx-perf\n"); + } + else + { + osal_printf("Rx-perf\n"); + } + + osal_printf("------------------------------------\n"); + osal_printf("channel number : %d\n", channel); + osal_printf("packet length (bytes): %d\n", len); + osal_printf("packet number : %d\n", num); + osal_printf("time duration (us) : %d\n", duration); + osal_printf("------------------------------------\n"); + osal_printf("avg. packet rate (pps) : %d\n", (num * 1000) / (duration / 1000)); + osal_printf("avg. throughput (Mbps) : %d\n", ((num / 1000) * len * 8) / (duration / 1000)); + osal_printf("interrupt number : %d\n", intr); + + if (PERF_DIR_TX == dir) + { + for (tx_channel = 0; tx_channel < channel; tx_channel++) + { + tx_fail += _perf_tx_perf_cb.send_fail[tx_channel]; + } + osal_printf("Tx fail : %d\n", tx_fail); + } + + osal_printf("------------------------------------\n"); +} + +static void +_perf_getIntrCnt( + UI32_T unit, + PERF_DIR_T dir, + UI32_T *ptr_intr_cnt) +{ + UI32_T intr_cnt = 0; + UI32_T channel = 0; + + if (PERF_DIR_TX == dir) + { + for (channel = 0; channel < perf_tx_channel_num; channel++) + { + _perf_tx_perf_cb.get_intr_cnt(unit, channel, &intr_cnt); + *ptr_intr_cnt += intr_cnt; + } + } + else + { + for (channel = 0; channel < perf_rx_channel_num; channel++) + { + _perf_rx_perf_cb.get_intr_cnt(unit, channel, &intr_cnt); + *ptr_intr_cnt += intr_cnt; + } + } +} + +static void +_perf_txCallback( + const UI32_T unit, + void *ptr_sw_gpd, + void *ptr_virt_addr) +{ + /* free dma */ + osal_dma_free(ptr_virt_addr); + + /* free gpd */ + osal_free(ptr_sw_gpd); +} + +static void +_perf_txTask( + void *ptr_argv) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + UI32_T unit = ((PERF_COOKIE_T *)ptr_argv)->unit; + UI32_T channel = ((PERF_COOKIE_T *)ptr_argv)->channel; + UI32_T len = ((PERF_COOKIE_T *)ptr_argv)->len; + UI32_T num = ((PERF_COOKIE_T *)ptr_argv)->num; + UI32_T port = ((PERF_COOKIE_T *)ptr_argv)->port; + BOOL_T test_skb = ((PERF_COOKIE_T *)ptr_argv)->test_skb; + + /* test targets */ + void *ptr_sw_gpd = NULL; + struct sk_buff *ptr_skb = NULL; + + /* temp variables */ + UI32_T send_fail = 0; + void *ptr_virt_addr = NULL; + CLX_ADDR_T phy_addr = 0x0; + + osal_initRunThread(); + do + { + rc = osal_waitEvent(&_perf_tx_perf_cb.start_sync[channel]); + if (CLX_E_OK != osal_isRunThread()) + { + break; /* deinit-thread */ + } + + while (_perf_tx_perf_cb.send_ok[channel] < num) + { + if (0 == (_perf_tx_perf_cb.send_ok[channel] % PERF_TX_PERF_MESG)) + { + printk("T"); + } + + if (TRUE == test_skb) + { + ptr_skb = osal_skb_alloc(len); + ptr_skb->len = len; + _perf_tx_perf_cb.get_netdev(unit, port, &ptr_skb->dev); + + /* send skb */ + osal_skb_send(ptr_skb); + } + else + { + /* prepare buf */ + ptr_virt_addr = osal_dma_alloc(len); + phy_addr = osal_dma_convertVirtToPhy(ptr_virt_addr); + + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + ptr_sw_gpd = (HAL_DAWN_PKT_TX_SW_GPD_T*)osal_alloc(sizeof(HAL_DAWN_PKT_TX_SW_GPD_T)); + if (NULL == ptr_sw_gpd) + { + osal_printf("***Error***, alloc sw-gpd fail.\n"); + break; + } + osal_memset(ptr_sw_gpd, 0x0, sizeof(HAL_DAWN_PKT_TX_SW_GPD_T)); + + /* trans skb to gpd */ + ((HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->callback = (void *)_perf_txCallback; + ((HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->ptr_cookie = (void *)ptr_virt_addr; + ((HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->gpd_num = 1; + ((HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->ptr_next = NULL; + ((HAL_DAWN_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->channel = channel; + + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + ptr_sw_gpd = (void*)osal_alloc(sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T)); + if (NULL == ptr_sw_gpd) + { + osal_printf("***Error***, alloc sw-gpd fail.\n"); + break; + } + osal_memset(ptr_sw_gpd, 0x0, sizeof(HAL_LIGHTNING_PKT_TX_SW_GPD_T)); + + /* trans skb to gpd */ + ((HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->callback = (void *)_perf_txCallback; + ((HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->ptr_cookie = (void *)ptr_virt_addr; + ((HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->gpd_num = 1; + ((HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->ptr_next = NULL; + ((HAL_LIGHTNING_PKT_TX_SW_GPD_T*)ptr_sw_gpd)->channel = channel; + } + + /* prepare gpd */ + rc = _perf_tx_perf_cb.prepare_gpd(unit, phy_addr, len, port, ptr_sw_gpd); + + /* send gpd */ + rc = _perf_tx_perf_cb.send_gpd(unit, channel, ptr_sw_gpd); + if (CLX_E_OK == rc) + { + _perf_tx_perf_cb.send_ok[channel]++; + send_fail = 0; + } + else + { + _perf_tx_perf_cb.send_fail[channel]++; + if (send_fail++ >= PERF_TX_PERF_FAIL) + { + osal_printf("***Error***, Tch-%d send fail over %d packet(s). (rc: %d)\n", + channel, PERF_TX_PERF_FAIL, rc); + break; + } + + _perf_txCallback(unit, ptr_sw_gpd, ptr_virt_addr); + osal_sleepThread(1000); + } + } + } + + osal_triggerEvent(&_perf_tx_perf_cb.end_sync[channel]); + } + while (CLX_E_OK == osal_isRunThread()); + osal_exitRunThread(); +} + +static void +_perf_txDeinit( + const UI32_T unit, + const UI32_T tx_channel) +{ + UI32_T channel = 0; + + for (channel = 0; channel < tx_channel; channel++) + { + /* destroy Tx resources */ + osal_stopThread (&_perf_tx_perf_cb.tx_task [channel]); + osal_triggerEvent(&_perf_tx_perf_cb.start_sync [channel]); + osal_destroyThread(&_perf_tx_perf_cb.tx_task [channel]); + osal_destroyEvent(&_perf_tx_perf_cb.end_sync [channel]); + osal_destroyEvent(&_perf_tx_perf_cb.start_sync [channel]); + } +} + +static void +_perf_txInit( + const UI32_T unit, + const UI32_T tx_channel, + const UI32_T len, + BOOL_T test_skb) +{ + UI32_T channel = 0; + + for (channel = 0; channel < tx_channel; channel++) + { + _perf_tx_perf_cb.send_ok [channel] = 0; + _perf_tx_perf_cb.send_fail[channel] = 0; + + /* create Tx resources */ + osal_createEvent("TX_START", &_perf_tx_perf_cb.start_sync [channel]); + osal_createEvent("TX_END", &_perf_tx_perf_cb.end_sync [channel]); + + _perf_tx_perf_cb.tx_cookie[channel].unit = unit; + _perf_tx_perf_cb.tx_cookie[channel].channel = channel; + _perf_tx_perf_cb.tx_cookie[channel].len = len; + _perf_tx_perf_cb.tx_cookie[channel].num = PERF_TX_PERF_NUM / tx_channel; + _perf_tx_perf_cb.tx_cookie[channel].port = 0; + _perf_tx_perf_cb.tx_cookie[channel].test_skb = test_skb; + + osal_createThread( + "TX_PERF", 64 * 1024, 90, + _perf_txTask, + (void *)&_perf_tx_perf_cb.tx_cookie[channel], + &_perf_tx_perf_cb.tx_task[channel]); + } +} + +static void +_perf_rxDeinit( + const UI32_T unit, + const UI32_T rx_channel) +{ + /* turn-off Rx test */ + _perf_rx_perf_cb.rx_test = FALSE; + + /* destroy Rx resources */ + osal_destroyEvent(&_perf_rx_perf_cb.end_sync); + osal_destroyEvent(&_perf_rx_perf_cb.start_sync); + + /* disable duplicate Rx packets to channels */ + _perf_duplicateRxPacket(unit, rx_channel, FALSE); +} + +static void +_perf_rxInit( + const UI32_T unit, + const UI32_T rx_channel, + const UI32_T len) +{ + /* enable duplicate Rx packets to channels */ + _perf_duplicateRxPacket(unit, rx_channel, TRUE); + + /* create Rx callback resources */ + _perf_rx_perf_cb.target_num = PERF_RX_PERF_NUM; + _perf_rx_perf_cb.target_len = len; + _perf_rx_perf_cb.recv_pass = 0; + + osal_createEvent("RX_START", &_perf_rx_perf_cb.start_sync); + osal_createEvent("RX_END", &_perf_rx_perf_cb.end_sync); + + /* turn-on Rx test */ + _perf_rx_perf_cb.rx_test = TRUE; +} + +/* FUNCTION NAME: perf_rxCallback + * PURPOSE: + * To count the Rx-gpd for Rx-test. + * INPUT: + * len -- To check if the Rx-gpd length equals to test length. + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successful operation. + * NOTES: + * None + */ +CLX_ERROR_NO_T +perf_rxCallback( + const UI32_T len) +{ + /* check length */ + if (len == _perf_rx_perf_cb.target_len) + { + _perf_rx_perf_cb.recv_pass++; + } + else + { + if (_perf_rx_perf_cb.recv_fail++ >= PERF_RX_PERF_FAIL) + { + _perf_rx_perf_cb.recv_fail = 0; + } + } + + /* send signals */ + if (0 == _perf_rx_perf_cb.recv_pass) + { + ; /* do nothing */ + } + else if (1 == _perf_rx_perf_cb.recv_pass) + { + osal_triggerEvent(&_perf_rx_perf_cb.start_sync); + } + else if (_perf_rx_perf_cb.recv_pass == _perf_rx_perf_cb.target_num) + { + osal_triggerEvent(&_perf_rx_perf_cb.end_sync); + } + else if (0 == (_perf_rx_perf_cb.recv_pass % PERF_RX_PERF_MESG)) + { + printk("R"); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: perf_rxTest + * PURPOSE: + * To check if Rx-test is going. + * INPUT: + * None + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successful operation. + * NOTES: + * None + */ +CLX_ERROR_NO_T +perf_rxTest(void) +{ + if (FALSE == _perf_rx_perf_cb.rx_test) + { + return (CLX_E_OTHERS); + } + + return (CLX_E_OK); +} + +/* FUNCTION NAME: perf_test + * PURPOSE: + * To do Tx-test or Rx-test. + * INPUT: + * len -- Test length + * tx_channel -- Test Tx channel numbers + * rx_channel -- Test Rx channel numbers + * test_skb -- Test GPD or SKB + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successful operation. + * NOTES: + * None + */ +CLX_ERROR_NO_T +perf_test( + UI32_T len, + UI32_T tx_channel, + UI32_T rx_channel, + BOOL_T test_skb) +{ + CLX_ERROR_NO_T rc = CLX_E_OK; + CLX_TIME_T start_time; + CLX_TIME_T end_time; + UI32_T unit = 0, channel = 0; + UI32_T tx_pkt_cnt = 0, tx_start_intr = 0, tx_end_intr = 0; + UI32_T rx_pkt_cnt = 0, rx_start_intr = 0, rx_end_intr = 0; + + if ((0 == tx_channel) && (0 == rx_channel)) + { + return (CLX_E_NOT_SUPPORT); + } + + pci_read_config_word(_ptr_ext_pci_dev, PCI_DEVICE_ID, &dev_id); + if (NETIF_KNL_DEVICE_IS_DAWN(dev_id)) + { + perf_tx_channel_num = HAL_DAWN_PKT_TX_CHANNEL_LAST; + perf_rx_channel_num = HAL_DAWN_PKT_RX_CHANNEL_LAST; + } + else if (NETIF_KNL_DEVICE_IS_LIGHTNING(dev_id)) + { + perf_tx_channel_num = HAL_LIGHTNING_PKT_TX_CHANNEL_LAST; + perf_rx_channel_num = HAL_LIGHTNING_PKT_RX_CHANNEL_LAST; + } + else + { + osal_printf("unknown chip family, dev_id=0x%x\n",dev_id); + return CLX_E_OTHERS; + } + + /* start test */ + if ((tx_channel > 0) && (rx_channel > 0)) + { + _perf_getIntrCnt(unit, PERF_DIR_TX, &tx_start_intr); + _perf_getIntrCnt(unit, PERF_DIR_RX, &rx_start_intr); + _perf_txInit(unit, tx_channel, len, test_skb); + _perf_rxInit(unit, rx_channel, len); + + /* wait 1st Rx GPD done */ + osal_waitEvent(&_perf_rx_perf_cb.start_sync); + + /* ------------- in-time ------------- */ + osal_getTime(&start_time); + for (channel = 0; channel < tx_channel; channel++) + { + osal_triggerEvent(&_perf_tx_perf_cb.start_sync[channel]); + } + for (channel = 0; channel < tx_channel; channel++) + { + osal_waitEvent(&_perf_tx_perf_cb.end_sync[channel]); + tx_pkt_cnt += _perf_tx_perf_cb.send_ok[channel]; + } + rx_pkt_cnt = _perf_rx_perf_cb.recv_pass; + osal_getTime(&end_time); + /* ------------- in-time ------------- */ + + _perf_txDeinit(unit, tx_channel); + _perf_rxDeinit(unit, rx_channel); + _perf_getIntrCnt(unit, PERF_DIR_TX, &tx_end_intr); + _perf_getIntrCnt(unit, PERF_DIR_RX, &rx_end_intr); + + _perf_showPerf(PERF_DIR_TX, + tx_channel, len, tx_pkt_cnt, tx_end_intr - tx_start_intr, end_time - start_time); + + _perf_showPerf(PERF_DIR_RX, + rx_channel, len, rx_pkt_cnt, rx_end_intr - rx_start_intr, end_time - start_time); + } + else if (tx_channel > 0) + { + _perf_getIntrCnt(unit, PERF_DIR_TX, &tx_start_intr); + _perf_txInit(unit, tx_channel, len, test_skb); + + /* ------------- in-time ------------- */ + osal_getTime(&start_time); + for (channel = 0; channel < tx_channel; channel++) + { + osal_triggerEvent(&_perf_tx_perf_cb.start_sync[channel]); + } + for (channel = 0; channel < tx_channel; channel++) + { + osal_waitEvent(&_perf_tx_perf_cb.end_sync[channel]); + tx_pkt_cnt += _perf_tx_perf_cb.send_ok[channel]; + } + osal_getTime(&end_time); + /* ------------- in-time ------------- */ + + _perf_txDeinit(unit, tx_channel); + _perf_getIntrCnt(unit, PERF_DIR_TX, &tx_end_intr); + + _perf_showPerf(PERF_DIR_TX, + tx_channel, len, tx_pkt_cnt, tx_end_intr - tx_start_intr, end_time - start_time); + } + else if (rx_channel > 0) + { + _perf_getIntrCnt(unit, PERF_DIR_RX, &rx_start_intr); + _perf_rxInit(unit, rx_channel, len); + + /* wait 1st Rx GPD done */ + osal_waitEvent(&_perf_rx_perf_cb.start_sync); + + /* ------------- in-time ------------- */ + osal_getTime(&start_time); + osal_waitEvent(&_perf_rx_perf_cb.end_sync); + osal_getTime(&end_time); + /* ------------- in-time ------------- */ + + _perf_rxDeinit(unit, rx_channel); + _perf_getIntrCnt(unit, PERF_DIR_RX, &rx_end_intr); + + _perf_showPerf(PERF_DIR_RX, + rx_channel, len, PERF_RX_PERF_NUM, rx_end_intr - rx_start_intr, end_time - start_time); + } + + return (rc); +} + diff --git a/platform/clounix/clounix-modules/modules/src/inc/aml/aml.h b/platform/clounix/clounix-modules/modules/src/inc/aml/aml.h new file mode 100644 index 000000000000..14fca2b3a8fb --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/aml/aml.h @@ -0,0 +1,108 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: aml.h + * PURPOSE: + * 1. Provide whole AML resource initialization API. + * 2. Provide configuration access APIs. + * 3. Provide ISR registration and deregistration APIs. + * 4. Provide memory access. + * 5. Provide DMA management APIs. + * 6. Provide address translation APIs. + * NOTES: + */ + +#ifndef AML_H +#define AML_H + + +/* INCLUDE FILE DECLARATIONS + */ +#include +#include + + +/* NAMING CONSTANT DECLARATIONS + */ + +/* #define AML_EN_I2C */ +/* #define AML_EN_CUSTOM_DMA_ADDR */ + +/* MACRO FUNCTION DECLARATIONS + */ + +/* DATA TYPE DECLARATIONS + */ +typedef enum +{ + AML_DEV_TYPE_PCI, + AML_DEV_TYPE_I2C, + AML_DEV_TYPE_SPI, + AML_DEV_TYPE_LAST + +} AML_HW_IF_T; + +typedef CLX_ERROR_NO_T +(*AML_DEV_READ_FUNC_T)( + const UI32_T unit, + const UI32_T addr_offset, + UI32_T *ptr_data, + const UI32_T len); + +typedef CLX_ERROR_NO_T +(*AML_DEV_WRITE_FUNC_T)( + const UI32_T unit, + const UI32_T addr_offset, + const UI32_T *ptr_data, + const UI32_T len); + +typedef CLX_ERROR_NO_T +(*AML_DEV_ISR_FUNC_T)( + void *ptr_data); + +/* To mask the chip interrupt in kernel interrupt routine. */ +typedef struct +{ + UI32_T mask_addr; + UI32_T mask_val; + +} AML_DEV_ISR_DATA_T; + +/* To read or write the HW-intf registers. */ +typedef struct +{ + AML_DEV_READ_FUNC_T read_callback; + AML_DEV_WRITE_FUNC_T write_callback; + +} AML_DEV_ACCESS_T; + +typedef struct +{ + UI32_T vendor; + UI32_T device; + UI32_T revision; + +} AML_DEV_ID_T; + + +typedef struct +{ + AML_HW_IF_T if_type; + AML_DEV_ID_T id; + AML_DEV_ACCESS_T access; + +} AML_DEV_T; +#endif /* #ifndef AML_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/clx_error.h b/platform/clounix/clounix-modules/modules/src/inc/clx_error.h new file mode 100644 index 000000000000..21d505ce4d6c --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/clx_error.h @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: clx_error.h + * PURPOSE: + * Define the generic error code on CLX SDK. + * NOTES: + */ + +#ifndef CLX_ERROR_H +#define CLX_ERROR_H + +/* INCLUDE FILE DECLARATIONS + */ +#include + + +/* NAMING CONSTANT DECLARATIONS + */ + +/* MACRO FUNCTION DECLARATIONS + */ + +/* DATA TYPE DECLARATIONS + */ + +typedef enum +{ + CLX_E_OK = 0, /* Ok and no error */ + CLX_E_BAD_PARAMETER, /* Parameter is wrong */ + CLX_E_NO_MEMORY, /* No memory is available */ + CLX_E_TABLE_FULL, /* Table is full */ + CLX_E_ENTRY_NOT_FOUND, /* Entry is not found */ + CLX_E_ENTRY_EXISTS, /* Entry already exists */ + CLX_E_NOT_SUPPORT, /* Feature is not supported */ + CLX_E_ALREADY_INITED, /* Module is reinitialized */ + CLX_E_NOT_INITED, /* Module is not initialized */ + CLX_E_OTHERS, /* Other errors */ + CLX_E_ENTRY_IN_USE, /* Entry is in use */ + CLX_E_TIMEOUT, /* Time out error */ + CLX_E_OP_INVALID, /* Operation is invalid */ + CLX_E_OP_STOPPED, /* Operation is stopped by user callback */ + CLX_E_OP_INCOMPLETE, /* Operation is incomplete */ + CLX_E_LAST +} CLX_ERROR_NO_T; + +/* EXPORTED SUBPROGRAM SPECIFICATIONS + */ +/* FUNCTION NAME: clx_error_getString + * PURPOSE: + * To obtain the error string of the specified error code + * + * INPUT: + * cause -- The specified error code + * OUTPUT: + * None + * RETURN: + * Pointer to the target error string + * + * NOTES: + * + * + */ +C8_T * +clx_error_getString( + const CLX_ERROR_NO_T cause ); + +#endif /* CLX_ERROR_H */ + diff --git a/platform/clounix/clounix-modules/modules/src/inc/clx_types.h b/platform/clounix/clounix-modules/modules/src/inc/clx_types.h new file mode 100644 index 000000000000..a0d483bb3a68 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/clx_types.h @@ -0,0 +1,329 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: clx_types.h + * PURPOSE: + * Define the commom data type in CLX SDK. + * NOTES: + */ + +#ifndef CLX_TYPES_H +#define CLX_TYPES_H + +/* INCLUDE FILE DECLARATIONS + */ + +#include + +/* NAMING CONSTANT DECLARATIONS + */ + +#define CLX_BIT_OFF 0 +#define CLX_BIT_ON 1 + +#define CLX_INVALID_ID (0xFFFFFFFF) +#define CLX_PORT_INVALID (CLX_INVALID_ID) +#define CLX_SEG_INVALID (CLX_INVALID_ID) + +/* for CPU Rx packet, indicate that the packet + * is not received from remote switch + */ +#define CLX_PATH_INVALID (CLX_INVALID_ID) + +#define CLX_SEMAPHORE_BINARY (1) +#define CLX_SEMAPHORE_SYNC (0) +#define CLX_SEMAPHORE_WAIT_FOREVER (0xFFFFFFFF) + +/* MACRO FUNCTION DECLARATIONS + */ +#if defined(CLX_EN_HOST_32_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_32_BIT_LITTLE_ENDIAN) +typedef unsigned int CLX_HUGE_T; +#elif defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) +typedef unsigned long long int CLX_HUGE_T; +#else +#error "The 32bit and 64bit compatible data type are not defined !!" +#endif + +#if defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) || defined(CLX_EN_64BIT_ADDR) +typedef unsigned long long int CLX_ADDR_T; +#else +typedef unsigned int CLX_ADDR_T; +#endif + +#if defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) || defined(CLX_EN_64BIT_ADDR) +#define CLX_ADDR_PRINT "0x%llx" +#else +#define CLX_ADDR_PRINT "0x%x" +#endif + +#if defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) || defined(CLX_EN_64BIT_ADDR) +#define CLX_ADDR_64_HI(__addr__) ((UI32_T)((__addr__) >> 32)) +#define CLX_ADDR_64_LOW(__addr__) ((UI32_T)((__addr__) & 0xFFFFFFFF)) +#define CLX_ADDR_32_TO_64(__hi32__,__low32__) (((unsigned long long int)(__low32__)) | \ + (((unsigned long long int)(__hi32__)) << 32)) +#else +#define CLX_ADDR_64_HI(__addr__) (0) +#define CLX_ADDR_64_LOW(__addr__) (__addr__) +#define CLX_ADDR_32_TO_64(__hi32__,__low32__) (__low32__) +#endif + +#define CLX_BITMAP_SIZE(bit_num) ((((bit_num) - 1) / 32) + 1) +#define CLX_IPV4_IS_MULTICAST(addr) (0xE0000000 == ((addr) & 0xF0000000)) +#define CLX_IPV6_IS_MULTICAST(addr) (0xFF == (((UI8_T *)(addr))[0])) +#define CLX_MAC_IS_MULTICAST(mac) ((mac[0]) & (0x1)) + +/* DATA TYPE DECLARATIONS + */ +typedef UI8_T CLX_BIT_MASK_8_T; +typedef UI16_T CLX_BIT_MASK_16_T; +typedef UI32_T CLX_BIT_MASK_32_T; +typedef UI64_T CLX_BIT_MASK_64_T; + +typedef UI8_T CLX_MAC_T[6]; +typedef UI32_T CLX_IPV4_T; +typedef UI8_T CLX_IPV6_T[16]; + +typedef UI32_T CLX_TIME_T; + +/* Bridge Domain id data type. */ +typedef UI32_T CLX_BRIDGE_DOMAIN_T; + +/* TRILL nickname type. */ +typedef UI16_T CLX_TRILL_NICKNAME_T; + +typedef union CLX_IP_U +{ + + CLX_IPV4_T ipv4_addr; + CLX_IPV6_T ipv6_addr; + +}CLX_IP_T; + +typedef struct CLX_IP_ADDR_S +{ + CLX_IP_T ip_addr; + CLX_IP_T ip_mask; + BOOL_T ipv4 ; +}CLX_IP_ADDR_T; + +/* Tunnel type*/ +typedef enum +{ + CLX_TUNNEL_TYPE_IPV4INIPV4 = 0, /* RFC2003, IPv4-in-IPv4 tunnel */ + CLX_TUNNEL_TYPE_IPV4INIPV6, /* RFC2003, IPv4-in-IPv6 tunnel */ + CLX_TUNNEL_TYPE_IPV6INIPV4, /* RFC2003, IPv6-in-IPv4 tunnel */ + CLX_TUNNEL_TYPE_IPV6INIPV6, /* RFC2003, IPv6-in-IPv6 tunnel */ + CLX_TUNNEL_TYPE_GREIPV4INIPV4, /* RFC2784/RFC2890,GRE IPv4-in-IPv4 tunnel */ + CLX_TUNNEL_TYPE_GREIPV6INIPV4, /* RFC2784/RFC2890,GRE IPv6-in-IPv4 tunnel */ + CLX_TUNNEL_TYPE_GREIPV4INIPV6, /* RFC2784/RFC2890,GRE IPv4-in-IPv6 tunnel */ + CLX_TUNNEL_TYPE_GREIPV6INIPV6, /* RFC2784/RFC2890,GRE IPv6-in-IPv6 tunnel */ + CLX_TUNNEL_TYPE_GRE_NSH, + CLX_TUNNEL_TYPE_6TO4, /* RFC3056, 6to4 tunnel*/ + CLX_TUNNEL_TYPE_ISATAP, /* RFC5214, ISATAP tunnel */ + CLX_TUNNEL_TYPE_NVGRE_L2, + CLX_TUNNEL_TYPE_NVGRE_V4, + CLX_TUNNEL_TYPE_NVGRE_V6, + CLX_TUNNEL_TYPE_NVGRE_NSH, + CLX_TUNNEL_TYPE_VXLAN, + CLX_TUNNEL_TYPE_GTP_V4, + CLX_TUNNEL_TYPE_GTP_V6, + CLX_TUNNEL_TYPE_MPLSINGRE, + CLX_TUNNEL_TYPE_VXLANGPE_L2, + CLX_TUNNEL_TYPE_VXLANGPE_V4, + CLX_TUNNEL_TYPE_VXLANGPE_V6, + CLX_TUNNEL_TYPE_VXLANGPE_NSH, + CLX_TUNNEL_TYPE_FLEX0_L2, + CLX_TUNNEL_TYPE_FLEX0_V4, + CLX_TUNNEL_TYPE_FLEX0_V6, + CLX_TUNNEL_TYPE_FLEX0_NSH, + CLX_TUNNEL_TYPE_FLEX1_L2, + CLX_TUNNEL_TYPE_FLEX1_V4, + CLX_TUNNEL_TYPE_FLEX1_V6, + CLX_TUNNEL_TYPE_FLEX1_NSH, + CLX_TUNNEL_TYPE_FLEX2_L2, + CLX_TUNNEL_TYPE_FLEX2_V4, + CLX_TUNNEL_TYPE_FLEX2_V6, + CLX_TUNNEL_TYPE_FLEX2_NSH, + CLX_TUNNEL_TYPE_FLEX3_L2, + CLX_TUNNEL_TYPE_FLEX3_V4, + CLX_TUNNEL_TYPE_FLEX3_V6, + CLX_TUNNEL_TYPE_FLEX3_NSH, + CLX_TUNNEL_TYPE_LAST +} CLX_TUNNEL_TYPE_T; + +/* tunnel key */ +typedef struct CLX_TUNNEL_KEY_S +{ + CLX_IP_ADDR_T src_ip; /* key: The outer source IP address used by tunnel encapsulation.*/ + CLX_IP_ADDR_T dst_ip; /* key: The outer destination IP address used by tunnel encapsulation. + * For automatic tunnel, this is not required. If not specified, + * its ip address value must be set to 0, but the IP version + * must be same with src_ip. + */ + CLX_TUNNEL_TYPE_T tunnel_type; /*key: The tunnel type.*/ +}CLX_TUNNEL_KEY_T; + +typedef UI16_T CLX_VLAN_T; +typedef UI32_T CLX_PORT_T; + +typedef enum{ + CLX_PORT_TYPE_NORMAL = 0, + CLX_PORT_TYPE_UNIT_PORT, + CLX_PORT_TYPE_LAG, + CLX_PORT_TYPE_VM_ETAG, + CLX_PORT_TYPE_VM_VNTAG, + CLX_PORT_TYPE_VM_VEPA, + CLX_PORT_TYPE_FCOE, + CLX_PORT_TYPE_IP_TUNNEL, + CLX_PORT_TYPE_TRILL, + CLX_PORT_TYPE_MPLS, + CLX_PORT_TYPE_MPLS_PW, + CLX_PORT_TYPE_CPU_PORT, + CLX_PORT_TYPE_SFC, + CLX_PORT_TYPE_LAST +}CLX_PORT_TYPE_T; + +/*support Green/Yellow/Red color*/ +typedef enum +{ + CLX_COLOR_GREEN = 0, + CLX_COLOR_YELLOW, + CLX_COLOR_RED, + CLX_COLOR_LAST +}CLX_COLOR_T; +typedef enum +{ + CLX_FWD_ACTION_FLOOD = 0, + CLX_FWD_ACTION_NORMAL, + CLX_FWD_ACTION_DROP, + CLX_FWD_ACTION_COPY_TO_CPU, + CLX_FWD_ACTION_REDIRECT_TO_CPU, + CLX_FWD_ACTION_FLOOD_COPY_TO_CPU, + CLX_FWD_ACTION_DROP_COPY_TO_CPU, + CLX_FWD_ACTION_LAST +} CLX_FWD_ACTION_T; + +typedef CLX_HUGE_T CLX_THREAD_ID_T; +typedef CLX_HUGE_T CLX_SEMAPHORE_ID_T; +typedef CLX_HUGE_T CLX_ISRLOCK_ID_T; +typedef CLX_HUGE_T CLX_IRQ_FLAGS_T; + +typedef enum +{ + CLX_DIR_INGRESS = 0, + CLX_DIR_EGRESS, + CLX_DIR_BOTH, + CLX_DIR_LAST +}CLX_DIR_T; + +typedef enum +{ + CLX_VLAN_ACTION_SET, + CLX_VLAN_ACTION_KEEP, + CLX_VLAN_ACTION_REMOVE, + CLX_VLAN_ACTION_LAST +} CLX_VLAN_ACTION_T; + +/* VLAN Precedence */ +/* 000 = SUBNET_PROTOCOL_MAC_PORT + * 001 = SUBNET_MAC_PROTOCOL_PORT + * 010 = PROTOCOL_SUBNET_MAC_PORT + * 011 = PROTOCOL_MAC_SUBNET_PORT + * 100 = MAC_SUBNET_PROTOCOL_PORT + * 101 = MAC_PROTOCOL_SUBNET_PORT + */ +typedef enum +{ + CLX_VLAN_PRECEDENCE_SUBNET_MAC_PROTOCOL_PORT = 1, + CLX_VLAN_PRECEDENCE_MAC_SUBNET_PROTOCOL_PORT = 4, + CLX_VLAN_PRECEDENCE_PORT_ONLY = 7, + CLX_VLAN_PRECEDENCE_FAVOR_TYPE = 8, + CLX_VLAN_PRECEDENCE_FAVOR_ADDR = 9, + CLX_VLAN_PRECEDENCE_LAST +} CLX_VLAN_PRECEDENCE_T; + +/* VLAN Tag Type */ +typedef enum +{ + CLX_VLAN_TAG_NONE = 0, /* UnTag */ + CLX_VLAN_TAG_SINGLE_PRI, /* Single Customer/Service Priority Tag */ + CLX_VLAN_TAG_SINGLE, /* Single Customer/Service Tag */ + CLX_VLAN_TAG_DOUBLE_PRI, /* Double Tag with any VID=0 */ + CLX_VLAN_TAG_DOUBLE, /* Double Tag */ + CLX_VLAN_TAG_LAST +} CLX_VLAN_TAG_T; + +typedef struct CLX_BUM_INFO_S +{ + UI32_T mcast_id; + UI32_T group_label; /* l2 da group label */ + UI32_T vid; /* used when FLAGS_ADD_VID is set */ + +#define CLX_BUM_INFO_FLAGS_MCAST_VALID (1U << 0) +#define CLX_BUM_INFO_FLAGS_TO_CPU (1U << 1) +#define CLX_BUM_INFO_FLAGS_ADD_VID (1U << 2) /* single tag to double tag (i.e) QinQ */ +#define CLX_BUM_INFO_FLAGS_TRILL_ALL_TREE (1U << 3) + UI32_T flags; +} CLX_BUM_INFO_T; + +typedef enum +{ + CLX_PHY_TYPE_INTERNAL = 0x0, + CLX_PHY_TYPE_EXTERNAL, + CLX_PHY_TYPE_LAST +} CLX_PHY_TYPE_T; + +typedef enum +{ + CLX_PHY_DEVICE_ADDR_PMA_PMD = 1, + CLX_PHY_DEVICE_ADDR_WIS = 2, + CLX_PHY_DEVICE_ADDR_PCS = 3, + CLX_PHY_DEVICE_ADDR_PHY_XS = 4, + CLX_PHY_DEVICE_ADDR_DTE_XS = 5, + CLX_PHY_DEVICE_ADDR_TC = 6, + CLX_PHY_DEVICE_ADDR_AN = 7, + CLX_PHY_DEVICE_ADDR_VENDOR_1 = 30, + CLX_PHY_DEVICE_ADDR_VENDOR_2 = 31, + CLX_PHY_DEVICE_ADDR_LAST +} CLX_PHY_DEVICE_ADDR_T; + +typedef enum +{ + CLX_BULK_OP_MODE_ERR_STOP = 0, + CLX_BULK_OP_MODE_ERR_CONTINUE, + CLX_BULK_OP_MODE_LAST +} CLX_BULK_OP_MODE_T; + +typedef struct CLX_RANGE_INFO_S +{ + UI32_T min_id; + UI32_T max_id; + UI32_T max_member_cnt; + +#define CLX_RANGE_INFO_FLAGS_MAX_MEMBER_CNT (1U << 0) + UI32_T flags; +} CLX_RANGE_INFO_T; + +typedef struct CLX_FDL_INFO_S +{ + UI32_T probability /* percentage from 0~100 */; + UI32_T threshold; /* range 0 ~ (2^20)-1 */ +} CLX_FDL_INFO_T; + +/* EXPORTED SUBPROGRAM SPECIFICATIONS + */ + +#endif /* CLX_TYPES_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/cmlib/cmlib.h b/platform/clounix/clounix-modules/modules/src/inc/cmlib/cmlib.h new file mode 100644 index 000000000000..fa6af133d7ef --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/cmlib/cmlib.h @@ -0,0 +1,103 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: cmlib.h + * PURPOSE: + * this file is used to provide init common library operations to other users. + * NOTES: + * it contains operations as below: + * 1. init common library + * 2. deinit common library. + * 3. register debug commands for all sub-modules. + * 4. deregister debug commands for all sub-modules. + * 5. provide debug functions for sub-modules. + * + * + * + */ +#ifndef CMLIB_H +#define CMLIB_H + +/* INCLUDE FILE DECLARATIONS + */ + +#include +#include + +/* NAMING CONSTANT DECLARATIONS + */ +#define CMLIB_NAME_MAX_LEN (32) + +/* MACRO FUNCTION DECLARATIONS + */ + + +/* FUNCTION NAME: CMLIB_MULTI_OVERFLOW + * PURPOSE: + * it is used to test if two 32-bit unsigned operand multiply will be overflow + * INPUT: + * ui32a -- operand a + * ui32b -- operand b + * OUTPUT: + * None. + * RETURN: + * 0 -- not overflow + * non 0 -- overflow + * NOTES: + * + */ +#define CMLIB_MULTI_OVERFLOW(ui32a, ui32b) \ + ((ui32a) ? ((~0U/(UI32_T)(ui32a)) < (UI32_T)(ui32b)) : 0) + +/* FUNCTION NAME: CMLIB_ADD_OVERFLOW + * PURPOSE: + * it is used to test if two operands add overflow. + * INPUT: + * ui32a -- operand a + * ui32b -- operand b + * OUTPUT: + * None. + * RETURN: + * 0 -- not overflow + * non 0 -- overflow + * NOTES: + * + */ +#define CMLIB_ADD_OVERFLOW(ui32a, ui32b) \ + ((UI32_T)(ui32a) > ~((UI32_T)(ui32b))) + +/* DATA TYPE DECLARATIONS + */ + +typedef struct CMLIB_DBG_LIST_NODE_S +{ + void *ptr_data; + struct CMLIB_DBG_LIST_NODE_S *ptr_next; +} CMLIB_DBG_LIST_NODE_T; + + +typedef struct +{ + CMLIB_DBG_LIST_NODE_T *ptr_front; + CLX_SEMAPHORE_ID_T sem; +} CMLIB_DBG_HEAD_T; + + +/* EXPORTED SUBPROGRAM SPECIFICATIONS + */ + +#endif /* End of CMLIB_H */ + diff --git a/platform/clounix/clounix-modules/modules/src/inc/cmlib/cmlib_list.h b/platform/clounix/clounix-modules/modules/src/inc/cmlib/cmlib_list.h new file mode 100644 index 000000000000..52d327f8da38 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/cmlib/cmlib_list.h @@ -0,0 +1,219 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: cmlib_list.h + * PURPOSE: + * this file is used to provide linked list operations to other users. + * linked list include: singly linked list, doubly linked list + * + * NOTES: + * it contains operations as below: + * 1. create a linked list + * 2. destroy a linked list + * 3. insert user data to a linked list + * 4. delete a user data from a linked list + * 5. locate a user data from a linked list + * 6. get next node from a linked list node + * 7. get previous node from a linked list node + * 7. get a linked list nodes count + * + */ +#ifndef CMLIB_LIST_H +#define CMLIB_LIST_H +/* INCLUDE FILE DECLARATIONS + */ +#include +/* NAMING CONSTANT DECLARATIONS + */ + + + +/* linked list type */ +typedef enum +{ + CMLIB_LIST_TYPE_SINGLY = 0, /* singly linked list type */ + CMLIB_LIST_TYPE_DOUBLY, /* doubly linked list type */ + CMLIB_LIST_TYPE_LAST, +} CMLIB_LIST_TYPE_T; + +/* MACRO FUNCTION DECLARATIONS + */ +/* DATA TYPE DECLARATIONS + */ + +/* linked list node */ +typedef struct CMLIB_LIST_NODE_S +{ + void *ptr_data; /* node data */ + struct CMLIB_LIST_NODE_S *ptr_next; /* point to next link node */ + struct CMLIB_LIST_NODE_S *ptr_prev; /* point to previous link node */ +} CMLIB_LIST_NODE_T; + +struct CMLIB_LIST_S; + +/* FUNCTION TYPE NAME: CMLIB_LIST_CMP_FUNC_T + * PURPOSE: + * it is used to find which position the node should be inserted. + * INPUT: + * ptr_node_data -- the checked linked list node data. + * ptr_insert_data -- the data will be inserted. + * OUTPUT: + * None. + * RETURN: + * 0 -- the insert node should be inserted before the node. + * non 0 -- it is not the right position. + * NOTES: + * + */ +typedef I32_T (*CMLIB_LIST_CMP_FUNC_T)( + void *ptr_node_data, + void *ptr_insert_data ); + +/* FUNCTION TYPE NAME: CMLIB_LIST_LOCATE_FUNC_T + * PURPOSE: + * it is used to locate a linked list node. + * INPUT: + * ptr_node_data -- the checked linked list node data. + * ptr_cookie -- the data used to check the linked list node. it is + * one of locate function parameters. + * OUTPUT: + * None. + * RETURN: + * 0 -- locate success + * non 0 -- locate failed, should continue to check. + * NOTES: + * + */ +typedef I32_T (*CMLIB_LIST_LOCATE_FUNC_T)( + void *ptr_node_data, + void *ptr_cookie ); + + +/* FUNCTION TYPE NAME: CMLIB_LIST_DESTROY_FUNC_T + * PURPOSE: + * it is used to release linked list node when destroy a linked list. + * INPUT: + * ptr_node_data -- the linked list node data will be destroyed. + * OUTPUT: + * None. + * RETURN: + * None. + * NOTES: + * + */ +typedef void (*CMLIB_LIST_DESTROY_FUNC_T)( + void *ptr_node_data ); + +typedef CMLIB_LIST_DESTROY_FUNC_T CMLIB_LIST_DELETE_FUNC_T; + +/* linked list operations */ +typedef struct +{ + CLX_ERROR_NO_T (*getNodeData) ( + struct CMLIB_LIST_S *ptr_list, /* the node owner */ + CMLIB_LIST_NODE_T *ptr_node, /* the node will be get the data */ + void **pptr_node_data );/* the data pointer saved in the node */ + + CLX_ERROR_NO_T (*insertByFunc)( /* it used to insert a node by a function */ + struct CMLIB_LIST_S *ptr_list, /* the linked list in which the node is inserted */ + void *ptr_data, /* the inserted data */ + CMLIB_LIST_CMP_FUNC_T insert_callback );/* the insert function decide where the data is + * inserted. + */ + + CLX_ERROR_NO_T (*insertToHead)( /* it used to insert a data to the head */ + struct CMLIB_LIST_S *ptr_list, /* the linked list in which the node is inserted */ + void *ptr_data ); /* the inserted data */ + + CLX_ERROR_NO_T (*insertToTail)( /* it used to insert a data to the tail */ + struct CMLIB_LIST_S *ptr_list, /* the linked list in which the node is inserted */ + void *ptr_data ); /* the inserted data */ + + CLX_ERROR_NO_T (*insertBefore)( /* insert a data before a specified node */ + struct CMLIB_LIST_S *ptr_list, /* the linked list in which the node is inserted */ + CMLIB_LIST_NODE_T *ptr_node, /* the specified node */ + void *ptr_insert_data ); /* the inserted data */ + + CLX_ERROR_NO_T (*insertAfter)( /* insert a data after a specified node */ + struct CMLIB_LIST_S *ptr_list, /* the linked list in which the node is inserted */ + CMLIB_LIST_NODE_T *ptr_node, /* the specified node */ + void *ptr_insert_data ); /* the inserted data */ + + CLX_ERROR_NO_T (*deleteNode)( /* delete a node from a linked list */ + struct CMLIB_LIST_S *ptr_list, /* the linked list from which delete */ + CMLIB_LIST_NODE_T *ptr_delete_node ); /* the node will be deleted */ + + CLX_ERROR_NO_T (*deleteByData)( + struct CMLIB_LIST_S *ptr_list, + void *ptr_data ); + + CLX_ERROR_NO_T (*locateByFunc)( /* locate a node from a linked list */ + struct CMLIB_LIST_S *ptr_list, /* the linked list from which locate */ + void *ptr_cookie, /* the cookie data for locate callback */ + CMLIB_LIST_LOCATE_FUNC_T locate_callback, /* locate calback function */ + CMLIB_LIST_NODE_T **pptr_node ); /* the located node */ + + CLX_ERROR_NO_T (*locateHead)( /* get the head node from a linked list */ + struct CMLIB_LIST_S *ptr_list, /* the linked list from which get */ + CMLIB_LIST_NODE_T **pptr_node ); /* the head node */ + + CLX_ERROR_NO_T (*locateTail)( /* get the tail node from a linked list */ + struct CMLIB_LIST_S *ptr_list, /* the linked list from which get */ + CMLIB_LIST_NODE_T **pptr_node ); /* the tail node */ + + CLX_ERROR_NO_T (*next)( /* get next node of the specified node */ + struct CMLIB_LIST_S *ptr_list, /* the node of this linked list */ + CMLIB_LIST_NODE_T *ptr_node, /* the speicified node */ + CMLIB_LIST_NODE_T **pptr_next_node); /* the next node */ + + CLX_ERROR_NO_T (*prev)( /* get previous node of the specified node */ + struct CMLIB_LIST_S *ptr_list, /* the node of this linked list */ + CMLIB_LIST_NODE_T *ptr_node, /* the speicified node */ + CMLIB_LIST_NODE_T **pptr_prev_node );/* the previous node */ + + CLX_ERROR_NO_T (*getLength)( /* get the node count of a linked list */ + struct CMLIB_LIST_S *ptr_list, /* the linked list */ + UI32_T *ptr_length); /* the linked list, output parameter */ + + CLX_ERROR_NO_T (*destroy)( /* destroy a linked list */ + struct CMLIB_LIST_S *ptr_list, /* the destroyed linked list */ + CMLIB_LIST_DESTROY_FUNC_T destroy_callback ); /* the destroy function for + * releasing linked list node data + */ + CLX_ERROR_NO_T (*deleteAll)( /* destroy all nodes from a linked list*/ + struct CMLIB_LIST_S *ptr_list, /* the linked list*/ + CMLIB_LIST_DELETE_FUNC_T delete_callback); /* the delete function for releasing node data*/ + +} CMLIB_LIST_OPS_T; + + +/* linked list head */ +typedef struct CMLIB_LIST_S +{ + CMLIB_LIST_NODE_T *ptr_head_node; /* linked list head node */ + CMLIB_LIST_NODE_T *ptr_tail_node; /* linked list tail node */ + CMLIB_LIST_TYPE_T type; /* list type */ + UI32_T capacity; /* max count of nodes in list + * size=0: the capacity is unlimited. + * size>0: the capacity is limited. + */ + void *ptr_node_pool; /* node pool */ + UI32_T node_count; /* the count of nodes in the list */ + CMLIB_LIST_OPS_T *ptr_ops; /* linked list operations */ +} CMLIB_LIST_T; + +#endif /* End of CMLIB_LIST_H */ + diff --git a/platform/clounix/clounix-modules/modules/src/inc/hal/common/hal_dev.h b/platform/clounix/clounix-modules/modules/src/inc/hal/common/hal_dev.h new file mode 100644 index 000000000000..2d867f03b427 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/hal/common/hal_dev.h @@ -0,0 +1,58 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: hal_dev.h + * PURPOSE: + * Provide a list of device IDs. + * + * NOTES: + */ + +#ifndef HAL_DEV_H +#define HAL_DEV_H + +/* INCLUDE FILE DECLARATIONS + */ +/* NAMING CONSTANT DECLARATIONS + */ +#define HAL_CLX_VENDOR_ID (0x0E8D) +#define HAL_CL_VENDOR_ID (0x1D9F) + +#define HAL_DEVICE_ID_CL3257 (0x3257) +#define HAL_DEVICE_ID_CL3258 (0x3258) + +#define HAL_DEVICE_ID_CL8300 (0x8300) /* chip family */ +#define HAL_DEVICE_ID_CL8363 (0x8363) /* 1.08T 1Bin */ +#define HAL_DEVICE_ID_CL8365 (0x8365) /* 1.8T 1Bin */ +#define HAL_DEVICE_ID_CL8366 (0x8366) /* 2.4T 1Bin */ +#define HAL_DEVICE_ID_CL8367 (0x8367) /* 3.2T 1Bin */ +#define HAL_DEVICE_ID_CL8368 (0x8368) /* 3.2T 2Bin */ +#define HAL_DEVICE_ID_CL8369 (0x8369) /* 6.4T 2Bin */ + +#define HAL_DEVICE_ID_CL8500 (0x8500) /* chip family */ +#define HAL_DEVICE_ID_CL8571 (0x8571) /* 3.2T 2Bin */ +#define HAL_DEVICE_ID_CL8573 (0x8573) /* 3.2T 2Bin */ +#define HAL_DEVICE_ID_CL8575 (0x8575) /* 4.0T 4Bin */ +#define HAL_DEVICE_ID_CL8577 (0x8577) /* 6.4T 4Bin */ +#define HAL_DEVICE_ID_CL8578 (0x8578) /* 8.0T 4Bin */ +#define HAL_DEVICE_ID_CL8579 (0x8579) /* 12.8T 4Bin */ + +#define HAL_REVISION_ID_E1 (0x01) +#define HAL_REVISION_ID_E2 (0x02) + +#define HAL_INVALID_DEVICE_ID (0xFFFFFFFF) + +#endif /* #ifndef HAL_DEV_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/hal/common/hal_dflt.h b/platform/clounix/clounix-modules/modules/src/inc/hal/common/hal_dflt.h new file mode 100644 index 000000000000..7966fd4f1ce9 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/hal/common/hal_dflt.h @@ -0,0 +1,412 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: hal_dflt.h + * PURPOSE: + * 1. Provide definition for sdk default + * 2. Provide registration/deregistration + * 3. Provide data structure declaration + * 4. Provide + * + * NOTES: + */ + +#ifndef HAL_DFLT_H +#define HAL_DFLT_H + + +/* INCLUDE FILE DECLARATIONS + */ +#include +#include + + +/* NAMING CONSTANT DECLARATIONS + */ + +/* NAMING CONSTANT DECLARATIONS + ----USER CONFIG (follow CLX_CFG_TYPE_T enum sequence)---- + */ +/* SWC module */ +#if defined(CLX_EN_SDN) +#define HAL_DFLT_CFG_CHIP_MODE (1) + /* chip operating mode. 0: legacy mode; 1:hybrid mode */ +#else +#define HAL_DFLT_CFG_CHIP_MODE (0) + /* chip operating mode. 0: legacy mode; 1:hybrid mode */ +#endif + +/* PORT module related configuration */ +#define HAL_DFLT_CFG_PORT_MAX_SPEED (0) + /* port max speed is not applied */ +#define HAL_DFLT_CFG_PORT_LANE_NUM (0) + /* port lane num is not applied */ +#define HAL_DFLT_CFG_PORT_TX_LANE (0) + /* port tx lane is not applied */ +#define HAL_DFLT_CFG_PORT_RX_LANE (0) + /* port rx lane is not appied */ +#define HAL_DFLT_CFG_PORT_TX_POLARITY_REV (0) + /* port tx polarity rev is not applied */ +#define HAL_DFLT_CFG_PORT_RX_POLARITY_REV (0) + /* port rx polarity rev is not applied */ +#define HAL_DFLT_CFG_PORT_EXT_LANE (0) + /* port ext lane is not applied */ +#define HAL_DFLT_CFG_PORT_VALID (0) + /* port valid is not applied */ + +/* l2 module related configuration */ +#define HAL_DFLT_CFG_L2_THREAD_PRI (50) +#define HAL_DFLT_CFG_L2_THREAD_STACK (64 * 1024) + /* customize L2 thread stack size in bytes */ +#define HAL_DFLT_CFG_L2_ADDR_MODE (0) + /* L2 address operation mode. 0: Polling mode, 1: FIFO mode */ +#define HAL_DFLT_CFG_L2_POLLING_INTERVAL (4000) + /* Times (msec) to poll all L2 FDB entries */ + +/* PKT module related configuration */ +#define HAL_DFLT_CFG_PKT_TX_GPD_NUM (1024) +#define HAL_DFLT_CFG_PKT_RX_GPD_NUM (1024) +#define HAL_DFLT_CFG_PKT_RX_SCHED_MODE (0) + /* 0: RR mode, 1: WRR mode */ +#define HAL_DFLT_CFG_PKT_TX_QUEUE_LEN (HAL_DFLT_CFG_PKT_TX_GPD_NUM * 10) +#define HAL_DFLT_CFG_PKT_RX_QUEUE_LEN (HAL_DFLT_CFG_PKT_RX_GPD_NUM * 10) +#define HAL_DFLT_CFG_PKT_RX_QUEUE_WEIGHT (0) + /* valid while CLX_CFG_TYPE_PKT_RX_SCHED_MODE is 1 + * param0: queue + * param1: NA + * value : weight + */ +#define HAL_DFLT_CFG_PKT_RX_ISR_THREAD_PRI (80) +#define HAL_DFLT_CFG_PKT_RX_ISR_THREAD_STACK (64 * 1024) + /* customize PKT RX ISR thread stack size in bytes */ +#define HAL_DFLT_CFG_PKT_RX_FREE_THREAD_PRI (80) +#define HAL_DFLT_CFG_PKT_RX_FREE_THREAD_STACK (64 * 1024) + /* customize PKT RX free thread stack size in bytes */ +#define HAL_DFLT_CFG_PKT_TX_ISR_THREAD_PRI (80) +#define HAL_DFLT_CFG_PKT_TX_ISR_THREAD_STACK (64 * 1024) + /* customize PKT TX ISR thread stack size in bytes */ +#define HAL_DFLT_CFG_PKT_TX_FREE_THREAD_PRI (80) +#define HAL_DFLT_CFG_PKT_TX_FREE_THREAD_STACK (64 * 1024) + /* customize PKT TX free thread stack size in bytes */ +#define HAL_DFLT_CFG_PKT_ERROR_ISR_THREAD_PRI (80) +#define HAL_DFLT_CFG_PKT_ERROR_ISR_THREAD_STACK (64 * 1024) + /* customize PKT ERROR ISR thread stack size in bytes */ +#define HAL_DFLT_CFG_PKT_DMA_ENHANCE_ENABLE (0) + + +/* STAT module related configuration */ +#define HAL_DFLT_CFG_CNT_THREAD_PRI (0) +#define HAL_DFLT_CFG_CNT_THREAD_STACK (0) + /* customize CNT thread stack size in bytes */ + +/* IFMON module related configuration */ +#define HAL_DFLT_CFG_IFMON_THREAD_PRI (0) +#define HAL_DFLT_CFG_IFMON_THREAD_STACK (0) + /* customize IFMON thread stack size in bytes */ + +/* share memory related configuration */ +#define HAL_DFLT_CFG_SHARE_MEM_SDN_ENTRY_NUM (0) + /* SDN flow table entry number from share memory */ +#define HAL_DFLT_CFG_SHARE_MEM_L3_ENTRY_NUM (0) + /* L3 entry number from share memory */ +#define HAL_DFLT_CFG_SHARE_MEM_L2_ENTRY_NUM (0) + /* L2 entry number from share memory */ + +/* DLB related configuration */ +#define HAL_DFLT_CFG_DLB_MONITOR_MODE (0) + /* DLB monitor mode. 1: async, 0: sync */ +#define HAL_DFLT_CFG_DLB_LAG_MONITOR_THREAD_PRI (0) +#define HAL_DFLT_CFG_DLB_LAG_MONITOR_THREAD_SLEEP_TIME (0) +#define HAL_DFLT_CFG_DLB_L3_MONITOR_THREAD_PRI (0) +#define HAL_DFLT_CFG_DLB_L3_MONITOR_THREAD_SLEEP_TIME (0) +#define HAL_DFLT_CFG_DLB_L3_INTR_THREAD_PRI (0) +#define HAL_DFLT_CFG_DLB_NVO3_MONITOR_THREAD_PRI (0) +#define HAL_DFLT_CFG_DLB_NVO3_MONITOR_THREAD_SLEEP_TIME (0) +#define HAL_DFLT_CFG_DLB_NVO3_INTR_THREAD_PRI (0) + +/* l3 related configuration */ +#define HAL_DFLT_CFG_L3_ECMP_MIN_BLOCK_SIZE (0) +#define HAL_DFLT_CFG_L3_ECMP_BLOCK_SIZE (0) +#define HAL_DFLT_CFG_TCAM_L3_WITH_IPV6_PREFIX_128_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_TCAM_L3_WITH_IPV6_PREFIX_64_REGION_ENTRY_NUM (0) + +/* share memory related configuration */ +#define HAL_DFLT_CFG_HASH_L2_FDB_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_L2_GROUP_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_SECURITY_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_L3_WITH_IPV6_PREFIX_128_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_L3_WITH_IPV6_PREFIX_64_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_L3_WITHOUT_PREFIX_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_L3_RPF_REGION_ENTRY_NUM (0) +#define HAL_DFLT_CFG_HASH_FLOW_REGION_ENTRY_NUM (0) + +#define HAL_DFLT_CFG_PORT_FC_MODE (0) + /* only use to init port TM buffer + * configuration for specific FC mode, + * which not enable/disable FC/PFC + * for the port/pcp. + * param0: port. + * param1: Invalid. + * value : 0, FC disable; + * 1, 802.3x FC; + * 2, PFC. + */ +#define HAL_DFLT_CFG_PORT_PFC_STATE (0) + /* valid while CLX_CFG_TYPE_PORT_TYPE_FC_MODE + * of the port is PFC. + * param0: port. + * param1: pcp. + * value : 0, PFC disable; + * 1, PFC enable. + */ +#define HAL_DFLT_CFG_PORT_PFC_QUEUE_STATE (0) + /* valid while CLX_CFG_TYPE_PORT_TYPE_FC_MODE + * of the port is PFC. + * param0: port. + * param1: queue. + * value : 0, PFC disable; + * 1, PFC enable; + */ +#define HAL_DFLT_CFG_PORT_PFC_MAPPING (0) + /* valid while CLX_CFG_TYPE_PORT_FC_MODE + * of the port is PFC. + * param0: port. + * param1: queue. + * value : PCP bitmap; + * + */ +#define HAL_DFLT_CFG_TRILL_ENABLE (0) + /* TRILL module related configuration */ +#define HAL_DFLT_CFG_USE_UNIT_PORT (0) + /* use UNIT_PORT or native port of CLX_PORT_T + * 1 : UNIT_PORT, 0 : native port + */ +#define HAL_DFLT_CFG_MAC_VLAN_ENABLE (0) + /* use dadicate mac vlan table */ +#define HAL_DFLT_CFG_CPI_PORT_MODE (0) + /* use to init CPI port working mode. + * param0: CPI port number. + * param1: NA. + * value : 0, CPI mode. + * 1, Ether mode. + */ +#define HAL_DFLT_CFG_PHY_ADDR (0) +#define HAL_DFLT_CFG_LED_CFG (0) +#define HAL_DFLT_CFG_USER_BUF_CTRL (0) +#define HAL_DFLT_CFG_FAIR_BUF_CTRL (0) + /* to enable the fairness in flow-control traffic. + * value : 0, disable fairness. + * 1, enable fairness. + */ +#define HAL_DFLT_CFG_HRM_BUF_SIZE (0) + /* to assign the head room size of port speed. + * param0: Port speed. + * 0, 1G (default) + * 1, 10G + * 2, 25G + * 3, 40G + * 4, 50G + * 5, 100G + * value : cell number. + */ +#define HAL_DFLT_CFG_STEERING_TRUNCATE_ENABLE (0) + /* set value 0: Do not truncate steering packets. + * set value 1: steering packets will be trucated to 1 cell and + * the cell size is based on chip. + */ +#define HAL_DFLT_CFG_FABRIC_MODE_ENABLE (0) + /* set value 0: Non-farbic chip mode. (default) + * set value 1: Fabric chip mode. + */ +#define HAL_DFLT_CFG_ACL_TCP_FLAGS_ENCODE_ENABLE (1) + /* set value 0: Do not encode tcp flags at acl entry. + * (Can only match bit 0-6 of tcp flags.) + * set value 1: Encode tcp flags at acl entry. (default) + */ +#define HAL_DFLT_CFG_TCAM_ECC_SCAN_ENABLE (0) + /* set value 0: Disable ECC TCAM scanning. (default) + * set value 1: Enable ECC TCAM scanning. + */ +#define HAL_DFLT_CFG_PORT_BUF_MAX (0) + /* + * Port max buffer threshold and unit is cell count. + * param0: port. + * param1: 0, ingress; + * 1, egress. + * value : 0, disable; + * others, enable max threshold. + */ +#define HAL_DFLT_CFG_INGRESS_DYNAMIC_BUF (0) + /* + * Queue dynamic alpha setting and value will be + * enlarge to multiple of 256. For example, set value + * as 16 to indicate alpha as 1/16. Set value + * as 256 to indicate alpha as 1. + * param0: port. + * param1: queue (0~7: sc). + * value : alpha * 256. + */ +#define HAL_DFLT_CFG_EGRESS_DYNAMIC_BUF (0) + /* + * Queue dynamic alpha setting and value will be + * enlarge to multiple of 256. For example, set value + * as 16 to indicate alpha as 1/16. Set value + * as 256 to indicate alpha as 1. + * param0: port. + * param1: queue (0~7: uc, 8~15: mc). + * value : alpha * 256. + */ + +#define HAL_DFLT_CFG_DCQCN_ENABLE (0) + /* set value 0: Disable DCQCN. (default) + * set value 1: Enable DCQCN. + */ + +#define HAL_DFLT_CFG_QUEUE_GROUP_MAP (0) + /* To map MC egress accounting from qeueu to group. + * param0: queue id. (0~7). + * value : group id. + */ + +#define HAL_DFLT_CFG_PRI_GROUP_MAP (0) + /* To account egress group from egress queue. + * PG setting is availabled when CLX_CFG_TYPE_USER_BUF_CTRL is enabled. + * param0: queue id. (0~47 for PCIE, 0-7 for others). + * param1: 0, Front port UC type. + 1, Front port MC type. + 2, Local CPU type. + 3, Remote CPU type. + 4, PCIE type. + 5, MIRROR type. + * value : group id. + */ + + +#define HAL_DFLT_CFG_MPLS_SR_NUM (0) + /* MPLS Segment Routing + * value: encapsulation number + */ +#define HAL_DFLT_CFG_L2_BYPASS_LAG_PRUNE_GROUP_NUM (0) + /* default value: 0 */ +#define HAL_DFLT_CFG_L3_BYPASS_LAG_PRUNE_GROUP_NUM (0) + /* default value: 0 */ + +/* DTEL related configuration */ +#define HAL_DFLT_CFG_DTEL_PROFILE_NUM (0) + /* DTEL profile number, it share with sFlow */ + +/* l3 related configuration */ +#define HAL_DFLT_CFG_TCAM_L3_SIP_ENABLE (0) + /* default value: 0, to expand TCAM capacity */ +#define HAL_DFLT_CFG_L3_ECMP_FDL_ENABLE (0) + /* default value: 0, to reserve adj for FDL */ + +#define HAL_DFLT_CFG_HASH_L3_IPV4_PREFIX_LENGTH_ENTRY_NUM (0) + /* param0: prefix-length (1~32) */ + /* param1: 1: vrf, 0: global */ + /* value: entry number */ + +#define HAL_DFLT_CFG_HASH_L3_IPV6_PREFIX_LENGTH_ENTRY_NUM (0) + /* param0: prefix-length (1~128) */ + /* param1: 1: vrf, 0: global */ + /* value: entry number */ + +#define HAL_DFLT_CFG_ACL_DROP_REDIRECT_CPU_PKT (0) + /* set value 0: acl drop_cpu action would not drop redirect to cpu pkt. + * (default) + * set value 1: acl drop_cpu action would drop redirect to cpu pkt. + */ +#define HAL_DFLT_CFG_STACKING_CHIP_PORT_NUM (0) + /* In stacking/chassis system, max used port num per device. + * default value: hw default max port + */ +#define HAL_DFLT_CFG_BUF_SNAPSHOT_INTERVAL (0) + +#define HAL_DFLT_CFG_LAG_MC_RESILIENT_ENABLE (0) + /* set value 0: disable (default). + * set value 1: enable. + */ + + +/* NAMING CONSTANT DECLARATIONS + ----DEFAULT PROPERTY ---- + */ +/* ---- VLAN ---- */ +#define HAL_DFLT_VLAN (1) +#define HAL_DFLT_BDID (1) + +/* ---- PORT ---- */ +#define HAL_DFLT_L2_MTU (1536) +#define HAL_DFLT_TPID_1ST (0x8100) +#define HAL_DFLT_TPID_2ND (0x0) + + + + +/* ---- IFMON ---- */ + +/* ---- L2 ---- */ + +/* ---- STP ---- */ +#define HAL_DFLT_STP_ID (0) + +/* ---- LAG ---- */ + +/* ---- MIR ---- */ + +/* ---- L3 ---- */ + +/* ---- L3T ---- */ + +/* ---- QOS ---- */ + +/* ---- METER ---- */ + +/* ---- PKT ---- */ + +/* ---- ACL ---- */ + +/* ---- STAT ---- */ + +/* ---- SEC ---- */ + +/* ---- SFLOW ---- */ + +/* ---- TM ---- */ + +/* ---- VM ---- */ + +/* ---- FCOE ---- */ + +/* ---- NV ---- */ + +/* ---- SWC ---- */ + +/* ---- SDN ---- */ + +/* ---- MPLS ---- */ + +/* ---- TRILL ---- */ + +/* ---- SFC ---- */ + +/* ---- STK ---- */ + + +/* MACRO FUNCTION DECLARATIONS + */ + +#endif diff --git a/platform/clounix/clounix-modules/modules/src/inc/hal_dawn_pkt_knl.h b/platform/clounix/clounix-modules/modules/src/inc/hal_dawn_pkt_knl.h new file mode 100755 index 000000000000..2d8c6ae8d077 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/hal_dawn_pkt_knl.h @@ -0,0 +1,2195 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: hal_dawn_pkt_knl.h + * PURPOSE: + * To provide Linux kernel for PDMA TX/RX control. + * + * NOTES: + */ + +#ifndef HAL_DAWN_PKT_KNL_H +#define HAL_DAWN_PKT_KNL_H +#include +#include + +/* CP_COMMON */ +#define HAL_DAWN_PKT_CP_COMMON_INT_EN_HI (0x012C0000) +#define HAL_DAWN_PKT_CP_COMMON_INT_LO_HI (0x012C0004) +#define HAL_DAWN_PKT_CP_COMMON_INT_LVL_HI (0x012C0008) +#define HAL_DAWN_PKT_CP_COMMON_INT_LVL_LO (0x012C000C) +#define HAL_DAWN_PKT_CP_COMMON_INT_MASK_SET_HI (0x012C0010) +#define HAL_DAWN_PKT_CP_COMMON_INT_MASK_SET_LO (0x012C0014) +#define HAL_DAWN_PKT_CP_COMMON_INT_MASK_CLR_HI (0x012C0018) +#define HAL_DAWN_PKT_CP_COMMON_INT_MASK_CLR_LO (0x012C001C) +#define HAL_DAWN_PKT_CP_COMMON_INT_MASK_VAL_HI (0x012C0020) +#define HAL_DAWN_PKT_CP_COMMON_INT_MASK_VAL_LO (0x012C0024) +#define HAL_DAWN_PKT_CP_COMMON_INT_STAT_HI (0x012C0028) +#define HAL_DAWN_PKT_CP_COMMON_INT_STAT_LO (0x012C002C) +#define HAL_DAWN_PKT_CP_COMMON_INT_CLR_HI (0x012C0030) +#define HAL_DAWN_PKT_CP_COMMON_INT_CLR_LO (0x012C0034) +#define HAL_DAWN_PKT_CP_COMMON_INT_SET_HI (0x012C0038) +#define HAL_DAWN_PKT_CP_COMMON_INT_SET_LO (0x012C003C) + +/* PDMA */ +#define HAL_DAWN_PKT_PDMA_ERR_INT_STAT (0x013F1000) +#define HAL_DAWN_PKT_PDMA_ERR_INT_CLR (0x013F1004) +#define HAL_DAWN_PKT_PDMA_ERR_INT_EN (0x013F1010) +#define HAL_DAWN_PKT_PDMA_ERR_INT_LVL (0x013F1014) +#define HAL_DAWN_PKT_PDMA_ERR_INT_MASK_SET (0x013F1018) +#define HAL_DAWN_PKT_PDMA_ERR_INT_MASK_CLR (0x013F101C) +#define HAL_DAWN_PKT_PDMA_ERR_INT_MASK_VAL (0x013F1020) +#define HAL_DAWN_PKT_PDMA_ERR_INT_SET (0x013F1024) +#define HAL_DAWN_PKT_PDMA_CREDIT_CFG (0x013F1100) + +/* Rx */ +#define HAL_DAWN_PKT_PDMA_RCH_GPD_RING_START_ADDR_LO (0x013F12E4) +#define HAL_DAWN_PKT_PDMA_RCH_GPD_RING_START_ADDR_HI (0x013F12E8) +#define HAL_DAWN_PKT_PDMA_RCH_GPD_RING_SIZE (0x013F12EC) +#define HAL_DAWN_PKT_PDMA_RCH_CMD (0x013F1300) +#define HAL_DAWN_PKT_PDMA_RCH_INT_EN (0x013F1360) +#define HAL_DAWN_PKT_PDMA_RCH_INT_LVL (0x013F1364) +#define HAL_DAWN_PKT_PDMA_RCH_INT_MASK (0x013F1368) +#define HAL_DAWN_PKT_PDMA_RCH_INT_SET (0x013F1370) +#define HAL_DAWN_PKT_PDMA_RCH_INT_CLR (0x013F1374) +#define HAL_DAWN_PKT_PDMA_RCH_INT_STAT (0x013F1378) + +/* Tx */ +#define HAL_DAWN_PKT_PDMA_TCH_GPD_RING_START_ADDR_LO (0x013F1A00) +#define HAL_DAWN_PKT_PDMA_TCH_GPD_RING_START_ADDR_HI (0x013F1A04) +#define HAL_DAWN_PKT_PDMA_TCH_GPD_RING_SIZE (0x013F1A08) +#define HAL_DAWN_PKT_PDMA_TCH_CMD (0x013F1A20) +#define HAL_DAWN_PKT_PDMA_TCH_INT_EN (0x013F1A40) +#define HAL_DAWN_PKT_PDMA_TCH_INT_LVL (0x013F1A44) +#define HAL_DAWN_PKT_PDMA_TCH_INT_MASK (0x013F1A48) +#define HAL_DAWN_PKT_PDMA_TCH_INT_SET (0x013F1A50) +#define HAL_DAWN_PKT_PDMA_TCH_INT_CLR (0x013F1A54) +#define HAL_DAWN_PKT_PDMA_TCH_INT_STAT (0x013F1A58) + +#define HAL_DAWN_PKT_GET_MMIO(__tbl__) (0x00FFFFFF & (__tbl__)) +#define HAL_DAWN_PKT_GET_PDMA_RCH_REG(__tbl__, __channel__) ((__tbl__) + (0x200 * (__channel__))) +#define HAL_DAWN_PKT_GET_PDMA_TCH_REG(__tbl__, __channel__) ((__tbl__) + (0x100 * (__channel__))) + + +#define HAL_DAWN_PORT_NUM (128) +#define HAL_DAWN_PLANE_NUM (4) +#define HAL_DAWN_PLANE_BITS (2) +#define HAL_DAWN_PLANE_MASK (0x3) + +/* NAMING DECLARATIONS + */ +/* PKT definitions */ +#define HAL_DAWN_PKT_TX_MAX_LEN (9216) +#define HAL_DAWN_PKT_RX_MAX_LEN (9216 + 86) /* EPP tunnel header */ +#define HAL_DAWN_PKT_MIN_LEN (64) /* Ethernet definition */ +#define HAL_DAWN_PKT_TMH_HDR_SZ (20) +#define HAL_DAWN_PKT_PPH_HDR_SZ (20) +#define HAL_DAWN_PKT_CRC_LEN (4) + +/* CH */ +#define HAL_DAWN_PKT_CH_LAST_GPD (0) +#define HAL_DAWN_PKT_CH_MIDDLE_GPD (1) + +/* PRG */ +#define HAL_DAWN_PKT_PRG_PROCESS_GPD (0) /* Normal */ +#define HAL_DAWN_PKT_PRG_SKIP_GPD (1) /* Skip */ + +/* CRCC */ +#define HAL_DAWN_PKT_CRCC_SUM_BY_HW (0) /* calculated by HW */ +#define HAL_DAWN_PKT_CRCC_SUM_BY_SW (1) /* calculated by SW */ + +/* IOC */ +#define HAL_DAWN_PKT_IOC_NO_INTR (0) /* trigger interrupt each GPD */ +#define HAL_DAWN_PKT_IOC_HAS_INTR (1) /* trigger interrupt when ch=0, default setting */ + +/* HWO */ +#define HAL_DAWN_PKT_HWO_SW_OWN (0) +#define HAL_DAWN_PKT_HWO_HW_OWN (1) + +/* ECC */ +#define HAL_DAWN_PKT_ECC_ERROR_OCCUR (1) + +/* CPU, CPI queue number */ +#define HAL_DAWN_PKT_CPU_QUE_NUM (48) +#define HAL_DAWN_PKT_CPI_QUE_NUM (8) + +/* PDMA Definitions */ +#define HAL_DAWN_PKT_PDMA_MAX_GPD_PER_PKT (10) /* <= 256 */ +#define HAL_DAWN_PKT_PDMA_TX_INTR_TIMEOUT (10 * 1000) /* us */ +#define HAL_DAWN_PKT_PDMA_TX_POLL_MAX_LOOP (10 * 1000) /* int */ + +/* Mode */ +#define HAL_DAWN_PKT_TX_WAIT_MODE (HAL_DAWN_PKT_TX_WAIT_ASYNC) + +/* TX Queue */ +#define HAL_DAWN_PKT_TX_TASK_MAX_LOOP (HAL_DFLT_CFG_PKT_TX_QUEUE_LEN) + +/* RX Queue */ +#define HAL_DAWN_PKT_RX_QUEUE_NUM (HAL_DAWN_PKT_RX_CHANNEL_LAST) +#define HAL_DAWN_PKT_RX_TASK_MAX_LOOP (HAL_DFLT_CFG_PKT_TX_QUEUE_LEN) + +/* MACRO FUNCTION DECLARATIONS + */ +/*---------------------------------------------------------------------------*/ +/* [CL8360] Alignment to 64-bytes */ +#if defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) +#define HAL_DAWN_PKT_PDMA_ALIGN_ADDR(pdma_addr, align_sz) (((pdma_addr) + (align_sz)) & 0xFFFFFFFFFFFFFFC0) +#else +#define HAL_DAWN_PKT_PDMA_ALIGN_ADDR(pdma_addr, align_sz) (((pdma_addr) + (align_sz)) & 0xFFFFFFC0) +#endif +/*---------------------------------------------------------------------------*/ +#if defined(CLX_EN_BIG_ENDIAN) +#define HAL_DAWN_PKT_ENDIAN_SWAP32(val) (val) +#else +#define HAL_DAWN_PKT_ENDIAN_SWAP32(val) CMLIB_UTIL_ENDIAN_SWAP32(val) +#endif +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_GET_BIT(flags, bit) ((((flags) & (bit)) > 0)? 1 : 0) +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_SET_BITMAP(bitmap, mask_bitmap) (bitmap = ((bitmap) | (mask_bitmap))) +#define HAL_DAWN_PKT_CLR_BITMAP(bitmap, mask_bitmap) (bitmap = ((bitmap) & (~(mask_bitmap)))) +/*---------------------------------------------------------------------------*/ +#define HAL_DAWN_PKT_GET_TX_INTR_TYPE(channel) (HAL_INTR_TX_CH0 + channel) +#define HAL_DAWN_PKT_GET_RX_INTR_TYPE(channel) (HAL_INTR_RX_CH0 + channel) + +/* DATA TYPE DECLARATIONS + */ +typedef enum +{ + HAL_DAWN_PKT_TX_WAIT_ASYNC = 0, + HAL_DAWN_PKT_TX_WAIT_SYNC_INTR = 1, + HAL_DAWN_PKT_TX_WAIT_SYNC_POLL = 2 + +} HAL_DAWN_PKT_TX_WAIT_T; + +typedef enum +{ + HAL_DAWN_PKT_RX_SCHED_RR = 0, + HAL_DAWN_PKT_RX_SCHED_WRR = 1 + +} HAL_DAWN_PKT_RX_SCHED_T; + +/* GPD and Packet Strucutre Definition */ +#if defined(CLX_EN_BIG_ENDIAN) + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T ecn : 2; + UI32_T store_and_forward : 1; + UI32_T lag_epoch : 1; + UI32_T src_supp_tag : 5; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T fab_one_arm_rte : 1; + UI32_T skip_ipp : 1; + UI32_T igr_fab_port_grp : 1; + /* CLX DWORD 3 */ + UI32_T : 2; + UI32_T nvo3_mgid :15; + UI32_T nvo3_intf :14; + UI32_T nvo3_src_supp_tag_w0 : 1; + /* CLX DWORD 4 */ + UI32_T nvo3_src_supp_tag_w1 : 4; + UI32_T mir_bmap : 8; + UI32_T cp_to_cpu_code : 4; + UI32_T cp_to_cpu_bmap :16; +} HAL_DAWN_PKT_ITMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T ecn : 2; + UI32_T store_and_forward : 1; + UI32_T lag_epoch : 1; + UI32_T src_supp_tag : 5; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T fab_one_arm_rte : 1; + UI32_T : 2; + /* CLX DWORD 3 */ + UI32_T :32; + /* CLX DWORD 4 */ + UI32_T :20; + UI32_T had_uturn : 1; + UI32_T : 2; + UI32_T excpt_code : 8; + UI32_T exp_dscp_mrkd : 1; +} HAL_DAWN_PKT_ETMH_FAB_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T ecn : 2; + UI32_T igr_fab_port_grp : 1; + UI32_T redir : 1; + UI32_T excpt_code_mir_bmap : 8; + UI32_T cp_to_cpu_bmap_w0 : 1; + /* CLX DWORD 3 */ + UI32_T cp_to_cpu_bmap_w1 : 7; + UI32_T egr_phy_port :12; + UI32_T src_supp_pnd : 1; + UI32_T mc_vid_ctl : 3; + UI32_T mc_vid_1st_w0 : 9; + /* CLX DWORD 4 */ + UI32_T mc_vid_1st_w1 : 3; + UI32_T mc_vid_2nd :12; + UI32_T mc_decr_ttl : 1; + UI32_T mc_is_routed : 1; + UI32_T mc_mel_vld : 1; + UI32_T mc_cp_idx :13; + UI32_T exp_dscp_mrkd : 1; +} HAL_DAWN_PKT_ETMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T mpls_pw_cw_vld : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T seg_vmid_w0 :17; + /* CLX DWORD 2 */ + UI32_T seg_vmid_w1 : 7; + UI32_T : 1; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T vid_ctl : 3; + UI32_T vid_1st :12; + UI32_T vid_2nd_w0 : 7; + /* CLX DWORD 3 */ + UI32_T vid_2nd_w1 : 5; + UI32_T flw_lbl :10; + UI32_T rewr_idx_ctl : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_1_w0 : 2; + /* CLX DWORD 4 */ + UI32_T rewr_idx_1_w1 :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts :16; +} HAL_DAWN_PKT_PPH_L2_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T mpls_pw_cw_vld : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T seg_vmid_w0 :17; + /* CLX DWORD 2 */ + UI32_T seg_vmid_w1 : 7; + UI32_T : 1; + UI32_T rpf_pnd : 1; + UI32_T adj_idx :18; + UI32_T is_mc : 1; + UI32_T decr_ttl : 1; + UI32_T decap_prop_ttl : 1; + UI32_T mrk_dscp_en : 1; + UI32_T mrk_dscp_val_w0 : 1; + /* CLX DWORD 3 */ + UI32_T mrk_dscp_val_w1 : 5; + UI32_T flw_lbl :10; + UI32_T rewr_idx_ctl : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_1_w0 : 2; + /* CLX DWORD 4 */ + UI32_T rewr_idx_1_w1 :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts :16; +} HAL_DAWN_PKT_PPH_L3UC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T mpls_pw_cw_vld : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T vid_1st :12; + UI32_T vid_2nd_w0 : 5; + /* CLX DWORD 2 */ + UI32_T vid_2nd_w1 : 7; + UI32_T :15; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T vid_ctl : 3; + UI32_T is_mc : 1; + UI32_T : 1; + UI32_T decap_prop_ttl : 1; + UI32_T mrk_dscp_en : 1; + UI32_T mrk_dscp_val_w0 : 1; + /* CLX DWORD 3 */ + UI32_T mrk_dscp_val_w1 : 5; + UI32_T flw_lbl :10; + UI32_T rewr_idx_ctl : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_1_w0 : 2; + /* CLX DWORD 4 */ + UI32_T rewr_idx_1_w1 :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts :16; +} HAL_DAWN_PKT_PPH_L3MC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T seg_vmid_w0 :17; + /* CLX DWORD 2 */ + UI32_T seg_vmid_w1 : 7; + UI32_T : 2; + UI32_T adj_idx :18; + UI32_T : 1; + UI32_T decr_ttl : 1; + UI32_T decap_prop_ttl : 1; + UI32_T mrk_exp_en : 1; + UI32_T : 1; + /* CLX DWORD 3 */ + UI32_T : 2; + UI32_T mrk_exp_val : 3; + UI32_T php_pop_keep_inner_qos : 1; + UI32_T :26; + /* CLX DWORD 4 */ + UI32_T :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts :16; +} HAL_DAWN_PKT_PPH_L25_T; + +#elif defined(CLX_EN_LITTLE_ENDIAN) + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T igr_fab_port_grp : 1; + UI32_T skip_ipp : 1; + UI32_T fab_one_arm_rte : 1; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T src_supp_tag : 5; + UI32_T lag_epoch : 1; + UI32_T store_and_forward : 1; + UI32_T ecn : 2; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T nvo3_src_supp_tag_w0 : 1; + UI32_T nvo3_intf :14; + UI32_T nvo3_mgid :15; + UI32_T : 2; + /* CLX DWORD 4 */ + UI32_T cp_to_cpu_bmap :16; + UI32_T cp_to_cpu_code : 4; + UI32_T mir_bmap : 8; + UI32_T nvo3_src_supp_tag_w1 : 4; +} HAL_DAWN_PKT_ITMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T : 2; + UI32_T fab_one_arm_rte : 1; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T src_supp_tag : 5; + UI32_T lag_epoch : 1; + UI32_T store_and_forward : 1; + UI32_T ecn : 2; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T :32; + /* CLX DWORD 4 */ + UI32_T exp_dscp_mrkd : 1; + UI32_T excpt_code : 8; + UI32_T : 2; + UI32_T had_uturn : 1; + UI32_T :20; +} HAL_DAWN_PKT_ETMH_FAB_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T cp_to_cpu_bmap_w0 : 1; + UI32_T excpt_code_mir_bmap : 8; + UI32_T redir : 1; + UI32_T igr_fab_port_grp : 1; + UI32_T ecn : 2; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T mc_vid_1st_w0 : 9; + UI32_T mc_vid_ctl : 3; + UI32_T src_supp_pnd : 1; + UI32_T egr_phy_port :12; + UI32_T cp_to_cpu_bmap_w1 : 7; + /* CLX DWORD 4 */ + UI32_T exp_dscp_mrkd : 1; + UI32_T mc_cp_idx :13; + UI32_T mc_mel_vld : 1; + UI32_T mc_is_routed : 1; + UI32_T mc_decr_ttl : 1; + UI32_T mc_vid_2nd :12; + UI32_T mc_vid_1st_w1 : 3; +} HAL_DAWN_PKT_ETMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T mpls_pw_cw_vld : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T seg_vmid_w0 :17; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T vid_2nd_w0 : 7; + UI32_T vid_1st :12; + UI32_T vid_ctl : 3; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T : 1; + UI32_T seg_vmid_w1 : 7; + /* CLX DWORD 3 */ + UI32_T rewr_idx_1_w0 : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_ctl : 2; + UI32_T flw_lbl :10; + UI32_T vid_2nd_w1 : 5; + /* CLX DWORD 4 */ + UI32_T ts :16; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T rewr_idx_1_w1 :11; +} HAL_DAWN_PKT_PPH_L2_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T mpls_pw_cw_vld : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T seg_vmid_w0 :17; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T mrk_dscp_val_w0 : 1; + UI32_T mrk_dscp_en : 1; + UI32_T decap_prop_ttl : 1; + UI32_T decr_ttl : 1; + UI32_T is_mc : 1; + UI32_T adj_idx :18; + UI32_T rpf_pnd : 1; + UI32_T : 1; + UI32_T seg_vmid_w1 : 7; + /* CLX DWORD 3 */ + UI32_T rewr_idx_1_w0 : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_ctl : 2; + UI32_T flw_lbl :10; + UI32_T mrk_dscp_val_w1 : 5; + /* CLX DWORD 4 */ + UI32_T ts :16; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T rewr_idx_1_w1 :11; +} HAL_DAWN_PKT_PPH_L3UC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T mpls_pw_cw_vld : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T vid_2nd_w0 : 5; + UI32_T vid_1st :12; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T mrk_dscp_val_w0 : 1; + UI32_T mrk_dscp_en : 1; + UI32_T decap_prop_ttl : 1; + UI32_T : 1; + UI32_T is_mc : 1; + UI32_T vid_ctl : 3; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T :15; + UI32_T vid_2nd_w1 : 7; + /* CLX DWORD 3 */ + UI32_T rewr_idx_1_w0 : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_ctl : 2; + UI32_T flw_lbl :10; + UI32_T mrk_dscp_val_w1 : 5; + /* CLX DWORD 4 */ + UI32_T ts :16; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T rewr_idx_1_w1 :11; +} HAL_DAWN_PKT_PPH_L3MC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T seg_vmid_w0 :17; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T : 1; + UI32_T mrk_exp_en : 1; + UI32_T decap_prop_ttl : 1; + UI32_T decr_ttl : 1; + UI32_T : 1; + UI32_T adj_idx :18; + UI32_T : 2; + UI32_T seg_vmid_w1 : 7; + /* CLX DWORD 3 */ + UI32_T :26; + UI32_T php_pop_keep_inner_qos : 1; + UI32_T mrk_exp_val : 3; + UI32_T : 2; + /* CLX DWORD 4 */ + UI32_T ts :16; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T :11; +} HAL_DAWN_PKT_PPH_L25_T; + +#else +#error "Host GPD endian is not defined!!\n" +#endif + +#if defined(CLX_EN_BIG_ENDIAN) + +/* RX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T chksum : 16; + UI32_T ioc : 1; + UI32_T : 1; + UI32_T avbl_buf_len : 14; + UI32_T : 32; + + union + { + HAL_DAWN_PKT_ITMH_ETH_T itmh_eth; + HAL_DAWN_PKT_ETMH_FAB_T etmh_fab; + HAL_DAWN_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_DAWN_PKT_PPH_L2_T pph_l2; + HAL_DAWN_PKT_PPH_L3UC_T pph_l3uc; + HAL_DAWN_PKT_PPH_L3MC_T pph_l3mc; + HAL_DAWN_PKT_PPH_L25_T pph_l25; + }; + + UI32_T : 32; + UI32_T hwo : 1; + UI32_T ch : 1; + UI32_T trn : 1; + UI32_T ecce : 1; + UI32_T errf : 1; + UI32_T : 5; + UI32_T queue : 6; + UI32_T : 2; + UI32_T cnsm_buf_len : 14; + +} HAL_DAWN_PKT_RX_GPD_T; + +/* TX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T chksum : 16; + UI32_T ioc : 1; + UI32_T : 1; + UI32_T data_buf_size : 14; + UI32_T : 32; + + union + { + HAL_DAWN_PKT_ITMH_ETH_T itmh_eth; + HAL_DAWN_PKT_ETMH_FAB_T etmh_fab; + HAL_DAWN_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_DAWN_PKT_PPH_L2_T pph_l2; + HAL_DAWN_PKT_PPH_L3UC_T pph_l3uc; + HAL_DAWN_PKT_PPH_L3MC_T pph_l3mc; + HAL_DAWN_PKT_PPH_L25_T pph_l25; + }; + + UI32_T : 16; + UI32_T ptp_hdr : 16; + UI32_T hwo : 1; + UI32_T ch : 1; + UI32_T : 1; + UI32_T ecce : 1; + UI32_T : 4; + UI32_T cos : 3; + UI32_T phc : 1; /* PTP Header Control */ + UI32_T ipc : 2; /* Ingress Plane Control */ + UI32_T crcc : 1; + UI32_T prg : 1; /* Purge */ + UI32_T : 2; + UI32_T pkt_len : 14; /* Total packet length */ + +} HAL_DAWN_PKT_TX_GPD_T; + +#elif defined(CLX_EN_LITTLE_ENDIAN) + +/* RX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T avbl_buf_len : 14; + UI32_T : 1; + UI32_T ioc : 1; + UI32_T chksum : 16; + UI32_T : 32; + + union + { + HAL_DAWN_PKT_ITMH_ETH_T itmh_eth; + HAL_DAWN_PKT_ETMH_FAB_T etmh_fab; + HAL_DAWN_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_DAWN_PKT_PPH_L2_T pph_l2; + HAL_DAWN_PKT_PPH_L3UC_T pph_l3uc; + HAL_DAWN_PKT_PPH_L3MC_T pph_l3mc; + HAL_DAWN_PKT_PPH_L25_T pph_l25; + }; + + UI32_T : 32; + UI32_T cnsm_buf_len : 14; + UI32_T : 2; + UI32_T queue : 6; + UI32_T : 5; + UI32_T errf : 1; + UI32_T ecce : 1; + UI32_T trn : 1; + UI32_T ch : 1; + UI32_T hwo : 1; + +} HAL_DAWN_PKT_RX_GPD_T; + +/* TX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T data_buf_size : 14; + UI32_T : 1; + UI32_T ioc : 1; + UI32_T chksum : 16; + UI32_T : 32; + + union + { + HAL_DAWN_PKT_ITMH_ETH_T itmh_eth; + HAL_DAWN_PKT_ETMH_FAB_T etmh_fab; + HAL_DAWN_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_DAWN_PKT_PPH_L2_T pph_l2; + HAL_DAWN_PKT_PPH_L3UC_T pph_l3uc; + HAL_DAWN_PKT_PPH_L3MC_T pph_l3mc; + HAL_DAWN_PKT_PPH_L25_T pph_l25; + }; + + UI32_T ptp_hdr : 16; + UI32_T : 16; + UI32_T pkt_len : 14; /* Total packet length */ + UI32_T : 2; + UI32_T prg : 1; /* Purge */ + UI32_T crcc : 1; + UI32_T ipc : 2; /* Ingress Plane Control */ + UI32_T phc : 1; /* PTP Header Control */ + UI32_T cos : 3; + UI32_T : 4; + UI32_T ecce : 1; + UI32_T : 1; + UI32_T ch : 1; + UI32_T hwo : 1; +} HAL_DAWN_PKT_TX_GPD_T; + +#else +#error "Host GPD endian is not defined\n" +#endif + +/* ----------------------------------------------------------------------------------- PP Type */ +typedef enum +{ + HAL_DAWN_PKT_TMH_TYPE_ITMH_ETH = 0, + HAL_DAWN_PKT_TMH_TYPE_ITMH_FAB, + HAL_DAWN_PKT_TMH_TYPE_ETMH_FAB, + HAL_DAWN_PKT_TMH_TYPE_ETMH_ETH, + HAL_DAWN_PKT_TMH_TYPE_LAST + +} HAL_DAWN_PKT_TMH_TYPE_T; + +typedef enum +{ + HAL_DAWN_PKT_TMH_SRV_L2 = 0, + HAL_DAWN_PKT_TMH_SRV_L25_MPLS, + HAL_DAWN_PKT_TMH_SRV_L3, + HAL_DAWN_PKT_TMH_SRV_EGR, /* L3 downgrade L2 */ + HAL_DAWN_PKT_TMH_SRV_L25_NSH, + HAL_DAWN_PKT_TMH_SRV_L25_TRILL, + HAL_DAWN_PKT_TMH_SRV_LAST + +} HAL_DAWN_PKT_TMH_SRV_T; + +typedef enum +{ + HAL_DAWN_PKT_TMH_DECAP_NONE = 0, + HAL_DAWN_PKT_TMH_DECAP_1_MPLS_LABEL, + HAL_DAWN_PKT_TMH_DECAP_2_MPLS_LABEL, + HAL_DAWN_PKT_TMH_DECAP_3_MPLS_LABEL, + HAL_DAWN_PKT_TMH_DECAP_4_MPLS_LABEL, + HAL_DAWN_PKT_TMH_DECAP_IP_TRILL_NSH, + HAL_DAWN_PKT_TMH_DECAP_LAST + +} HAL_DAWN_PKT_TMH_DECAP_T; + +typedef struct +{ + union + { + HAL_DAWN_PKT_ITMH_ETH_T itmh_eth; + HAL_DAWN_PKT_ETMH_FAB_T etmh_fab; + HAL_DAWN_PKT_ETMH_ETH_T etmh_eth; + }; +} HAL_DAWN_PKT_TMH_T; + +typedef struct +{ + union + { + HAL_DAWN_PKT_PPH_L2_T pph_l2; + HAL_DAWN_PKT_PPH_L3UC_T pph_l3uc; + HAL_DAWN_PKT_PPH_L3MC_T pph_l3mc; + HAL_DAWN_PKT_PPH_L25_T pph_l25; + }; +} HAL_DAWN_PKT_PPH_T; + +/* ----------------------------------------------------------------------------------- Reg Type */ +typedef enum +{ + HAL_DAWN_PKT_L2_ISR_RCH0 = (0x1UL << 0), + HAL_DAWN_PKT_L2_ISR_RCH1 = (0x1UL << 1), + HAL_DAWN_PKT_L2_ISR_RCH2 = (0x1UL << 2), + HAL_DAWN_PKT_L2_ISR_RCH3 = (0x1UL << 3), + HAL_DAWN_PKT_L2_ISR_TCH0 = (0x1UL << 4), + HAL_DAWN_PKT_L2_ISR_TCH1 = (0x1UL << 5), + HAL_DAWN_PKT_L2_ISR_TCH2 = (0x1UL << 6), + HAL_DAWN_PKT_L2_ISR_TCH3 = (0x1UL << 7), + HAL_DAWN_PKT_L2_ISR_RX_QID_MAP_ERR = (0x1UL << 8), + HAL_DAWN_PKT_L2_ISR_RX_FRAME_ERR = (0x1UL << 9) + +} HAL_DAWN_PKT_L2_ISR_T; + +typedef enum +{ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR = (0x1UL << 0), /* Tx GPD.hwo = 0 */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR = (0x1UL << 1), /* Tx GPD.chksm is error */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR = (0x1UL << 2), /* S/W push too much GPD */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR = (0x1UL << 3), /* AXI Rd Error when do GPD read */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR = (0x1UL << 4), /* Tx GPD.data_buf_size = 0 */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR = (0x1UL << 5), /* Tx GPD.pkt_len < 64 */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR = (0x1UL << 6), /* Tx GPD.pkt_len = 9217 */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR = (0x1UL << 7), /* Tx GPD.pkt_len != sum of data_buf_size */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR = (0x1UL << 8), /* AXI Rd Error when do Payload read */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_COS_ERROR = (0x1UL << 9), /* Tx GPD.cos is not match cos_to_tch_map */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR = (0x1UL << 10), /* Multi-GPD packet's GPD# > 255 */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_PFC = (0x1UL << 11), /* */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR = (0x1UL << 12), /* Credit Underflow (count down to 0) */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR = (0x1UL << 13), /* AXI Wr Error (GPD Write-Back) */ + HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT = (0x1UL << 14) + +} HAL_DAWN_PKT_TX_CHANNEL_L2_ISR_T; + +typedef enum +{ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW = (0x1UL << 0), /* Rx GPD.avbl_gpd_num < threshold */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY = (0x1UL << 1), /* Rx GPD.avbl_gpd_num = 0 */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR = (0x1UL << 2), /* Rx GPD.hwo = 0 */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR = (0x1UL << 3), /* Rx GPD.chksm is error */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR = (0x1UL << 4), /* DMAR error occurs in PCIE */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR = (0x1UL << 5), /* DMAW error occurs in PCIE */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT = (0x1UL << 6), /* Stop Completion Acknowledge */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR = (0x1UL << 7), /* Multi-GPD packet's GPD# > 255 */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT = (0x1UL << 8), /* */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP = (0x1UL << 9), /* */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP = (0x1UL << 10), /* */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP = (0x1UL << 11), /* */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP = (0x1UL << 12), /* */ + HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP = (0x1UL << 13) + +} HAL_DAWN_PKT_RX_CHANNEL_L2_ISR_T; + +typedef enum +{ + HAL_DAWN_PKT_TX_CHANNEL_CFG_IOC = (0x1UL << 0), + HAL_DAWN_PKT_TX_CHANNEL_CFG_CHKSUM = (0x1UL << 1), + HAL_DAWN_PKT_TX_CHANNEL_CFG_PFC = (0x1UL << 2), + HAL_DAWN_PKT_TX_CHANNEL_CFG_PKT_LEN_CHK = (0x1UL << 3), + HAL_DAWN_PKT_TX_CHANNEL_CFG_EARLY_DONE_IRQ = (0x1UL << 4), + HAL_DAWN_PKT_TX_CHANNEL_CFG_CHK_COS = (0x1UL << 5), + HAL_DAWN_PKT_TX_CHANNEL_CFG_ADV_GPD_WRBK = (0x1UL << 6), + HAL_DAWN_PKT_TX_CHANNEL_CFG_GPD_WRBK_FULL_PKT_LEN = (0x1UL << 7), + HAL_DAWN_PKT_TX_CHANNEL_CFG_LAST = (0x1UL << 8) + +} HAL_DAWN_PKT_TX_CHANNEL_CFG_T; + +typedef enum +{ + HAL_DAWN_PKT_RX_CHANNEL_CFG_IOC = (0x1UL << 0), + HAL_DAWN_PKT_RX_CHANNEL_CFG_CHKSUM = (0x1UL << 1), + HAL_DAWN_PKT_RX_CHANNEL_CFG_LAST = (0x1UL << 2) + +} HAL_DAWN_PKT_RX_CHANNEL_CFG_T; + +/* ----------------------------------------------------------------------------------- Tx */ +typedef enum +{ + HAL_DAWN_PKT_TX_CHANNEL_0 = 0, + HAL_DAWN_PKT_TX_CHANNEL_1, + HAL_DAWN_PKT_TX_CHANNEL_2, + HAL_DAWN_PKT_TX_CHANNEL_3, + HAL_DAWN_PKT_TX_CHANNEL_LAST + +} HAL_DAWN_PKT_TX_CHANNEL_T; + +typedef void +(*HAL_DAWN_PKT_TX_FUNC_T)( + const UI32_T unit, + const void *ptr_sw_gpd, /* SW-GPD to be processed */ + void *ptr_coockie); /* Private data of SDK */ + +typedef struct HAL_DAWN_PKT_TX_SW_GPD_S +{ + HAL_DAWN_PKT_TX_FUNC_T callback; /* (unit, ptr_sw_gpd, ptr_cookie) */ + void *ptr_cookie; /* Pointer of CLX_PKT_TX_PKT_T */ + HAL_DAWN_PKT_TX_GPD_T tx_gpd; + UI32_T gpd_num; + struct HAL_DAWN_PKT_TX_SW_GPD_S *ptr_next; + +#if defined (CLX_EN_NETIF) + UI32_T channel; /* For counter */ +#endif + +} HAL_DAWN_PKT_TX_SW_GPD_T; + +typedef struct +{ + UI32_T send_ok; + UI32_T gpd_empty; + UI32_T poll_timeout; + + /* queue */ + UI32_T enque_ok; + UI32_T enque_retry; + + /* event */ + UI32_T trig_event; + + /* normal interrupt */ + UI32_T tx_done; + + /* abnormal interrupt */ + UI32_T gpd_hwo_err; /* bit-0 */ + UI32_T gpd_chksm_err; /* bit-1 */ + UI32_T gpd_no_ovfl_err; /* bit-2 */ + UI32_T gpd_dma_read_err; /* bit-3 */ + UI32_T buf_size_err; /* bit-4 */ + UI32_T runt_err; /* bit-5 */ + UI32_T ovsz_err; /* bit-6 */ + UI32_T len_mismatch_err; /* bit-7 */ + UI32_T pktpl_dma_read_err; /* bit-8 */ + UI32_T cos_err; /* bit-9 */ + UI32_T gpd_gt255_err; /* bit-10 */ + UI32_T pfc; /* bit-11 */ + UI32_T credit_udfl_err; /* bit-12 */ + UI32_T dma_write_err; /* bit-13 */ + UI32_T sw_issue_stop; /* bit-14 */ + + /* others */ + UI32_T err_recover; + UI32_T ecc_err; + +} HAL_DAWN_PKT_TX_CHANNEL_CNT_T; + +typedef struct +{ + HAL_DAWN_PKT_TX_CHANNEL_CNT_T channel[HAL_DAWN_PKT_TX_CHANNEL_LAST]; + UI32_T invoke_gpd_callback; + UI32_T no_memory; + + /* queue */ + UI32_T deque_ok; + UI32_T deque_fail; + + /* event */ + UI32_T wait_event; + +} HAL_DAWN_PKT_TX_CNT_T; + +/* ----------------------------------------------------------------------------------- Rx */ +typedef enum +{ + HAL_DAWN_PKT_RX_CHANNEL_0 = 0, + HAL_DAWN_PKT_RX_CHANNEL_1, + HAL_DAWN_PKT_RX_CHANNEL_2, + HAL_DAWN_PKT_RX_CHANNEL_3, + HAL_DAWN_PKT_RX_CHANNEL_LAST +} HAL_DAWN_PKT_RX_CHANNEL_T; + +typedef enum +{ + HAL_DAWN_PKT_C_NEXT = 0, /* callback continuous */ + HAL_DAWN_PKT_C_STOP = 1, + HAL_DAWN_PKT_C_OTHERS = 2 +} HAL_DAWN_PKT_CALLBACK_NO_T; + +typedef enum +{ + HAL_DAWN_PKT_RX_CALLBACK_ACTION_INSERT = 0, + HAL_DAWN_PKT_RX_CALLBACK_ACTION_APPEND = 1, + HAL_DAWN_PKT_RX_CALLBACK_ACTION_DELETE = 2, + HAL_DAWN_PKT_RX_CALLBACK_ACTION_DELETE_ALL = 3 +} HAL_DAWN_PKT_RX_CALLBACK_ACTION_T; + +typedef HAL_DAWN_PKT_CALLBACK_NO_T +(*HAL_DAWN_PKT_RX_FUNC_T)( + const UI32_T unit, + const void *ptr_sw_gpd, /* SW-GPD to be processed */ + void *ptr_cookie); /* Private data of SDK */ + +typedef struct HAL_DAWN_PKT_RX_CALLBACK_S +{ + HAL_DAWN_PKT_RX_FUNC_T callback; /* (unit, ptr_sw_gpd, ptr_cookie) */ + void *ptr_cookie; + struct HAL_DAWN_PKT_RX_CALLBACK_S *ptr_next; +} HAL_DAWN_PKT_RX_CALLBACK_T; + +typedef struct HAL_DAWN_PKT_RX_SW_GPD_S +{ + BOOL_T rx_complete; /* FALSE when PDMA error occurs */ + HAL_DAWN_PKT_RX_GPD_T rx_gpd; + struct HAL_DAWN_PKT_RX_SW_GPD_S *ptr_next; + +#if defined (CLX_EN_NETIF) + void *ptr_cookie; /* Pointer of virt-addr */ +#endif + +} HAL_DAWN_PKT_RX_SW_GPD_T; + +typedef struct +{ + /* queue */ + UI32_T enque_ok; + UI32_T enque_retry; + UI32_T deque_ok; + UI32_T deque_fail; + + /* event */ + UI32_T trig_event; + + /* normal interrupt */ + UI32_T rx_done; + + /* abnormal interrupt */ + UI32_T avbl_gpd_low; /* bit-0 */ + UI32_T avbl_gpd_empty; /* bit-1 */ + UI32_T avbl_gpd_err; /* bit-2 */ + UI32_T gpd_chksm_err; /* bit-3 */ + UI32_T dma_read_err; /* bit-4 */ + UI32_T dma_write_err; /* bit-5 */ + UI32_T sw_issue_stop; /* bit-6 */ + UI32_T gpd_gt255_err; /* bit-7 */ + UI32_T tod_uninit; /* bit-8 */ + UI32_T pkt_err_drop; /* bit-9 */ + UI32_T udsz_drop; /* bit-10 */ + UI32_T ovsz_drop; /* bit-11 */ + UI32_T cmdq_ovf_drop; /* bit-12 */ + UI32_T fifo_ovf_drop; /* bit-13 */ + + /* others */ + UI32_T err_recover; + UI32_T ecc_err; + +#if defined (CLX_EN_NETIF) + /* it means that user doesn't create intf on that port */ + UI32_T netdev_miss; +#endif + + +} HAL_DAWN_PKT_RX_CHANNEL_CNT_T; + +typedef struct +{ + HAL_DAWN_PKT_RX_CHANNEL_CNT_T channel[HAL_DAWN_PKT_RX_CHANNEL_LAST]; + UI32_T invoke_gpd_callback; + UI32_T no_memory; + + /* event */ + UI32_T wait_event; + +} HAL_DAWN_PKT_RX_CNT_T; + +/* ----------------------------------------------------------------------------------- Reg */ +#if defined(CLX_EN_LITTLE_ENDIAN) + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_axlen_cfg : 3; + UI32_T : 5; + UI32_T tch_axi_free_arvalid : 1; + UI32_T : 7; + UI32_T tch_arvalid_thrhold_cfg : 2; + UI32_T : 6; + UI32_T tch_rready_low_4_hdr : 1; + UI32_T tch_ios_crdt_add_en : 1; + UI32_T : 6; + } field; +} HAL_DAWN_PKT_AXI_LEN_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_lbk_en : 1; + UI32_T : 3; + UI32_T pdma_lbk_plane : 2; + UI32_T : 2; + UI32_T pm_lbk_en : 1; + UI32_T : 7; + UI32_T pm_lbk_rqid : 6; + UI32_T : 2; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_LBK_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_lbk_rqid0 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid1 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid2 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid3 : 6; + UI32_T : 2; + } field; +} HAL_DAWN_PKT_LBK_RQID0_3_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_lbk_rqid4 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid5 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid6 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid7 : 6; + UI32_T : 2; + } field; +} HAL_DAWN_PKT_LBK_RQID4_7_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T cos_pfc_sts0 : 8; + UI32_T cos_pfc_sts1 : 8; + UI32_T cos_pfc_sts2 : 8; + UI32_T cos_pfc_sts3 : 8; + } field; +} HAL_DAWN_PKT_COS_PFC_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_ela_en : 1; + UI32_T : 7; + UI32_T pdma_ela_valid_sel : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_ELA_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_ela_word0_sel : 8; + UI32_T pdma_ela_word1_sel : 8; + UI32_T pdma_ela_word2_sel : 8; + UI32_T pdma_ela_word3_sel : 8; + } field; +} HAL_DAWN_PKT_ELA_SEL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T ingr_pln_ios_credit_base_size_lo : 8; + UI32_T ingr_pln_ios_credit_base_size_hi : 8; + UI32_T ingr_pln_ios_credit_set : 1; + UI32_T : 7; + UI32_T : 1; + UI32_T ingr_pln_full_pkt_mode : 1; + UI32_T : 6; + } field; +} HAL_DAWN_PKT_IGR_PLN_CREDIT_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T ingr_pln_cur_ios_credit_lo : 8; + UI32_T ingr_pln_cur_ios_credit_hi : 8; + UI32_T ingr_pln_ios_credit_ovfl : 1; + UI32_T ingr_pln_ios_credit_udfl : 1; + UI32_T : 6; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_IGR_PLN_CREDIT_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T ingr_pln_ios_credit_rdy_lo_bound : 8; + UI32_T ingr_pln_ios_credit_rdy_hi_bound : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_IGR_PLN_CREDIT_THR_REG_T; + + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_stomp_crc_en : 1; + UI32_T : 7; + UI32_T rch_crc_regen_en : 1; + UI32_T : 7; + UI32_T rch_pfc_fun_en : 1; + UI32_T : 7; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_RCH_STOMP_CRC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_ioc_en : 1; + UI32_T : 7; + UI32_T rch_chksm_en : 1; + UI32_T : 7; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_RCH_MISC_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_gpd_pfc_lo : 8; + UI32_T rch_gpd_pfc_hi : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_RCH_GPD_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_fifo_pfc_lo_lo : 8; + UI32_T rch_fifo_pfc_lo_hi : 3; + UI32_T : 5; + UI32_T rch_fifo_pfc_hi_lo : 8; + UI32_T rch_fifo_pfc_hi_hi : 3; + UI32_T : 5; + } field; +} HAL_DAWN_PKT_RCH_FIFO_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_cmdq_pfc_lo : 5; + UI32_T : 3; + UI32_T rch_cmdq_pfc_hi : 5; + UI32_T : 3; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_RCH_CMDQ_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_start : 1; + UI32_T rch_resume : 1; + UI32_T rch_stop : 1; + UI32_T : 5; + UI32_T : 8; + UI32_T rch_gpd_add_no_lo : 8; + UI32_T rch_gpd_add_no_hi : 8; + } field; +} HAL_DAWN_PKT_RCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_fifo_ovf_drop_cnt_clr : 1; + UI32_T rch_cmdq_ovf_drop_cnt_clr : 1; + UI32_T rch_ovsz_drop_cnt_clr : 1; + UI32_T rch_udsz_drop_cnt_clr : 1; + UI32_T rch_pkterr_drop_cnt_clr : 1; + UI32_T rch_flush_cnt_clr : 1; + UI32_T : 2; + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_RCH_CNT_CLR_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_active : 1; + UI32_T rch_avbl_gpd_pfc : 1; + UI32_T rch_fifo_pfc : 1; + UI32_T rch_cmdq_pfc : 1; + UI32_T rch_pfc : 1; + UI32_T : 3; + UI32_T : 8; + UI32_T rch_avbl_gpd_no_lo : 8; + UI32_T rch_avbl_gpd_no_hi : 8; + } field; +} HAL_DAWN_PKT_RCH_STATUS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_ioc_en : 1; + UI32_T tch_chksm_en : 1; + UI32_T tch_pfc_en : 1; + UI32_T tch_pktlen_chk_en : 1; + UI32_T tch_early_done_irq : 1; + UI32_T tch_chk_cos_en : 1; + UI32_T tch_adv_gpd_wrbk : 1; + UI32_T tch_gpd_wrbk_full_pkt_len : 1; + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_TCH_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_start : 1; + UI32_T tch_resume : 1; + UI32_T tch_stop : 1; + UI32_T : 5; + UI32_T : 8; + UI32_T tch_gpd_add_no_lo : 8; + UI32_T tch_gpd_add_no_hi : 8; + } field; +} HAL_DAWN_PKT_TCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_active : 1; + UI32_T tch_pfc : 1; + UI32_T tch_gpd_rd_dma_act : 1; + UI32_T : 5; + UI32_T : 8; + UI32_T tch_avbl_gpd_no : 1; + UI32_T : 7; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_TCH_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_gpd_dmar_qos : 4; + UI32_T : 4; + UI32_T tch_pkt_dmar_qos : 4; + UI32_T : 4; + UI32_T tch_gpd_dmaw_qos : 4; + UI32_T : 4; + UI32_T : 8; + } field; +} HAL_DAWN_PKT_TCH_QOS_CFG_REG_T; + +#elif defined(CLX_EN_BIG_ENDIAN) + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 6; + UI32_T tch_ios_crdt_add_en : 1; + UI32_T tch_rready_low_4_hdr : 1; + UI32_T : 6; + UI32_T tch_arvalid_thrhold_cfg : 2; + UI32_T : 7; + UI32_T tch_axi_free_arvalid : 1; + UI32_T : 5; + UI32_T tch_axlen_cfg : 3; + } field; +} HAL_DAWN_PKT_AXI_LEN_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 2; + UI32_T pm_lbk_rqid : 6; + UI32_T : 7; + UI32_T pm_lbk_en : 1; + UI32_T : 2; + UI32_T pdma_lbk_plane : 2; + UI32_T : 3; + UI32_T pdma_lbk_en : 1; + } field; +} HAL_DAWN_PKT_LBK_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 2; + UI32_T pdma_lbk_rqid3 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid2 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid1 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid0 : 6; + } field; +} HAL_DAWN_PKT_LBK_RQID0_3_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 2; + UI32_T pdma_lbk_rqid7 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid6 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid5 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid4 : 6; + } field; +} HAL_DAWN_PKT_LBK_RQID4_7_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T cos_pfc_sts3 : 8; + UI32_T cos_pfc_sts2 : 8; + UI32_T cos_pfc_sts1 : 8; + UI32_T cos_pfc_sts0 : 8; + } field; +} HAL_DAWN_PKT_COS_PFC_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T pdma_ela_valid_sel : 8; + UI32_T : 7; + UI32_T pdma_ela_en : 1; + } field; +} HAL_DAWN_PKT_ELA_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_ela_word3_sel : 8; + UI32_T pdma_ela_word2_sel : 8; + UI32_T pdma_ela_word1_sel : 8; + UI32_T pdma_ela_word0_sel : 8; + } field; +} HAL_DAWN_PKT_ELA_SEL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 6; + UI32_T ingr_pln_full_pkt_mode : 1; + UI32_T : 1; + UI32_T : 7; + UI32_T ingr_pln_ios_credit_set : 1; + UI32_T ingr_pln_ios_credit_base_size_hi : 8; + UI32_T ingr_pln_ios_credit_base_size_lo : 8; + } field; +} HAL_DAWN_PKT_IGR_PLN_CREDIT_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 6; + UI32_T ingr_pln_ios_credit_udfl : 1; + UI32_T ingr_pln_ios_credit_ovfl : 1; + UI32_T ingr_pln_cur_ios_credit_hi : 8; + UI32_T ingr_pln_cur_ios_credit_lo : 8; + } field; +} HAL_DAWN_PKT_IGR_PLN_CREDIT_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T ingr_pln_ios_credit_rdy_hi_bound : 8; + UI32_T ingr_pln_ios_credit_rdy_lo_bound : 8; + } field; +} HAL_DAWN_PKT_IGR_PLN_CREDIT_THR_REG_T; + + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 7; + UI32_T rch_pfc_fun_en : 1; + UI32_T : 7; + UI32_T rch_crc_regen_en : 1; + UI32_T : 7; + UI32_T rch_stomp_crc_en : 1; + } field; +} HAL_DAWN_PKT_RCH_STOMP_CRC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 7; + UI32_T rch_chksm_en : 1; + UI32_T : 7; + UI32_T rch_ioc_en : 1; + } field; +} HAL_DAWN_PKT_RCH_MISC_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T rch_gpd_pfc_hi : 8; + UI32_T rch_gpd_pfc_lo : 8; + } field; +} HAL_DAWN_PKT_RCH_GPD_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 5; + UI32_T rch_fifo_pfc_hi_hi : 3; + UI32_T rch_fifo_pfc_hi_lo : 8; + UI32_T : 5; + UI32_T rch_fifo_pfc_lo_hi : 3; + UI32_T rch_fifo_pfc_lo_lo : 8; + } field; +} HAL_DAWN_PKT_RCH_FIFO_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 3; + UI32_T rch_cmdq_pfc_hi : 5; + UI32_T : 3; + UI32_T rch_cmdq_pfc_lo : 5; + } field; +} HAL_DAWN_PKT_RCH_CMDQ_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_gpd_add_no_hi : 8; + UI32_T rch_gpd_add_no_lo : 8; + UI32_T : 8; + UI32_T : 5; + UI32_T rch_stop : 1; + UI32_T rch_resume : 1; + UI32_T rch_start : 1; + } field; +} HAL_DAWN_PKT_RCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + UI32_T : 2; + UI32_T rch_flush_cnt_clr : 1; + UI32_T rch_pkterr_drop_cnt_clr : 1; + UI32_T rch_udsz_drop_cnt_clr : 1; + UI32_T rch_ovsz_drop_cnt_clr : 1; + UI32_T rch_cmdq_ovf_drop_cnt_clr : 1; + UI32_T rch_fifo_ovf_drop_cnt_clr : 1; + } field; +} HAL_DAWN_PKT_RCH_CNT_CLR_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_avbl_gpd_no_hi : 8; + UI32_T rch_avbl_gpd_no_lo : 8; + UI32_T : 8; + UI32_T : 3; + UI32_T rch_pfc : 1; + UI32_T rch_cmdq_pfc : 1; + UI32_T rch_fifo_pfc : 1; + UI32_T rch_avbl_gpd_pfc : 1; + UI32_T rch_active : 1; + } field; +} HAL_DAWN_PKT_RCH_STATUS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + UI32_T tch_gpd_wrbk_full_pkt_len : 1; + UI32_T tch_adv_gpd_wrbk : 1; + UI32_T tch_chk_cos_en : 1; + UI32_T tch_early_done_irq : 1; + UI32_T tch_pktlen_chk_en : 1; + UI32_T tch_pfc_en : 1; + UI32_T tch_chksm_en : 1; + UI32_T tch_ioc_en : 1; + } field; +} HAL_DAWN_PKT_TCH_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_gpd_add_no_hi : 8; + UI32_T tch_gpd_add_no_lo : 8; + UI32_T : 8; + UI32_T : 5; + UI32_T tch_stop : 1; + UI32_T tch_resume : 1; + UI32_T tch_start : 1; + } field; +} HAL_DAWN_PKT_TCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 7; + UI32_T tch_avbl_gpd_no : 1; + UI32_T : 8; + UI32_T : 5; + UI32_T tch_gpd_rd_dma_act : 1; + UI32_T tch_pfc : 1; + UI32_T tch_active : 1; + } field; +} HAL_DAWN_PKT_TCH_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 4; + UI32_T tch_gpd_dmaw_qos : 4; + UI32_T : 4; + UI32_T tch_pkt_dmar_qos : 4; + UI32_T : 4; + UI32_T tch_gpd_dmar_qos : 4; + } field; +} HAL_DAWN_PKT_TCH_QOS_CFG_REG_T; + +#else +#error "Host GPD endian is not defined\n" +#endif + +/* ----------------------------------------------------------------------------------- CLX_EN_NETIF */ +#if defined (CLX_EN_NETIF) +#define HAL_DAWN_PKT_DRIVER_MAJOR_NUM (10) +#define HAL_DAWN_PKT_DRIVER_MINOR_NUM (252) /* DO NOT use MISC_DYNAMIC_MINOR */ +#define HAL_DAWN_PKT_DRIVER_NAME "clx_netif" +#define HAL_DAWN_PKT_DRIVER_PATH "/dev/"HAL_DAWN_PKT_DRIVER_NAME + +/* These requirements come from CLX_NETIF APIs. + * clx_netif -> hal_pkt_drv -> hal_pkt_knl + */ + +typedef struct +{ + UI32_T tx_pkt; + UI32_T tx_queue_full; + UI32_T tx_error; + UI32_T rx_pkt; + +} HAL_DAWN_PKT_NETIF_INTF_CNT_T; + +typedef struct +{ + /* unique key */ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + UI32_T port; /* only support unit port and local port */ + + /* metadata */ + UI8_T mac[6]; + +#define HAL_DAWN_PKT_NETIF_INTF_FLAGS_MAC (1UL << 0) + UI32_T flags; + + +} HAL_DAWN_PKT_NETIF_INTF_T; + +#if defined(NETIF_EN_NETLINK) +typedef struct +{ + C8_T name[CLX_NETIF_NAME_LEN]; + C8_T mc_group_name[CLX_NETIF_NAME_LEN]; +} HAL_DAWN_PKT_NETIF_RX_DST_NETLINK_T; +#endif + +typedef enum +{ + HAL_DAWN_PKT_NETIF_RX_DST_SDK = 0, +#if defined(NETIF_EN_NETLINK) + HAL_DAWN_PKT_NETIF_RX_DST_NETLINK, +#endif + HAL_DAWN_PKT_NETIF_RX_DST_LAST +} HAL_DAWN_PKT_NETIF_RX_DST_TYPE_T; + +typedef struct +{ + /* unique key */ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + UI32_T priority; + + /* match fields */ + UI32_T port; /* only support unit port and local port */ + HAL_PKT_RX_REASON_BITMAP_T reason_bitmap; + UI8_T pattern[CLX_NETIF_PROFILE_PATTERN_NUM][CLX_NETIF_PROFILE_PATTERN_LEN]; + UI8_T mask[CLX_NETIF_PROFILE_PATTERN_NUM][CLX_NETIF_PROFILE_PATTERN_LEN]; + UI32_T offset[CLX_NETIF_PROFILE_PATTERN_NUM]; + + /* for each flag 1:must hit, 0:don't care */ +#define HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PORT (1UL << 0) +#define HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_REASON (1UL << 1) +#define HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_0 (1UL << 2) +#define HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_1 (1UL << 3) +#define HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_2 (1UL << 4) +#define HAL_DAWN_PKT_NETIF_PROFILE_FLAGS_PATTERN_3 (1UL << 5) + UI32_T flags; + + HAL_DAWN_PKT_NETIF_RX_DST_TYPE_T dst_type; +#if defined(NETIF_EN_NETLINK) + HAL_DAWN_PKT_NETIF_RX_DST_NETLINK_T netlink; +#endif + +} HAL_DAWN_PKT_NETIF_PROFILE_T; + + +/* These requirements come from CLX_PKT APIs. + * clx_pkt -> hal_pkt_srv -> hal_pkt_drv -> hal_pkt_knl + */ +typedef enum +{ + /* network interface */ + HAL_DAWN_PKT_IOCTL_TYPE_CREATE_INTF = 0, + HAL_DAWN_PKT_IOCTL_TYPE_DESTROY_INTF, + HAL_DAWN_PKT_IOCTL_TYPE_GET_INTF, + HAL_DAWN_PKT_IOCTL_TYPE_CREATE_PROFILE, + HAL_DAWN_PKT_IOCTL_TYPE_DESTROY_PROFILE, + HAL_DAWN_PKT_IOCTL_TYPE_GET_PROFILE, + HAL_DAWN_PKT_IOCTL_TYPE_GET_INTF_CNT, + HAL_DAWN_PKT_IOCTL_TYPE_CLEAR_INTF_CNT, + /* driver */ + HAL_DAWN_PKT_IOCTL_TYPE_WAIT_RX_FREE, + HAL_DAWN_PKT_IOCTL_TYPE_WAIT_TX_FREE, /* waitTxFree(ASYNC) */ + HAL_DAWN_PKT_IOCTL_TYPE_SET_RX_CFG, /* setRxConfig */ + HAL_DAWN_PKT_IOCTL_TYPE_GET_RX_CFG, /* getRxConfig */ + HAL_DAWN_PKT_IOCTL_TYPE_DEINIT_TASK, /* deinitTask */ + HAL_DAWN_PKT_IOCTL_TYPE_DEINIT_DRV, /* deinitDrv */ + HAL_DAWN_PKT_IOCTL_TYPE_INIT_TASK, /* initTask */ + HAL_DAWN_PKT_IOCTL_TYPE_INIT_DRV, /* initDrv */ + /* counter */ + HAL_DAWN_PKT_IOCTL_TYPE_GET_TX_CNT, + HAL_DAWN_PKT_IOCTL_TYPE_GET_RX_CNT, + HAL_DAWN_PKT_IOCTL_TYPE_CLEAR_TX_CNT, + HAL_DAWN_PKT_IOCTL_TYPE_CLEAR_RX_CNT, + /* port attribute */ + HAL_DAWN_PKT_IOCTL_TYPE_SET_PORT_ATTR, +#if defined(NETIF_EN_NETLINK) + HAL_DAWN_PKT_IOCTL_TYPE_NL_SET_INTF_PROPERTY, + HAL_DAWN_PKT_IOCTL_TYPE_NL_GET_INTF_PROPERTY, + HAL_DAWN_PKT_IOCTL_TYPE_NL_CREATE_NETLINK, + HAL_DAWN_PKT_IOCTL_TYPE_NL_DESTROY_NETLINK, + HAL_DAWN_PKT_IOCTL_TYPE_NL_GET_NETLINK, +#endif + HAL_DAWN_PKT_IOCTL_TYPE_LAST + +} HAL_DAWN_PKT_IOCTL_TYPE_T; + +typedef enum +{ + HAL_DAWN_PKT_IOCTL_RX_TYPE_INIT = 0, + HAL_DAWN_PKT_IOCTL_RX_TYPE_DEINIT, + HAL_DAWN_PKT_IOCTL_RX_TYPE_LAST, + +} HAL_DAWN_PKT_IOCTL_RX_TYPE_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; + HAL_DAWN_PKT_RX_CNT_T rx_cnt; + HAL_DAWN_PKT_TX_CNT_T tx_cnt; + CLX_ERROR_NO_T rc; + +} HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T; + +typedef struct +{ + UI32_T unit; + HAL_DAWN_PKT_NETIF_INTF_T net_intf; /* addIntf[In,Out], delIntf[In] */ + HAL_DAWN_PKT_NETIF_PROFILE_T net_profile; /* createProfile[In,Out], destroyProfile[In] */ + HAL_DAWN_PKT_NETIF_INTF_CNT_T cnt; + CLX_ERROR_NO_T rc; + +} HAL_DAWN_PKT_IOCTL_NETIF_COOKIE_T; + +typedef struct +{ + CLX_ADDR_T callback; /* (unit, ptr_sw_gpd, ptr_cookie) */ + CLX_ADDR_T cookie; /* Pointer of CLX_PKT_TX_PKT_T */ + UI32_T channel; + UI32_T gpd_num; + CLX_ADDR_T hw_gpd_addr; + CLX_ADDR_T sw_gpd_addr; + +} HAL_DAWN_PKT_IOCTL_TX_GPD_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; /* sendGpd[In] */ + CLX_ADDR_T ioctl_gpd_addr; /* sendGpd[In] */ + CLX_ADDR_T done_sw_gpd_addr; /* waitTxFree[Out] */ + +} HAL_DAWN_PKT_IOCTL_TX_COOKIE_T; + +typedef struct +{ + BOOL_T rx_complete; /* FALSE when PDMA error occurs */ + CLX_ADDR_T hw_gpd_addr; /* Pointer to HW GPD in user's SW GPD struct */ + CLX_ADDR_T dma_buf_addr; /* Pointer to DMA buffer allocated by the user (virtual) */ + +} HAL_DAWN_PKT_IOCTL_RX_GPD_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; /* getRxCnt[In], clearRxInt[In] */ + CLX_ADDR_T ioctl_gpd_addr; /* waitRxFree[Out] */ + UI32_T buf_len; /* setRxCfg[In] */ + HAL_DAWN_PKT_IOCTL_RX_TYPE_T rx_type; /* setRxCfg[In] */ + +} HAL_DAWN_PKT_IOCTL_RX_COOKIE_T; + +typedef struct +{ + UI32_T port; + UI32_T status; + CLX_PORT_SPEED_T speed; + +} HAL_DAWN_PKT_IOCTL_PORT_COOKIE_T; + +#if defined(NETIF_EN_NETLINK) + +typedef struct +{ + /* intf property */ + UI32_T intf_id; + CLX_NETIF_INTF_PROPERTY_T property; + UI32_T param0; + UI32_T param1; + + /* netlink */ + CLX_NETIF_NETLINK_T netlink; + + CLX_ERROR_NO_T rc; + +} HAL_DAWN_PKT_NL_IOCTL_COOKIE_T; + + +#endif /* End of NETIF_EN_NETLINK */ + +typedef union +{ + UI32_T value; + struct + { + UI32_T unit : 6; /* Maximum unit number is 64. */ + HAL_DAWN_PKT_IOCTL_TYPE_T type : 10; /* Maximum 1024 IOCTL types */ + UI32_T rsvd : 16; + } field; + +} HAL_DAWN_PKT_IOCTL_CMD_T; + +#endif /* End of CLX_EN_NETIF */ + +/*---------------------------------------------------------------------------*/ +/* perf */ +CLX_ERROR_NO_T +hal_dawn_pkt_getTxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt); + +CLX_ERROR_NO_T +hal_dawn_pkt_getRxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt); + +/* ioctl */ +CLX_ERROR_NO_T +hal_dawn_pkt_getTxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_dawn_pkt_getRxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_dawn_pkt_clearTxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_TX_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_dawn_pkt_clearRxKnlCnt( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_dawn_pkt_setRxKnlConfig( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_dawn_pkt_getRxKnlConfig( + const UI32_T unit, + HAL_DAWN_PKT_IOCTL_RX_COOKIE_T *ptr_cookie); + +/* perf */ +CLX_ERROR_NO_T +hal_dawn_pkt_getNetDev( + const UI32_T unit, + const UI32_T port, + struct net_device **pptr_net_dev); + +CLX_ERROR_NO_T +hal_dawn_pkt_prepareGpd( + const UI32_T unit, + const CLX_ADDR_T phy_addr, + const UI32_T len, + const UI32_T port, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd); + +CLX_ERROR_NO_T +hal_dawn_pkt_sendGpd( + const UI32_T unit, + const HAL_DAWN_PKT_TX_CHANNEL_T channel, + HAL_DAWN_PKT_TX_SW_GPD_T *ptr_sw_gpd); + +CLX_ERROR_NO_T +hal_dawn_pkt_init( + const UI32_T unit); + +CLX_ERROR_NO_T +hal_dawn_pkt_exit( + const UI32_T unit); + +ssize_t +hal_dawn_pkt_dev_tx( + struct file *file, + const char __user *buf, + size_t count, + loff_t *pos); + +long +hal_dawn_pkt_dev_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg); + +#endif /* end of HAL_DAWN_PKT_KNL_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/hal_lightning_pkt_knl.h b/platform/clounix/clounix-modules/modules/src/inc/hal_lightning_pkt_knl.h new file mode 100755 index 000000000000..307ef417709c --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/hal_lightning_pkt_knl.h @@ -0,0 +1,2293 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: hal_lightning_pkt_knl.h + * PURPOSE: + * To provide Linux kernel for PDMA TX/RX control. + * + * NOTES: + */ + +#ifndef HAL_LIGHTNING_PKT_KNL_H +#define HAL_LIGHTNING_PKT_KNL_H + +#include +#include + +/* CP_COMMON */ +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_EN_HI (0x000FC000) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_EN_LO (0x000FC004) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_LVL_HI (0x000FC008) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_LVL_LO (0x000FC00C) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_SET_HI (0x000FC010) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_SET_LO (0x000FC014) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_CLR_HI (0x000FC018) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_CLR_LO (0x000FC034) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_VAL_HI (0x000FC020) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_MASK_VAL_LO (0x000FC024) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_STAT_HI (0x000FC028) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_STAT_LO (0x000FC02C) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_CLR_HI (0x000FC030) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_CLR_LO (0x000FC034) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_SET_HI (0x000FC038) +#define HAL_LIGHTNING_PKT_CP_COMMON_INT_SET_LO (0x000FC03C) + +/* PDMA */ +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_STAT (0x003F1000) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_CLR (0x003F1004) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_EN (0x003F1010) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_LVL (0x003F1014) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_MASK_SET (0x003F1018) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_MASK_CLR (0x003F101C) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_MASK_VAL (0x003F1020) +#define HAL_LIGHTNING_PKT_PDMA_ERR_INT_SET (0x003F1024) +#define HAL_LIGHTNING_PKT_PDMA_CREDIT_CFG (0x003F1100) + +/* Rx */ +#define HAL_LIGHTNING_PKT_PDMA_RCH_GPD_RING_START_ADDR_LO (0x003F12E4) +#define HAL_LIGHTNING_PKT_PDMA_RCH_GPD_RING_START_ADDR_HI (0x003F12E8) +#define HAL_LIGHTNING_PKT_PDMA_RCH_GPD_RING_SIZE (0x003F12EC) +#define HAL_LIGHTNING_PKT_PDMA_RCH_CMD (0x003F1300) +#define HAL_LIGHTNING_PKT_PDMA_RCH_INT_EN (0x003F1360) +#define HAL_LIGHTNING_PKT_PDMA_RCH_INT_LVL (0x003F1364) +#define HAL_LIGHTNING_PKT_PDMA_RCH_INT_MASK (0x003F1368) +#define HAL_LIGHTNING_PKT_PDMA_RCH_INT_SET (0x003F1374) +#define HAL_LIGHTNING_PKT_PDMA_RCH_INT_CLR (0x003F1378) +#define HAL_LIGHTNING_PKT_PDMA_RCH_INT_STAT (0x003F1370) + +/* Tx */ +#define HAL_LIGHTNING_PKT_PDMA_TCH_GPD_RING_START_ADDR_LO (0x003F1A00) +#define HAL_LIGHTNING_PKT_PDMA_TCH_GPD_RING_START_ADDR_HI (0x003F1A04) +#define HAL_LIGHTNING_PKT_PDMA_TCH_GPD_RING_SIZE (0x003F1A08) +#define HAL_LIGHTNING_PKT_PDMA_TCH_CMD (0x003F1A20) +#define HAL_LIGHTNING_PKT_PDMA_TCH_INT_EN (0x003F1A40) +#define HAL_LIGHTNING_PKT_PDMA_TCH_INT_LVL (0x003F1A44) +#define HAL_LIGHTNING_PKT_PDMA_TCH_INT_MASK (0x003F1A48) +#define HAL_LIGHTNING_PKT_PDMA_TCH_INT_SET (0x003F1A54) +#define HAL_LIGHTNING_PKT_PDMA_TCH_INT_CLR (0x003F1A58) +#define HAL_LIGHTNING_PKT_PDMA_TCH_INT_STAT (0x003F1A50) + +#define HAL_LIGHTNING_PKT_GET_MMIO(__tbl__) (0x00FFFFFF & (__tbl__)) +#define HAL_LIGHTNING_PKT_GET_PDMA_RCH_REG(__tbl__, __channel__) ((__tbl__) + (0x200 * (__channel__))) +#define HAL_LIGHTNING_PKT_GET_PDMA_TCH_REG(__tbl__, __channel__) ((__tbl__) + (0x100 * (__channel__))) + +#define HAL_LIGHTNING_PORT_NUM (256) +#define HAL_LIGHTNING_PLANE_NUM (8) +#define HAL_LIGHTNING_PLANE_BITS (3) +#define HAL_LIGHTNING_PLANE_MASK (0x7) + +/* NAMING DECLARATIONS + */ +/* PKT definitions */ +#define HAL_LIGHTNING_PKT_TX_MAX_LEN (9216) +#define HAL_LIGHTNING_PKT_RX_MAX_LEN (9216 + 86) /* EPP tunnel header */ +#define HAL_LIGHTNING_PKT_MIN_LEN (64) /* Ethernet definition */ +#define HAL_LIGHTNING_PKT_TMH_HDR_SZ (20) +#define HAL_LIGHTNING_PKT_PPH_HDR_SZ (20) +#define HAL_LIGHTNING_PKT_CRC_LEN (4) + +/* CH */ +#define HAL_LIGHTNING_PKT_CH_LAST_GPD (0) +#define HAL_LIGHTNING_PKT_CH_MIDDLE_GPD (1) + +/* PRG */ +#define HAL_LIGHTNING_PKT_PRG_PROCESS_GPD (0) /* Normal */ +#define HAL_LIGHTNING_PKT_PRG_SKIP_GPD (1) /* Skip */ + +/* CRCC */ +#define HAL_LIGHTNING_PKT_CRCC_SUM_BY_HW (0) /* calculated by HW */ +#define HAL_LIGHTNING_PKT_CRCC_SUM_BY_SW (1) /* calculated by SW */ + +/* IOC */ +#define HAL_LIGHTNING_PKT_IOC_NO_INTR (0) /* trigger interrupt each GPD */ +#define HAL_LIGHTNING_PKT_IOC_HAS_INTR (1) /* trigger interrupt when ch=0, default setting */ + +/* HWO */ +#define HAL_LIGHTNING_PKT_HWO_SW_OWN (0) +#define HAL_LIGHTNING_PKT_HWO_HW_OWN (1) + +/* ECC */ +#define HAL_LIGHTNING_PKT_ECC_ERROR_OCCUR (1) + +/* CPU, CPI queue number */ +#define HAL_LIGHTNING_PKT_CPU_QUE_NUM (48) +#define HAL_LIGHTNING_PKT_CPI_QUE_NUM (8) + +/* PDMA Definitions */ +#define HAL_LIGHTNING_PKT_PDMA_MAX_GPD_PER_PKT (10) /* <= 256 */ +#define HAL_LIGHTNING_PKT_PDMA_TX_INTR_TIMEOUT (10 * 1000) /* us */ +#define HAL_LIGHTNING_PKT_PDMA_TX_POLL_MAX_LOOP (10 * 1000) /* int */ + +/* Mode */ +#define HAL_LIGHTNING_PKT_TX_WAIT_MODE (HAL_LIGHTNING_PKT_TX_WAIT_ASYNC) + +/* TX Queue */ +#define HAL_LIGHTNING_PKT_TX_TASK_MAX_LOOP (HAL_DFLT_CFG_PKT_TX_QUEUE_LEN) + +/* RX Queue */ +#define HAL_LIGHTNING_PKT_RX_QUEUE_NUM (HAL_LIGHTNING_PKT_RX_CHANNEL_LAST) +#define HAL_LIGHTNING_PKT_RX_TASK_MAX_LOOP (HAL_DFLT_CFG_PKT_RX_QUEUE_LEN) + +/* MACRO FUNCTION DECLARATIONS + */ +/*---------------------------------------------------------------------------*/ +/* [CL8570] Alignment to 64-bytes */ +#if defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) || defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) +#define HAL_LIGHTNING_PKT_PDMA_ALIGN_ADDR(pdma_addr, align_sz) (((pdma_addr) + (align_sz)) & 0xFFFFFFFFFFFFFFC0) +#else +#define HAL_LIGHTNING_PKT_PDMA_ALIGN_ADDR(pdma_addr, align_sz) (((pdma_addr) + (align_sz)) & 0xFFFFFFC0) +#endif +/*---------------------------------------------------------------------------*/ +#if defined(CLX_EN_BIG_ENDIAN) +#define HAL_LIGHTNING_PKT_ENDIAN_SWAP32(val) (val) +#else +#define HAL_LIGHTNING_PKT_ENDIAN_SWAP32(val) CMLIB_UTIL_ENDIAN_SWAP32(val) +#endif +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_GET_BIT(flags, bit) ((((flags) & (bit)) > 0)? 1 : 0) +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_SET_BITMAP(bitmap, mask_bitmap) (bitmap = ((bitmap) | (mask_bitmap))) +#define HAL_LIGHTNING_PKT_CLR_BITMAP(bitmap, mask_bitmap) (bitmap = ((bitmap) & (~(mask_bitmap)))) +/*---------------------------------------------------------------------------*/ +#define HAL_LIGHTNING_PKT_GET_TX_INTR_TYPE(channel) (HAL_INTR_TX_CH0 + channel) +#define HAL_LIGHTNING_PKT_GET_RX_INTR_TYPE(channel) (HAL_INTR_RX_CH0 + channel) + +/* DATA TYPE DECLARATIONS + */ +typedef enum +{ + HAL_LIGHTNING_PKT_TX_WAIT_ASYNC = 0, + HAL_LIGHTNING_PKT_TX_WAIT_SYNC_INTR = 1, + HAL_LIGHTNING_PKT_TX_WAIT_SYNC_POLL = 2 + +} HAL_LIGHTNING_PKT_TX_WAIT_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_RX_SCHED_RR = 0, + HAL_LIGHTNING_PKT_RX_SCHED_WRR = 1 + +} HAL_LIGHTNING_PKT_RX_SCHED_T; + +/* GPD and Packet Strucutre Definition */ +#if defined(CLX_EN_BIG_ENDIAN) + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T : 2; + UI32_T ecn : 2; + UI32_T store_and_forward : 1; + UI32_T lag_epoch : 1; + UI32_T src_supp_tag : 5; + UI32_T : 2; + UI32_T skip_ipp : 1; + UI32_T igr_fab_port_grp : 1; + /* CLX DWORD 3 */ + UI32_T :32; + /* CLX DWORD 4 */ + UI32_T :20; + UI32_T had_uturn : 1; + UI32_T fab_stacking_supp : 2; + UI32_T chip_igr_lag_port : 8; + UI32_T exp_dscp_mrkd : 1; +} HAL_LIGHTNING_PKT_ITMH_FAB_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T ecn : 2; + UI32_T store_and_forward : 1; + UI32_T lag_epoch : 1; + UI32_T src_supp_tag : 5; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T fab_one_arm_rte : 1; + UI32_T skip_ipp : 1; + UI32_T igr_fab_port_grp : 1; + /* CLX DWORD 3 */ + UI32_T : 2; + UI32_T nvo3_mgid :15; + UI32_T nvo3_intf :14; + UI32_T nvo3_src_supp_tag_w0 : 1; + /* CLX DWORD 4 */ + UI32_T nvo3_src_supp_tag_w1 : 4; + UI32_T mir_bmap : 8; + UI32_T cp_to_cpu_code : 4; + UI32_T cp_to_cpu_bmap :16; +} HAL_LIGHTNING_PKT_ITMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T ecn : 2; + UI32_T store_and_forward : 1; + UI32_T lag_epoch : 1; + UI32_T src_supp_tag : 5; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T fab_one_arm_rte : 1; + UI32_T : 2; + /* CLX DWORD 3 */ + UI32_T :32; + /* CLX DWORD 4 */ + UI32_T :20; + UI32_T had_uturn : 1; + UI32_T : 2; + UI32_T excpt_code : 8; + UI32_T exp_dscp_mrkd : 1; +} HAL_LIGHTNING_PKT_ETMH_FAB_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T typ : 2; + UI32_T tc : 4; + UI32_T color : 2; + UI32_T srv : 3; + UI32_T trig : 1; + UI32_T igr_phy_port :12; + UI32_T hsh_val_w0 : 8; + /* CLX DWORD 1 */ + UI32_T hsh_val_w1 : 2; + UI32_T dst_idx :15; + UI32_T src_idx :15; + /* CLX DWORD 2 */ + UI32_T intf_fdid :14; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T skip_epp : 1; + UI32_T steer_applied : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T ecn : 2; + UI32_T igr_fab_port_grp : 1; + UI32_T redir : 1; + UI32_T excpt_code_mir_bmap : 8; + UI32_T cp_to_cpu_bmap_w0 : 1; + /* CLX DWORD 3 */ + UI32_T cp_to_cpu_bmap_w1 : 7; + UI32_T egr_phy_port :12; + UI32_T src_supp_pnd : 1; + UI32_T mc_vid_ctl : 3; + UI32_T mc_vid_1st_w0 : 9; + /* CLX DWORD 4 */ + UI32_T mc_vid_1st_w1 : 3; + UI32_T mc_vid_2nd :12; + UI32_T mc_decr_ttl : 1; + UI32_T mc_is_routed : 1; + UI32_T mc_mel_vld : 1; + UI32_T mc_cp_idx :13; + UI32_T exp_dscp_mrkd : 1; +} HAL_LIGHTNING_PKT_ETMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T mpls_pw_cw_vld : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T seg_vmid_w0 :17; + /* CLX DWORD 2 */ + UI32_T seg_vmid_w1 : 7; + UI32_T : 1; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T vid_ctl : 3; + UI32_T vid_1st :12; + UI32_T vid_2nd_w0 : 7; + /* CLX DWORD 3 */ + UI32_T vid_2nd_w1 : 5; + UI32_T flw_lbl :10; + UI32_T rewr_idx_ctl : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_1_w0 : 2; + /* CLX DWORD 4 */ + UI32_T rewr_idx_1_w1 :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts_0_7 : 8; + UI32_T ts_8_15 : 8; +} HAL_LIGHTNING_PKT_PPH_L2_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T mpls_pw_cw_vld : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T seg_vmid_w0 :17; + /* CLX DWORD 2 */ + UI32_T seg_vmid_w1 : 7; + UI32_T : 1; + UI32_T rpf_pnd : 1; + UI32_T adj_idx :18; + UI32_T is_mc : 1; + UI32_T decr_ttl : 1; + UI32_T decap_prop_ttl : 1; + UI32_T mrk_dscp_en : 1; + UI32_T mrk_dscp_val_w0 : 1; + /* CLX DWORD 3 */ + UI32_T mrk_dscp_val_w1 : 5; + UI32_T flw_lbl :10; + UI32_T rewr_idx_ctl : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_1_w0 : 2; + /* CLX DWORD 4 */ + UI32_T rewr_idx_1_w1 :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts_0_7 : 8; + UI32_T ts_8_15 : 8; +} HAL_LIGHTNING_PKT_PPH_L3UC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T mpls_pw_cw_vld : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T vid_1st :12; + UI32_T vid_2nd_w0 : 5; + /* CLX DWORD 2 */ + UI32_T vid_2nd_w1 : 7; + UI32_T :15; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T vid_ctl : 3; + UI32_T is_mc : 1; + UI32_T : 1; + UI32_T decap_prop_ttl : 1; + UI32_T mrk_dscp_en : 1; + UI32_T mrk_dscp_val_w0 : 1; + /* CLX DWORD 3 */ + UI32_T mrk_dscp_val_w1 : 5; + UI32_T flw_lbl :10; + UI32_T rewr_idx_ctl : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_1_w0 : 2; + /* CLX DWORD 4 */ + UI32_T rewr_idx_1_w1 :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts_0_7 : 8; + UI32_T ts_8_15 : 8; +} HAL_LIGHTNING_PKT_PPH_L3MC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T decap_act : 3; + UI32_T igr_l2_vid_num : 2; + UI32_T nvo3_encap_idx :14; + UI32_T : 1; + UI32_T hit_idx_w0 :12; + /* CLX DWORD 1 */ + UI32_T hit_idx_w1 : 7; + UI32_T nvo3_adj_idx : 8; + UI32_T seg_vmid_w0 :17; + /* CLX DWORD 2 */ + UI32_T seg_vmid_w1 : 7; + UI32_T : 2; + UI32_T adj_idx :18; + UI32_T : 1; + UI32_T decr_ttl : 1; + UI32_T decap_prop_ttl : 1; + UI32_T mrk_exp_en : 1; + UI32_T : 1; + /* CLX DWORD 3 */ + UI32_T : 2; + UI32_T mrk_exp_val : 3; + UI32_T php_pop_keep_inner_qos : 1; + UI32_T :26; + /* CLX DWORD 4 */ + UI32_T :11; + UI32_T mrk_pcp_dei_en : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_dei_val : 1; + UI32_T ts_0_7 : 8; + UI32_T ts_8_15 : 8; +} HAL_LIGHTNING_PKT_PPH_L25_T; + +#elif defined(CLX_EN_LITTLE_ENDIAN) + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T igr_fab_port_grp : 1; + UI32_T skip_ipp : 1; + UI32_T : 2; + UI32_T src_supp_tag : 5; + UI32_T lag_epoch : 1; + UI32_T store_and_forward : 1; + UI32_T ecn : 2; + UI32_T : 2; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T :32; + /* CLX DWORD 4 */ + UI32_T exp_dscp_mrkd : 1; + UI32_T chip_igr_lag_port : 8; + UI32_T fab_stacking_supp : 2; + UI32_T had_uturn : 1; + UI32_T :20; +} HAL_LIGHTNING_PKT_ITMH_FAB_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T igr_fab_port_grp : 1; + UI32_T skip_ipp : 1; + UI32_T fab_one_arm_rte : 1; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T src_supp_tag : 5; + UI32_T lag_epoch : 1; + UI32_T store_and_forward : 1; + UI32_T ecn : 2; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T nvo3_src_supp_tag_w0 : 1; + UI32_T nvo3_intf :14; + UI32_T nvo3_mgid :15; + UI32_T : 2; + /* CLX DWORD 4 */ + UI32_T cp_to_cpu_bmap :16; + UI32_T cp_to_cpu_code : 4; + UI32_T mir_bmap : 8; + UI32_T nvo3_src_supp_tag_w1 : 4; +} HAL_LIGHTNING_PKT_ITMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T : 2; + UI32_T fab_one_arm_rte : 1; + UI32_T one_arm_rte_srv_fdid : 1; + UI32_T src_supp_tag : 5; + UI32_T lag_epoch : 1; + UI32_T store_and_forward : 1; + UI32_T ecn : 2; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T :32; + /* CLX DWORD 4 */ + UI32_T exp_dscp_mrkd : 1; + UI32_T excpt_code : 8; + UI32_T : 2; + UI32_T had_uturn : 1; + UI32_T :20; +} HAL_LIGHTNING_PKT_ETMH_FAB_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hsh_val_w0 : 8; + UI32_T igr_phy_port :12; + UI32_T trig : 1; + UI32_T srv : 3; + UI32_T color : 2; + UI32_T tc : 4; + UI32_T typ : 2; + /* CLX DWORD 1 */ + UI32_T src_idx :15; + UI32_T dst_idx :15; + UI32_T hsh_val_w1 : 2; + /* CLX DWORD 2 */ + UI32_T cp_to_cpu_bmap_w0 : 1; + UI32_T excpt_code_mir_bmap : 8; + UI32_T redir : 1; + UI32_T igr_fab_port_grp : 1; + UI32_T ecn : 2; + UI32_T nvo3_mpls_uhp_prop_ttl : 1; + UI32_T nvo3_ip_tnl_decap_prop_ttl : 1; + UI32_T steer_applied : 1; + UI32_T skip_epp : 1; + UI32_T nvo3_mgid_is_transit : 1; + UI32_T intf_fdid :14; + /* CLX DWORD 3 */ + UI32_T mc_vid_1st_w0 : 9; + UI32_T mc_vid_ctl : 3; + UI32_T src_supp_pnd : 1; + UI32_T egr_phy_port :12; + UI32_T cp_to_cpu_bmap_w1 : 7; + /* CLX DWORD 4 */ + UI32_T exp_dscp_mrkd : 1; + UI32_T mc_cp_idx :13; + UI32_T mc_mel_vld : 1; + UI32_T mc_is_routed : 1; + UI32_T mc_decr_ttl : 1; + UI32_T mc_vid_2nd :12; + UI32_T mc_vid_1st_w1 : 3; +} HAL_LIGHTNING_PKT_ETMH_ETH_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T mpls_pw_cw_vld : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T seg_vmid_w0 :17; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T vid_2nd_w0 : 7; + UI32_T vid_1st :12; + UI32_T vid_ctl : 3; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T : 1; + UI32_T seg_vmid_w1 : 7; + /* CLX DWORD 3 */ + UI32_T rewr_idx_1_w0 : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_ctl : 2; + UI32_T flw_lbl :10; + UI32_T vid_2nd_w1 : 5; + /* CLX DWORD 4 */ + UI32_T ts_8_15 : 8; + UI32_T ts_0_7 : 8; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T rewr_idx_1_w1 :11; +} HAL_LIGHTNING_PKT_PPH_L2_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T mpls_pw_cw_vld : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T seg_vmid_w0 :17; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T mrk_dscp_val_w0 : 1; + UI32_T mrk_dscp_en : 1; + UI32_T decap_prop_ttl : 1; + UI32_T decr_ttl : 1; + UI32_T is_mc : 1; + UI32_T adj_idx :18; + UI32_T rpf_pnd : 1; + UI32_T : 1; + UI32_T seg_vmid_w1 : 7; + /* CLX DWORD 3 */ + UI32_T rewr_idx_1_w0 : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_ctl : 2; + UI32_T flw_lbl :10; + UI32_T mrk_dscp_val_w1 : 5; + /* CLX DWORD 4 */ + UI32_T ts_8_15 : 8; + UI32_T ts_0_7 : 8; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T rewr_idx_1_w1 :11; +} HAL_LIGHTNING_PKT_PPH_L3UC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T mpls_pw_cw_vld : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T vid_2nd_w0 : 5; + UI32_T vid_1st :12; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T mrk_dscp_val_w0 : 1; + UI32_T mrk_dscp_en : 1; + UI32_T decap_prop_ttl : 1; + UI32_T : 1; + UI32_T is_mc : 1; + UI32_T vid_ctl : 3; + UI32_T l2_sa_lrn_en_hw : 1; + UI32_T l2_sa_lrn_en_hw_cvs : 1; + UI32_T :15; + UI32_T vid_2nd_w1 : 7; + /* CLX DWORD 3 */ + UI32_T rewr_idx_1_w0 : 2; + UI32_T rewr_idx_0 :13; + UI32_T rewr_idx_ctl : 2; + UI32_T flw_lbl :10; + UI32_T mrk_dscp_val_w1 : 5; + /* CLX DWORD 4 */ + UI32_T ts_8_15 : 8; + UI32_T ts_0_7 : 8; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T rewr_idx_1_w1 :11; +} HAL_LIGHTNING_PKT_PPH_L3MC_T; + +typedef struct +{ + /* CLX DWORD 0 */ + UI32_T hit_idx_w0 :12; + UI32_T : 1; + UI32_T nvo3_encap_idx :14; + UI32_T igr_l2_vid_num : 2; + UI32_T decap_act : 3; + /* CLX DWORD 1 */ + UI32_T seg_vmid_w0 :17; + UI32_T nvo3_adj_idx : 8; + UI32_T hit_idx_w1 : 7; + /* CLX DWORD 2 */ + UI32_T : 1; + UI32_T mrk_exp_en : 1; + UI32_T decap_prop_ttl : 1; + UI32_T decr_ttl : 1; + UI32_T : 1; + UI32_T adj_idx :18; + UI32_T : 2; + UI32_T seg_vmid_w1 : 7; + /* CLX DWORD 3 */ + UI32_T :26; + UI32_T php_pop_keep_inner_qos : 1; + UI32_T mrk_exp_val : 3; + UI32_T : 2; + /* CLX DWORD 4 */ + UI32_T ts_8_15 : 8; + UI32_T ts_0_7 : 8; + UI32_T mrk_dei_val : 1; + UI32_T mrk_pcp_val : 3; + UI32_T mrk_pcp_dei_en : 1; + UI32_T :11; +} HAL_LIGHTNING_PKT_PPH_L25_T; + +#else +#error "Host GPD endian is not defined!!\n" +#endif + +#if defined(CLX_EN_BIG_ENDIAN) + +/* RX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T chksum : 16; + UI32_T ioc : 1; + UI32_T : 1; + UI32_T avbl_buf_len : 14; + UI32_T : 32; + + union + { + HAL_LIGHTNING_PKT_ITMH_FAB_T itmh_fab; + HAL_LIGHTNING_PKT_ITMH_ETH_T itmh_eth; + HAL_LIGHTNING_PKT_ETMH_FAB_T etmh_fab; + HAL_LIGHTNING_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_LIGHTNING_PKT_PPH_L2_T pph_l2; + HAL_LIGHTNING_PKT_PPH_L3UC_T pph_l3uc; + HAL_LIGHTNING_PKT_PPH_L3MC_T pph_l3mc; + HAL_LIGHTNING_PKT_PPH_L25_T pph_l25; + }; + + UI32_T ts_16_23 : 8; + UI32_T ts_24_31 : 8; + UI32_T : 6; + UI32_T ts_32_33 : 2; + UI32_T : 8; + UI32_T hwo : 1; + UI32_T ch : 1; + UI32_T trn : 1; + UI32_T ecce : 1; + UI32_T errf : 1; + UI32_T : 5; + UI32_T queue : 6; + UI32_T : 2; + UI32_T cnsm_buf_len : 14; + +} HAL_LIGHTNING_PKT_RX_GPD_T; + +/* TX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T chksum : 16; + UI32_T ioc : 1; + UI32_T : 1; + UI32_T data_buf_size : 14; + UI32_T : 32; + + union + { + HAL_LIGHTNING_PKT_ITMH_FAB_T itmh_fab; + HAL_LIGHTNING_PKT_ITMH_ETH_T itmh_eth; + HAL_LIGHTNING_PKT_ETMH_FAB_T etmh_fab; + HAL_LIGHTNING_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_LIGHTNING_PKT_PPH_L2_T pph_l2; + HAL_LIGHTNING_PKT_PPH_L3UC_T pph_l3uc; + HAL_LIGHTNING_PKT_PPH_L3MC_T pph_l3mc; + HAL_LIGHTNING_PKT_PPH_L25_T pph_l25; + }; + + UI32_T : 16; + UI32_T ptp_hdr : 16; + UI32_T hwo : 1; + UI32_T ch : 1; + UI32_T : 1; + UI32_T ecce : 1; + UI32_T crce : 1; + UI32_T : 3; + UI32_T cos : 3; + UI32_T phc : 1; /* PTP Header Control */ + UI32_T ipc : 3; /* Ingress Plane Control */ + UI32_T prg : 1; /* Purge */ + UI32_T : 2; + UI32_T pkt_len : 14; /* Total packet length */ + +} HAL_LIGHTNING_PKT_TX_GPD_T; + +#elif defined(CLX_EN_LITTLE_ENDIAN) + +/* RX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T avbl_buf_len : 14; + UI32_T : 1; + UI32_T ioc : 1; + UI32_T chksum : 16; + UI32_T : 32; + + union + { + HAL_LIGHTNING_PKT_ITMH_FAB_T itmh_fab; + HAL_LIGHTNING_PKT_ITMH_ETH_T itmh_eth; + HAL_LIGHTNING_PKT_ETMH_FAB_T etmh_fab; + HAL_LIGHTNING_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_LIGHTNING_PKT_PPH_L2_T pph_l2; + HAL_LIGHTNING_PKT_PPH_L3UC_T pph_l3uc; + HAL_LIGHTNING_PKT_PPH_L3MC_T pph_l3mc; + HAL_LIGHTNING_PKT_PPH_L25_T pph_l25; + }; + + UI32_T : 8; + UI32_T ts_32_33 : 2; + UI32_T : 6; + UI32_T ts_24_31 : 8; + UI32_T ts_16_23 : 8; + UI32_T cnsm_buf_len : 14; + UI32_T : 2; + UI32_T queue : 6; + UI32_T : 5; + UI32_T errf : 1; + UI32_T ecce : 1; + UI32_T trn : 1; + UI32_T ch : 1; + UI32_T hwo : 1; + +} HAL_LIGHTNING_PKT_RX_GPD_T; + +/* TX GPD STRUCTURE */ +typedef struct +{ + UI32_T data_buf_addr_lo; + UI32_T data_buf_addr_hi; + UI32_T data_buf_size : 14; + UI32_T : 1; + UI32_T ioc : 1; + UI32_T chksum : 16; + UI32_T : 32; + + union + { + HAL_LIGHTNING_PKT_ITMH_FAB_T itmh_fab; + HAL_LIGHTNING_PKT_ITMH_ETH_T itmh_eth; + HAL_LIGHTNING_PKT_ETMH_FAB_T etmh_fab; + HAL_LIGHTNING_PKT_ETMH_ETH_T etmh_eth; + }; + union + { + HAL_LIGHTNING_PKT_PPH_L2_T pph_l2; + HAL_LIGHTNING_PKT_PPH_L3UC_T pph_l3uc; + HAL_LIGHTNING_PKT_PPH_L3MC_T pph_l3mc; + HAL_LIGHTNING_PKT_PPH_L25_T pph_l25; + }; + + UI32_T ptp_hdr : 16; + UI32_T : 16; + UI32_T pkt_len : 14; /* Total packet length */ + UI32_T : 2; + UI32_T prg : 1; /* Purge */ + UI32_T ipc : 3; /* Ingress Plane Control */ + UI32_T phc : 1; /* PTP Header Control */ + UI32_T cos : 3; + UI32_T : 3; + UI32_T crce : 1; + UI32_T ecce : 1; + UI32_T : 1; + UI32_T ch : 1; + UI32_T hwo : 1; +} HAL_LIGHTNING_PKT_TX_GPD_T; + +#else +#error "Host GPD endian is not defined\n" +#endif + +/* ----------------------------------------------------------------------------------- PP Type */ +typedef enum +{ + HAL_LIGHTNING_PKT_TMH_TYPE_ITMH_ETH = 0, + HAL_LIGHTNING_PKT_TMH_TYPE_ITMH_FAB, + HAL_LIGHTNING_PKT_TMH_TYPE_ETMH_FAB, + HAL_LIGHTNING_PKT_TMH_TYPE_ETMH_ETH, + HAL_LIGHTNING_PKT_TMH_TYPE_LAST + +} HAL_LIGHTNING_PKT_TMH_TYPE_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_TMH_SRV_L2 = 0, + HAL_LIGHTNING_PKT_TMH_SRV_L25_MPLS, + HAL_LIGHTNING_PKT_TMH_SRV_L3, + HAL_LIGHTNING_PKT_TMH_SRV_EGR, /* L3 downgrade L2 */ + HAL_LIGHTNING_PKT_TMH_SRV_L25_NSH, + HAL_LIGHTNING_PKT_TMH_SRV_L25_TRILL, + HAL_LIGHTNING_PKT_TMH_SRV_LAST + +} HAL_LIGHTNING_PKT_TMH_SRV_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_TMH_DECAP_NONE = 0, + HAL_LIGHTNING_PKT_TMH_DECAP_1_MPLS_LABEL, + HAL_LIGHTNING_PKT_TMH_DECAP_2_MPLS_LABEL, + HAL_LIGHTNING_PKT_TMH_DECAP_3_MPLS_LABEL, + HAL_LIGHTNING_PKT_TMH_DECAP_4_MPLS_LABEL, + HAL_LIGHTNING_PKT_TMH_DECAP_IP_TRILL_NSH, + HAL_LIGHTNING_PKT_TMH_DECAP_LAST + +} HAL_LIGHTNING_PKT_TMH_DECAP_T; + +typedef struct +{ + union + { + HAL_LIGHTNING_PKT_ITMH_FAB_T itmh_fab; + HAL_LIGHTNING_PKT_ITMH_ETH_T itmh_eth; + HAL_LIGHTNING_PKT_ETMH_FAB_T etmh_fab; + HAL_LIGHTNING_PKT_ETMH_ETH_T etmh_eth; + }; +} HAL_LIGHTNING_PKT_TMH_T; + +typedef struct +{ + union + { + HAL_LIGHTNING_PKT_PPH_L2_T pph_l2; + HAL_LIGHTNING_PKT_PPH_L3UC_T pph_l3uc; + HAL_LIGHTNING_PKT_PPH_L3MC_T pph_l3mc; + HAL_LIGHTNING_PKT_PPH_L25_T pph_l25; + }; +} HAL_LIGHTNING_PKT_PPH_T; + +/* ----------------------------------------------------------------------------------- Reg Type */ +typedef enum +{ + HAL_LIGHTNING_PKT_L2_ISR_RCH0 = (0x1UL << 0), + HAL_LIGHTNING_PKT_L2_ISR_RCH1 = (0x1UL << 1), + HAL_LIGHTNING_PKT_L2_ISR_RCH2 = (0x1UL << 2), + HAL_LIGHTNING_PKT_L2_ISR_RCH3 = (0x1UL << 3), + HAL_LIGHTNING_PKT_L2_ISR_TCH0 = (0x1UL << 4), + HAL_LIGHTNING_PKT_L2_ISR_TCH1 = (0x1UL << 5), + HAL_LIGHTNING_PKT_L2_ISR_TCH2 = (0x1UL << 6), + HAL_LIGHTNING_PKT_L2_ISR_TCH3 = (0x1UL << 7), + HAL_LIGHTNING_PKT_L2_ISR_RX_QID_MAP_ERR = (0x1UL << 8), + HAL_LIGHTNING_PKT_L2_ISR_RX_FRAME_ERR = (0x1UL << 9) + +} HAL_LIGHTNING_PKT_L2_ISR_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_HWO_ERROR = (0x1UL << 0), /* Tx GPD.hwo = 0 */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR = (0x1UL << 1), /* Tx GPD.chksm is error */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_NO_OVFL_ERROR = (0x1UL << 2), /* S/W push too much GPD */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_DMA_READ_ERROR = (0x1UL << 3), /* AXI Rd Error when do GPD read */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_BUF_SIZE_ERROR = (0x1UL << 4), /* Tx GPD.data_buf_size = 0 */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_RUNT_ERROR = (0x1UL << 5), /* Tx GPD.pkt_len < 64 */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_OVSZ_ERROR = (0x1UL << 6), /* Tx GPD.pkt_len = 9217 */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_LEN_MISMATCH_ERROR = (0x1UL << 7), /* Tx GPD.pkt_len != sum of data_buf_size */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PKTPL_DMA_READ_ERROR = (0x1UL << 8), /* AXI Rd Error when do Payload read */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_COS_ERROR = (0x1UL << 9), /* Tx GPD.cos is not match cos_to_tch_map */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_GPD_GT255_ERROR = (0x1UL << 10), /* Multi-GPD packet's GPD# > 255 */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_PFC = (0x1UL << 11), /* */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_CREDIT_UDFL_ERROR = (0x1UL << 12), /* Credit Underflow (count down to 0) */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_DMA_WRITE_ERROR = (0x1UL << 13), /* AXI Wr Error (GPD Write-Back) */ + HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_STOP_CMD_CPLT = (0x1UL << 14) + +} HAL_LIGHTNING_PKT_TX_CHANNEL_L2_ISR_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_LOW = (0x1UL << 0), /* Rx GPD.avbl_gpd_num < threshold */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_EMPTY = (0x1UL << 1), /* Rx GPD.avbl_gpd_num = 0 */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_AVAIL_GPD_ERROR = (0x1UL << 2), /* Rx GPD.hwo = 0 */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_CHKSM_ERROR = (0x1UL << 3), /* Rx GPD.chksm is error */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_READ_ERROR = (0x1UL << 4), /* DMAR error occurs in PCIE */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_DMA_WRITE_ERROR = (0x1UL << 5), /* DMAW error occurs in PCIE */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_STOP_CMD_CPLT = (0x1UL << 6), /* Stop Completion Acknowledge */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_GPD_GT255_ERROR = (0x1UL << 7), /* Multi-GPD packet's GPD# > 255 */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_TOD_UNINIT = (0x1UL << 8), /* */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_PKT_ERROR_DROP = (0x1UL << 9), /* */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_UDSZ_DROP = (0x1UL << 10), /* */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_OVSZ_DROP = (0x1UL << 11), /* */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_CMDQ_OVF_DROP = (0x1UL << 12), /* */ + HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_FIFO_OVF_DROP = (0x1UL << 13) + +} HAL_LIGHTNING_PKT_RX_CHANNEL_L2_ISR_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_IOC = (0x1UL << 0), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_CHKSUM = (0x1UL << 1), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_PFC = (0x1UL << 2), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_PKT_LEN_CHK = (0x1UL << 3), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_EARLY_DONE_IRQ = (0x1UL << 4), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_CHK_COS = (0x1UL << 5), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_ADV_GPD_WRBK = (0x1UL << 6), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_GPD_WRBK_FULL_PKT_LEN = (0x1UL << 7), + HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_LAST = (0x1UL << 8) + +} HAL_LIGHTNING_PKT_TX_CHANNEL_CFG_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_RX_CHANNEL_CFG_IOC = (0x1UL << 0), + HAL_LIGHTNING_PKT_RX_CHANNEL_CFG_CHKSUM = (0x1UL << 1), + HAL_LIGHTNING_PKT_RX_CHANNEL_CFG_LAST = (0x1UL << 2) + +} HAL_LIGHTNING_PKT_RX_CHANNEL_CFG_T; + +/* ----------------------------------------------------------------------------------- Tx */ +typedef enum +{ + HAL_LIGHTNING_PKT_TX_CHANNEL_0 = 0, + HAL_LIGHTNING_PKT_TX_CHANNEL_1, + HAL_LIGHTNING_PKT_TX_CHANNEL_2, + HAL_LIGHTNING_PKT_TX_CHANNEL_3, + HAL_LIGHTNING_PKT_TX_CHANNEL_LAST + +} HAL_LIGHTNING_PKT_TX_CHANNEL_T; + +typedef void +(*HAL_LIGHTNING_PKT_TX_FUNC_T)( + const UI32_T unit, + const void *ptr_sw_gpd, /* SW-GPD to be processed */ + void *ptr_coockie); /* Private data of SDK */ + +typedef struct HAL_LIGHTNING_PKT_TX_SW_GPD_S +{ + HAL_LIGHTNING_PKT_TX_FUNC_T callback; /* (unit, ptr_sw_gpd, ptr_cookie) */ + void *ptr_cookie; /* Pointer of CLX_PKT_TX_PKT_T */ + HAL_LIGHTNING_PKT_TX_GPD_T tx_gpd; + UI32_T gpd_num; + struct HAL_LIGHTNING_PKT_TX_SW_GPD_S *ptr_next; + +#if defined (CLX_EN_NETIF) + UI32_T channel; /* For counter */ +#endif + +} HAL_LIGHTNING_PKT_TX_SW_GPD_T; + +typedef struct +{ + UI32_T send_ok; + UI32_T gpd_empty; + UI32_T poll_timeout; + + /* queue */ + UI32_T enque_ok; + UI32_T enque_retry; + + /* event */ + UI32_T trig_event; + + /* normal interrupt */ + UI32_T tx_done; + + /* abnormal interrupt */ + UI32_T gpd_hwo_err; /* bit-0 */ + UI32_T gpd_chksm_err; /* bit-1 */ + UI32_T gpd_no_ovfl_err; /* bit-2 */ + UI32_T gpd_dma_read_err; /* bit-3 */ + UI32_T buf_size_err; /* bit-4 */ + UI32_T runt_err; /* bit-5 */ + UI32_T ovsz_err; /* bit-6 */ + UI32_T len_mismatch_err; /* bit-7 */ + UI32_T pktpl_dma_read_err; /* bit-8 */ + UI32_T cos_err; /* bit-9 */ + UI32_T gpd_gt255_err; /* bit-10 */ + UI32_T pfc; /* bit-11 */ + UI32_T credit_udfl_err; /* bit-12 */ + UI32_T dma_write_err; /* bit-13 */ + UI32_T sw_issue_stop; /* bit-14 */ + + /* others */ + UI32_T err_recover; + UI32_T ecc_err; + +} HAL_LIGHTNING_PKT_TX_CHANNEL_CNT_T; + +typedef struct +{ + HAL_LIGHTNING_PKT_TX_CHANNEL_CNT_T channel[HAL_LIGHTNING_PKT_TX_CHANNEL_LAST]; + UI32_T invoke_gpd_callback; + UI32_T no_memory; + + /* queue */ + UI32_T deque_ok; + UI32_T deque_fail; + + /* event */ + UI32_T wait_event; + +} HAL_LIGHTNING_PKT_TX_CNT_T; + +/* ----------------------------------------------------------------------------------- Rx */ +typedef enum +{ + HAL_LIGHTNING_PKT_RX_CHANNEL_0 = 0, + HAL_LIGHTNING_PKT_RX_CHANNEL_1, + HAL_LIGHTNING_PKT_RX_CHANNEL_2, + HAL_LIGHTNING_PKT_RX_CHANNEL_3, + HAL_LIGHTNING_PKT_RX_CHANNEL_LAST +} HAL_LIGHTNING_PKT_RX_CHANNEL_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_C_NEXT = 0, /* callback continuous */ + HAL_LIGHTNING_PKT_C_STOP = 1, + HAL_LIGHTNING_PKT_C_OTHERS = 2 +} HAL_LIGHTNING_PKT_CALLBACK_NO_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_RX_CALLBACK_ACTION_INSERT = 0, + HAL_LIGHTNING_PKT_RX_CALLBACK_ACTION_APPEND = 1, + HAL_LIGHTNING_PKT_RX_CALLBACK_ACTION_DELETE = 2, + HAL_LIGHTNING_PKT_RX_CALLBACK_ACTION_DELETE_ALL = 3 +} HAL_LIGHTNING_PKT_RX_CALLBACK_ACTION_T; + +typedef HAL_LIGHTNING_PKT_CALLBACK_NO_T +(*HAL_LIGHTNING_PKT_RX_FUNC_T)( + const UI32_T unit, + const void *ptr_sw_gpd, /* SW-GPD to be processed */ + void *ptr_cookie); /* Private data of SDK */ + +typedef struct HAL_LIGHTNING_PKT_RX_CALLBACK_S +{ + HAL_LIGHTNING_PKT_RX_FUNC_T callback; /* (unit, ptr_sw_gpd, ptr_cookie) */ + void *ptr_cookie; + struct HAL_LIGHTNING_PKT_RX_CALLBACK_S *ptr_next; +} HAL_LIGHTNING_PKT_RX_CALLBACK_T; + +typedef struct HAL_LIGHTNING_PKT_RX_SW_GPD_S +{ + BOOL_T rx_complete; /* FALSE when PDMA error occurs */ + HAL_LIGHTNING_PKT_RX_GPD_T rx_gpd; + struct HAL_LIGHTNING_PKT_RX_SW_GPD_S *ptr_next; + +#if defined (CLX_EN_NETIF) + void *ptr_cookie; /* Pointer of virt-addr */ +#endif + +} HAL_LIGHTNING_PKT_RX_SW_GPD_T; + +typedef struct +{ + /* queue */ + UI32_T enque_ok; + UI32_T enque_retry; + UI32_T deque_ok; + UI32_T deque_fail; + + /* event */ + UI32_T trig_event; + + /* normal interrupt */ + UI32_T rx_done; + + /* abnormal interrupt */ + UI32_T avbl_gpd_low; /* bit-0 */ + UI32_T avbl_gpd_empty; /* bit-1 */ + UI32_T avbl_gpd_err; /* bit-2 */ + UI32_T gpd_chksm_err; /* bit-3 */ + UI32_T dma_read_err; /* bit-4 */ + UI32_T dma_write_err; /* bit-5 */ + UI32_T sw_issue_stop; /* bit-6 */ + UI32_T gpd_gt255_err; /* bit-7 */ + UI32_T tod_uninit; /* bit-8 */ + UI32_T pkt_err_drop; /* bit-9 */ + UI32_T udsz_drop; /* bit-10 */ + UI32_T ovsz_drop; /* bit-11 */ + UI32_T cmdq_ovf_drop; /* bit-12 */ + UI32_T fifo_ovf_drop; /* bit-13 */ + + /* others */ + UI32_T err_recover; + UI32_T ecc_err; + +#if defined (CLX_EN_NETIF) + /* it means that user doesn't create intf on that port */ + UI32_T netdev_miss; +#endif + + +} HAL_LIGHTNING_PKT_RX_CHANNEL_CNT_T; + +typedef struct +{ + HAL_LIGHTNING_PKT_RX_CHANNEL_CNT_T channel[HAL_LIGHTNING_PKT_RX_CHANNEL_LAST]; + UI32_T invoke_gpd_callback; + UI32_T no_memory; + + /* event */ + UI32_T wait_event; + +} HAL_LIGHTNING_PKT_RX_CNT_T; + +/* ----------------------------------------------------------------------------------- Reg */ +#if defined(CLX_EN_LITTLE_ENDIAN) + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_axlen_cfg : 3; + UI32_T : 5; + UI32_T tch_axi_free_arvalid : 1; + UI32_T : 7; + UI32_T tch_arvalid_thrhold_cfg : 2; + UI32_T : 6; + UI32_T tch_rready_low_4_hdr : 1; + UI32_T tch_ios_crdt_add_en : 1; + UI32_T : 6; + } field; +} HAL_LIGHTNING_PKT_AXI_LEN_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_lbk_en : 1; + UI32_T : 3; + UI32_T pdma_lbk_plane : 2; + UI32_T : 2; + UI32_T pm_lbk_en : 1; + UI32_T : 7; + UI32_T pm_lbk_rqid : 6; + UI32_T : 2; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_LBK_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_lbk_rqid0 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid1 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid2 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid3 : 6; + UI32_T : 2; + } field; +} HAL_LIGHTNING_PKT_LBK_RQID0_3_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_lbk_rqid4 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid5 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid6 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid7 : 6; + UI32_T : 2; + } field; +} HAL_LIGHTNING_PKT_LBK_RQID4_7_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T cos_pfc_sts0 : 8; + UI32_T cos_pfc_sts1 : 8; + UI32_T cos_pfc_sts2 : 8; + UI32_T cos_pfc_sts3 : 8; + } field; +} HAL_LIGHTNING_PKT_COS_PFC_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_ela_en : 1; + UI32_T : 7; + UI32_T pdma_ela_valid_sel : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_ELA_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_ela_word0_sel : 8; + UI32_T pdma_ela_word1_sel : 8; + UI32_T pdma_ela_word2_sel : 8; + UI32_T pdma_ela_word3_sel : 8; + } field; +} HAL_LIGHTNING_PKT_ELA_SEL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T ingr_pln_ios_credit_base_size_lo : 8; + UI32_T ingr_pln_ios_credit_base_size_hi : 8; + UI32_T ingr_pln_ios_credit_set : 1; + UI32_T : 7; + UI32_T : 1; + UI32_T ingr_pln_full_pkt_mode : 1; + UI32_T : 6; + } field; +} HAL_LIGHTNING_PKT_IGR_PLN_CREDIT_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T ingr_pln_cur_ios_credit_lo : 8; + UI32_T ingr_pln_cur_ios_credit_hi : 8; + UI32_T ingr_pln_ios_credit_ovfl : 1; + UI32_T ingr_pln_ios_credit_udfl : 1; + UI32_T : 6; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_IGR_PLN_CREDIT_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T ingr_pln_ios_credit_rdy_lo_bound : 8; + UI32_T ingr_pln_ios_credit_rdy_hi_bound : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_IGR_PLN_CREDIT_THR_REG_T; + + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_stomp_crc_en : 1; + UI32_T : 7; + UI32_T rch_crc_regen_en : 1; + UI32_T : 7; + UI32_T rch_pfc_fun_en : 1; + UI32_T : 7; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_STOMP_CRC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_ioc_en : 1; + UI32_T : 7; + UI32_T rch_chksm_en : 1; + UI32_T : 7; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_MISC_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_gpd_pfc_lo : 8; + UI32_T rch_gpd_pfc_hi : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_GPD_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_fifo_pfc_lo_lo : 8; + UI32_T rch_fifo_pfc_lo_hi : 3; + UI32_T : 5; + UI32_T rch_fifo_pfc_hi_lo : 8; + UI32_T rch_fifo_pfc_hi_hi : 3; + UI32_T : 5; + } field; +} HAL_LIGHTNING_PKT_RCH_FIFO_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_cmdq_pfc_lo : 5; + UI32_T : 3; + UI32_T rch_cmdq_pfc_hi : 5; + UI32_T : 3; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_CMDQ_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_start : 1; + UI32_T rch_resume : 1; + UI32_T rch_stop : 1; + UI32_T : 5; + UI32_T : 8; + UI32_T rch_gpd_add_no_lo : 8; + UI32_T rch_gpd_add_no_hi : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_fifo_ovf_drop_cnt_clr : 1; + UI32_T rch_cmdq_ovf_drop_cnt_clr : 1; + UI32_T rch_ovsz_drop_cnt_clr : 1; + UI32_T rch_udsz_drop_cnt_clr : 1; + UI32_T rch_pkterr_drop_cnt_clr : 1; + UI32_T rch_flush_cnt_clr : 1; + UI32_T : 2; + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_CNT_CLR_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_active : 1; + UI32_T rch_avbl_gpd_pfc : 1; + UI32_T rch_fifo_pfc : 1; + UI32_T rch_cmdq_pfc : 1; + UI32_T rch_pfc : 1; + UI32_T : 3; + UI32_T : 8; + UI32_T rch_avbl_gpd_no_lo : 8; + UI32_T rch_avbl_gpd_no_hi : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_STATUS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_ioc_en : 1; + UI32_T tch_chksm_en : 1; + UI32_T tch_pfc_en : 1; + UI32_T tch_pktlen_chk_en : 1; + UI32_T tch_early_done_irq : 1; + UI32_T tch_chk_cos_en : 1; + UI32_T tch_adv_gpd_wrbk : 1; + UI32_T tch_gpd_wrbk_full_pkt_len : 1; + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_TCH_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_start : 1; + UI32_T tch_resume : 1; + UI32_T tch_stop : 1; + UI32_T : 5; + UI32_T : 8; + UI32_T tch_gpd_add_no_lo : 8; + UI32_T tch_gpd_add_no_hi : 8; + } field; +} HAL_LIGHTNING_PKT_TCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_active : 1; + UI32_T tch_pfc : 1; + UI32_T tch_gpd_rd_dma_act : 1; + UI32_T : 5; + UI32_T : 8; + UI32_T tch_avbl_gpd_no : 1; + UI32_T : 7; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_TCH_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_gpd_dmar_qos : 4; + UI32_T : 4; + UI32_T tch_pkt_dmar_qos : 4; + UI32_T : 4; + UI32_T tch_gpd_dmaw_qos : 4; + UI32_T : 4; + UI32_T : 8; + } field; +} HAL_LIGHTNING_PKT_TCH_QOS_CFG_REG_T; + +#elif defined(CLX_EN_BIG_ENDIAN) + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 6; + UI32_T tch_ios_crdt_add_en : 1; + UI32_T tch_rready_low_4_hdr : 1; + UI32_T : 6; + UI32_T tch_arvalid_thrhold_cfg : 2; + UI32_T : 7; + UI32_T tch_axi_free_arvalid : 1; + UI32_T : 5; + UI32_T tch_axlen_cfg : 3; + } field; +} HAL_LIGHTNING_PKT_AXI_LEN_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 2; + UI32_T pm_lbk_rqid : 6; + UI32_T : 7; + UI32_T pm_lbk_en : 1; + UI32_T : 2; + UI32_T pdma_lbk_plane : 2; + UI32_T : 3; + UI32_T pdma_lbk_en : 1; + } field; +} HAL_LIGHTNING_PKT_LBK_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 2; + UI32_T pdma_lbk_rqid3 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid2 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid1 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid0 : 6; + } field; +} HAL_LIGHTNING_PKT_LBK_RQID0_3_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 2; + UI32_T pdma_lbk_rqid7 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid6 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid5 : 6; + UI32_T : 2; + UI32_T pdma_lbk_rqid4 : 6; + } field; +} HAL_LIGHTNING_PKT_LBK_RQID4_7_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T cos_pfc_sts3 : 8; + UI32_T cos_pfc_sts2 : 8; + UI32_T cos_pfc_sts1 : 8; + UI32_T cos_pfc_sts0 : 8; + } field; +} HAL_LIGHTNING_PKT_COS_PFC_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T pdma_ela_valid_sel : 8; + UI32_T : 7; + UI32_T pdma_ela_en : 1; + } field; +} HAL_LIGHTNING_PKT_ELA_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T pdma_ela_word3_sel : 8; + UI32_T pdma_ela_word2_sel : 8; + UI32_T pdma_ela_word1_sel : 8; + UI32_T pdma_ela_word0_sel : 8; + } field; +} HAL_LIGHTNING_PKT_ELA_SEL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 6; + UI32_T ingr_pln_full_pkt_mode : 1; + UI32_T : 1; + UI32_T : 7; + UI32_T ingr_pln_ios_credit_set : 1; + UI32_T ingr_pln_ios_credit_base_size_hi : 8; + UI32_T ingr_pln_ios_credit_base_size_lo : 8; + } field; +} HAL_LIGHTNING_PKT_IGR_PLN_CREDIT_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 6; + UI32_T ingr_pln_ios_credit_udfl : 1; + UI32_T ingr_pln_ios_credit_ovfl : 1; + UI32_T ingr_pln_cur_ios_credit_hi : 8; + UI32_T ingr_pln_cur_ios_credit_lo : 8; + } field; +} HAL_LIGHTNING_PKT_IGR_PLN_CREDIT_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T ingr_pln_ios_credit_rdy_hi_bound : 8; + UI32_T ingr_pln_ios_credit_rdy_lo_bound : 8; + } field; +} HAL_LIGHTNING_PKT_IGR_PLN_CREDIT_THR_REG_T; + + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 7; + UI32_T rch_pfc_fun_en : 1; + UI32_T : 7; + UI32_T rch_crc_regen_en : 1; + UI32_T : 7; + UI32_T rch_stomp_crc_en : 1; + } field; +} HAL_LIGHTNING_PKT_RCH_STOMP_CRC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 7; + UI32_T rch_chksm_en : 1; + UI32_T : 7; + UI32_T rch_ioc_en : 1; + } field; +} HAL_LIGHTNING_PKT_RCH_MISC_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T rch_gpd_pfc_hi : 8; + UI32_T rch_gpd_pfc_lo : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_GPD_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 5; + UI32_T rch_fifo_pfc_hi_hi : 3; + UI32_T rch_fifo_pfc_hi_lo : 8; + UI32_T : 5; + UI32_T rch_fifo_pfc_lo_hi : 3; + UI32_T rch_fifo_pfc_lo_lo : 8; + } field; +} HAL_LIGHTNING_PKT_RCH_FIFO_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 3; + UI32_T rch_cmdq_pfc_hi : 5; + UI32_T : 3; + UI32_T rch_cmdq_pfc_lo : 5; + } field; +} HAL_LIGHTNING_PKT_RCH_CMDQ_PFC_CTRL_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_gpd_add_no_hi : 8; + UI32_T rch_gpd_add_no_lo : 8; + UI32_T : 8; + UI32_T : 5; + UI32_T rch_stop : 1; + UI32_T rch_resume : 1; + UI32_T rch_start : 1; + } field; +} HAL_LIGHTNING_PKT_RCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + UI32_T : 2; + UI32_T rch_flush_cnt_clr : 1; + UI32_T rch_pkterr_drop_cnt_clr : 1; + UI32_T rch_udsz_drop_cnt_clr : 1; + UI32_T rch_ovsz_drop_cnt_clr : 1; + UI32_T rch_cmdq_ovf_drop_cnt_clr : 1; + UI32_T rch_fifo_ovf_drop_cnt_clr : 1; + } field; +} HAL_LIGHTNING_PKT_RCH_CNT_CLR_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T rch_avbl_gpd_no_hi : 8; + UI32_T rch_avbl_gpd_no_lo : 8; + UI32_T : 8; + UI32_T : 3; + UI32_T rch_pfc : 1; + UI32_T rch_cmdq_pfc : 1; + UI32_T rch_fifo_pfc : 1; + UI32_T rch_avbl_gpd_pfc : 1; + UI32_T rch_active : 1; + } field; +} HAL_LIGHTNING_PKT_RCH_STATUS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 8; + UI32_T : 8; + UI32_T tch_gpd_wrbk_full_pkt_len : 1; + UI32_T tch_adv_gpd_wrbk : 1; + UI32_T tch_chk_cos_en : 1; + UI32_T tch_early_done_irq : 1; + UI32_T tch_pktlen_chk_en : 1; + UI32_T tch_pfc_en : 1; + UI32_T tch_chksm_en : 1; + UI32_T tch_ioc_en : 1; + } field; +} HAL_LIGHTNING_PKT_TCH_CFG_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T tch_gpd_add_no_hi : 8; + UI32_T tch_gpd_add_no_lo : 8; + UI32_T : 8; + UI32_T : 5; + UI32_T tch_stop : 1; + UI32_T tch_resume : 1; + UI32_T tch_start : 1; + } field; +} HAL_LIGHTNING_PKT_TCH_CMD_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 7; + UI32_T tch_avbl_gpd_no : 1; + UI32_T : 8; + UI32_T : 5; + UI32_T tch_gpd_rd_dma_act : 1; + UI32_T tch_pfc : 1; + UI32_T tch_active : 1; + } field; +} HAL_LIGHTNING_PKT_TCH_STS_REG_T; + +typedef union +{ + UI32_T reg; + struct + { + UI32_T : 8; + UI32_T : 4; + UI32_T tch_gpd_dmaw_qos : 4; + UI32_T : 4; + UI32_T tch_pkt_dmar_qos : 4; + UI32_T : 4; + UI32_T tch_gpd_dmar_qos : 4; + } field; +} HAL_LIGHTNING_PKT_TCH_QOS_CFG_REG_T; + +#else +#error "Host GPD endian is not defined\n" +#endif + +/* ----------------------------------------------------------------------------------- CLX_EN_NETIF */ +#if defined (CLX_EN_NETIF) +#define HAL_LIGHTNING_PKT_DRIVER_MAJOR_NUM (10) +#define HAL_LIGHTNING_PKT_DRIVER_MINOR_NUM (252) /* DO NOT use MISC_DYNAMIC_MINOR */ +#define HAL_LIGHTNING_PKT_DRIVER_NAME "clx_netif" +#define HAL_LIGHTNING_PKT_DRIVER_PATH "/dev/"HAL_LIGHTNING_PKT_DRIVER_NAME + +/* These requirements come from CLX_NETIF APIs. + * clx_netif -> hal_lightning_pkt_drv -> hal_lightning_pkt_knl + */ + +typedef struct +{ + UI32_T tx_pkt; + UI32_T tx_queue_full; + UI32_T tx_error; + UI32_T rx_pkt; + +} HAL_LIGHTNING_PKT_NETIF_INTF_CNT_T; + +typedef struct +{ + /* unique key */ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + UI32_T port; /* only support unit port and local port */ + + /* metadata */ + UI8_T mac[6]; + +#define HAL_LIGHTNING_PKT_NETIF_INTF_FLAGS_MAC (1UL << 0) + UI32_T flags; + + +} HAL_LIGHTNING_PKT_NETIF_INTF_T; + +#if defined(NETIF_EN_NETLINK) +typedef struct +{ + C8_T name[CLX_NETIF_NAME_LEN]; + C8_T mc_group_name[CLX_NETIF_NAME_LEN]; +} HAL_LIGHTNING_PKT_NETIF_RX_DST_NETLINK_T; +#endif + +typedef enum +{ + HAL_LIGHTNING_PKT_NETIF_RX_DST_SDK = 0, +#if defined(NETIF_EN_NETLINK) + HAL_LIGHTNING_PKT_NETIF_RX_DST_NETLINK, +#endif + HAL_LIGHTNING_PKT_NETIF_RX_DST_LAST +} HAL_LIGHTNING_PKT_NETIF_RX_DST_TYPE_T; + +typedef struct +{ + /* unique key */ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + UI32_T priority; + + /* match fields */ + UI32_T port; /* only support unit port and local port */ + HAL_PKT_RX_REASON_BITMAP_T reason_bitmap; + UI8_T pattern[CLX_NETIF_PROFILE_PATTERN_NUM][CLX_NETIF_PROFILE_PATTERN_LEN]; + UI8_T mask[CLX_NETIF_PROFILE_PATTERN_NUM][CLX_NETIF_PROFILE_PATTERN_LEN]; + UI32_T offset[CLX_NETIF_PROFILE_PATTERN_NUM]; + + /* for each flag 1:must hit, 0:don't care */ +#define HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PORT (1UL << 0) +#define HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_REASON (1UL << 1) +#define HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_0 (1UL << 2) +#define HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_1 (1UL << 3) +#define HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_2 (1UL << 4) +#define HAL_LIGHTNING_PKT_NETIF_PROFILE_FLAGS_PATTERN_3 (1UL << 5) + UI32_T flags; + + HAL_LIGHTNING_PKT_NETIF_RX_DST_TYPE_T dst_type; +#if defined(NETIF_EN_NETLINK) + HAL_LIGHTNING_PKT_NETIF_RX_DST_NETLINK_T netlink; +#endif + +} HAL_LIGHTNING_PKT_NETIF_PROFILE_T; + + +/* These requirements come from CLX_PKT APIs. + * clx_pkt -> hal_lightning_pkt_srv -> hal_lightning_pkt_drv -> hal_lightning_pkt_knl + */ +typedef enum +{ + /* network interface */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_CREATE_INTF = 0, + HAL_LIGHTNING_PKT_IOCTL_TYPE_DESTROY_INTF, + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_INTF, + HAL_LIGHTNING_PKT_IOCTL_TYPE_CREATE_PROFILE, + HAL_LIGHTNING_PKT_IOCTL_TYPE_DESTROY_PROFILE, + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_PROFILE, + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_INTF_CNT, + HAL_LIGHTNING_PKT_IOCTL_TYPE_CLEAR_INTF_CNT, + /* driver */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_WAIT_RX_FREE, + HAL_LIGHTNING_PKT_IOCTL_TYPE_WAIT_TX_FREE, /* waitTxFree(ASYNC) */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_SET_RX_CFG, /* setRxConfig */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_RX_CFG, /* getRxConfig */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_DEINIT_TASK, /* deinitTask */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_DEINIT_DRV, /* deinitDrv */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_INIT_TASK, /* initTask */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_INIT_DRV, /* initDrv */ + /* counter */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_TX_CNT, + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_RX_CNT, + HAL_LIGHTNING_PKT_IOCTL_TYPE_CLEAR_TX_CNT, + HAL_LIGHTNING_PKT_IOCTL_TYPE_CLEAR_RX_CNT, + /* port attribute */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_SET_PORT_ATTR, + HAL_LIGHTNING_PKT_IOCTL_TYPE_GET_PORT_ATTR, +#if defined(NETIF_EN_NETLINK) + HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_SET_INTF_PROPERTY, + HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_GET_INTF_PROPERTY, + HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_CREATE_NETLINK, + HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_DESTROY_NETLINK, + HAL_LIGHTNING_PKT_IOCTL_TYPE_NL_GET_NETLINK, +#endif + HAL_LIGHTNING_PKT_IOCTL_TYPE_LAST + +} HAL_LIGHTNING_PKT_IOCTL_TYPE_T; + +typedef enum +{ + HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_INIT = 0, + HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_DEINIT, + HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_LAST, + +} HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; + HAL_LIGHTNING_PKT_RX_CNT_T rx_cnt; + HAL_LIGHTNING_PKT_TX_CNT_T tx_cnt; + CLX_ERROR_NO_T rc; + +} HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T; + +typedef struct +{ + UI32_T unit; + HAL_LIGHTNING_PKT_NETIF_INTF_T net_intf; /* addIntf[In,Out], delIntf[In] */ + HAL_LIGHTNING_PKT_NETIF_PROFILE_T net_profile; /* createProfile[In,Out], destroyProfile[In] */ + HAL_LIGHTNING_PKT_NETIF_INTF_CNT_T cnt; + CLX_ERROR_NO_T rc; + +} HAL_LIGHTNING_PKT_IOCTL_NETIF_COOKIE_T; + +typedef struct +{ + CLX_ADDR_T callback; /* (unit, ptr_sw_gpd, ptr_cookie) */ + CLX_ADDR_T cookie; /* Pointer of CLX_PKT_TX_PKT_T */ + UI32_T channel; + UI32_T gpd_num; + CLX_ADDR_T hw_gpd_addr; + CLX_ADDR_T sw_gpd_addr; + +} HAL_LIGHTNING_PKT_IOCTL_TX_GPD_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; /* sendGpd[In] */ + CLX_ADDR_T ioctl_gpd_addr; /* sendGpd[In] */ + CLX_ADDR_T done_sw_gpd_addr; /* waitTxFree[Out] */ + +} HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T; + +typedef struct +{ + BOOL_T rx_complete; /* FALSE when PDMA error occurs */ + CLX_ADDR_T hw_gpd_addr; /* Pointer to HW GPD in user's SW GPD struct */ + CLX_ADDR_T dma_buf_addr; /* Pointer to DMA buffer allocated by the user (virtual) */ + +} HAL_LIGHTNING_PKT_IOCTL_RX_GPD_T; + +typedef struct +{ + UI32_T unit; + UI32_T channel; /* getRxCnt[In], clearRxInt[In] */ + CLX_ADDR_T ioctl_gpd_addr; /* waitRxFree[Out] */ + UI32_T buf_len; /* setRxCfg[In] */ + HAL_LIGHTNING_PKT_IOCTL_RX_TYPE_T rx_type; /* setRxCfg[In] */ + +} HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T; + +typedef struct +{ + UI32_T port; + UI32_T status; + CLX_PORT_SPEED_T speed; + +} HAL_LIGHTNING_PKT_IOCTL_PORT_COOKIE_T; + + +#if defined(NETIF_EN_NETLINK) + +typedef struct +{ + /* intf property */ + UI32_T intf_id; + CLX_NETIF_INTF_PROPERTY_T property; + UI32_T param0; + UI32_T param1; + + /* netlink */ + CLX_NETIF_NETLINK_T netlink; + + CLX_ERROR_NO_T rc; + +} HAL_LIGHTNING_PKT_NL_IOCTL_COOKIE_T; + + +#endif /* End of NETIF_EN_NETLINK */ + +typedef union +{ + UI32_T value; + struct + { + UI32_T unit : 6; /* Maximum unit number is 64. */ + HAL_LIGHTNING_PKT_IOCTL_TYPE_T type : 10; /* Maximum 1024 IOCTL types */ + UI32_T rsvd : 16; + } field; + +} HAL_LIGHTNING_PKT_IOCTL_CMD_T; + +#endif /* End of CLX_EN_NETIF */ + +//} +/*---------------------------------------------------------------------------*/ +/* perf */ +CLX_ERROR_NO_T +hal_lightning_pkt_getTxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt); + +CLX_ERROR_NO_T +hal_lightning_pkt_getRxIntrCnt( + const UI32_T unit, + const UI32_T channel, + UI32_T *ptr_intr_cnt); + +/* ioctl */ +CLX_ERROR_NO_T +hal_lightning_pkt_getTxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_lightning_pkt_getRxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_CH_CNT_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_lightning_pkt_clearTxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_TX_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_lightning_pkt_clearRxKnlCnt( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_lightning_pkt_setRxKnlConfig( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie); + +CLX_ERROR_NO_T +hal_lightning_pkt_getRxKnlConfig( + const UI32_T unit, + HAL_LIGHTNING_PKT_IOCTL_RX_COOKIE_T *ptr_cookie); + +/* perf */ +CLX_ERROR_NO_T +hal_lightning_pkt_getNetDev( + const UI32_T unit, + const UI32_T port, + struct net_device **pptr_net_dev); + +CLX_ERROR_NO_T +hal_lightning_pkt_prepareGpd( + const UI32_T unit, + const CLX_ADDR_T phy_addr, + const struct sk_buff *ptr_skb, + const UI32_T port, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd); + +CLX_ERROR_NO_T +hal_lightning_pkt_sendGpd( + const UI32_T unit, + const HAL_LIGHTNING_PKT_TX_CHANNEL_T channel, + HAL_LIGHTNING_PKT_TX_SW_GPD_T *ptr_sw_gpd); + +CLX_ERROR_NO_T +hal_lightning_pkt_init( + const UI32_T unit); + +CLX_ERROR_NO_T +hal_lightning_pkt_exit( + const UI32_T unit); + +ssize_t +hal_lightning_pkt_dev_tx( + struct file *file, + const char __user *buf, + size_t count, + loff_t *pos); + +long +hal_lightning_pkt_dev_ioctl( + struct file *filp, + unsigned int cmd, + unsigned long arg); + +#endif /* end of HAL_LIGHTNING_PKT_KNL_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/netif_knl.h b/platform/clounix/clounix-modules/modules/src/inc/netif_knl.h new file mode 100644 index 000000000000..a6d83df90ad1 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/netif_knl.h @@ -0,0 +1,477 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_knl.h + * NOTES: + */ +#ifndef NETIF_KNL_H +#define NETIF_KNL_H + +#include +#include + +#define CLX_NETIF_NAME_LEN (16) +#define CLX_NETIF_PROFILE_NUM_MAX (256) +#define CLX_NETIF_PROFILE_PATTERN_NUM (4) +#define CLX_NETIF_PROFILE_PATTERN_LEN (8) + +#define NETIF_EN_NETLINK + +/* Port Speed */ +typedef enum +{ + CLX_PORT_SPEED_1G = 1000, + CLX_PORT_SPEED_10G = 10000, + CLX_PORT_SPEED_25G = 25000, + CLX_PORT_SPEED_40G = 40000, + CLX_PORT_SPEED_50G = 50000, + CLX_PORT_SPEED_100G = 100000, + CLX_PORT_SPEED_200G = 200000, + CLX_PORT_SPEED_400G = 400000, + CLX_PORT_SPEED_LAST +} CLX_PORT_SPEED_T; + +#define HAL_INVALID_GROUP_LABEL (0) +#define HAL_INVALID_NVO3_ENCAP_IDX (0x3FFF) +#define HAL_INVALID_NVO3_ADJ_IDX (0xFF) +#define HAL_INVALID_LCL_INTF_GRP (0x1FFF) +#define HAL_INVALID_CNT_MTR_IDX (0x7FFF) +#define HAL_INVALID_FDID (0) /* means fdid is not created */ +#define HAL_INVALID_L3_INTF (0) /* means L3 interface is disabled */ +#define HAL_INVALID_FRR_STATE_IDX (0) /* means ECMP FRR is disabled */ +#define HAL_INVALID_SEG_VMID (0xFFFFFF) +#define HAL_INVALID_CPU_ID (0x1F) +#define HAL_INVALID_DOS_IDX (0xF) +#define HAL_INVALID_HW_BUM_OFFSET (0x3) +#define HAL_INVALID_IEV_RSLT_IDX (0x3FFFF) +#define HAL_INVALID_PHB_HW_IDX (0x1F) /* SRV INTF uses invalid index */ +#define HAL_DEFAULT_PHB_HW_IDX (0x1F) /* LCL INTF uses default index */ +#define HAL_RSV_FDID (0x3FFF) /* HW reserved; all 1 means use outer vid as FDID */ +#define HAL_RSV_L3_INTF (0x3FFF) /* HW reserved; all 1 means use outer vid as L3 Intf */ + /* all 1 means invalid at egress side */ +#define HAL_INVALID_ADJ_IDX (0x3FFFF) /* For 18bit adj_idx */ +#define HAL_INVALID_MTR_HW_IDX (0x1FFFF) +#define HAL_RSV_MEL_IDX (0x1FFF) + +#define HAL_LAG_PORT_NUM (512) +#define HAL_L2_MGID_NUM (16384) /* non-replicate mgid */ +#define HAL_L3_MGID_NUM (8192) /* replicate mgid */ +#define HAL_MGID_NUM (HAL_L2_MGID_NUM + HAL_L3_MGID_NUM) +#define HAL_EXCPT_CPU_NUM (256) +#define HAL_EXCPT_DROP_NUM (256) +#define HAL_DROP_NUM (512) +#define HAL_MIRROR_NUM (256) +#define HAL_REDIRECT_CPU_NUM (2048) +#define HAL_TUNNEL_NUM (8192) +#define HAL_NSH_NUM (8192) +#define HAL_FRR_NUM (4096) +#define HAL_ECMP_NUM (2048) +#define HAL_INVALID_NUM (10240) + +#define HAL_EXCPT_CPU_BASE_ID (28 * 1024) +#define HAL_EXCPT_CPU_NON_L3_MIN (0) +#define HAL_EXCPT_CPU_NON_L3_MAX (HAL_EXCPT_CPU_NON_L3_MIN + HAL_EXCPT_CPU_NUM - 1) +#define HAL_EXCPT_CPU_L3_MIN (HAL_EXCPT_CPU_NON_L3_MIN + HAL_EXCPT_CPU_NUM) +#define HAL_EXCPT_CPU_L3_MAX (HAL_EXCPT_CPU_L3_MIN + HAL_EXCPT_CPU_NUM - 1) + +#if defined(NETIF_EN_NETLINK) + +#define CLX_NETIF_NETLINK_NUM_MAX (256) +#define CLX_NETIF_NETLINK_MC_GROUP_NUM_MAX (32) + +typedef enum +{ + CLX_NETIF_INTF_PROPERTY_IGR_SAMPLING_RATE, + CLX_NETIF_INTF_PROPERTY_EGR_SAMPLING_RATE, + CLX_NETIF_INTF_PROPERTY_LAST +} CLX_NETIF_INTF_PROPERTY_T; + +typedef struct +{ + C8_T name[CLX_NETIF_NAME_LEN]; + +} CLX_NETIF_NETLINK_MC_GROUP_T; + +typedef struct +{ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + CLX_NETIF_NETLINK_MC_GROUP_T mc_group[CLX_NETIF_NETLINK_MC_GROUP_NUM_MAX]; + UI32_T mc_group_num; + +} CLX_NETIF_NETLINK_T; + +#endif + +/* The reason defiend for the packets which are copied/redirected to CPU. */ + +/* RX Packet Reasons */ +typedef enum +{ + CLX_PKT_RX_REASON_ECIA_SFLOW = 0, /* Egress flow-based sflow hit. */ + CLX_PKT_RX_REASON_VLAN_MISS_VLAN_CHK, /* VLAN lookup miss or not accepted. */ + CLX_PKT_RX_REASON_PAR_ERR, /* Parser error to CPU. */ + CLX_PKT_RX_REASON_PAR_WARN, /* Parser warning to CPU. */ + CLX_PKT_RX_REASON_DOS_CHK, /* DoS checking fail to CPU. */ + CLX_PKT_RX_REASON_BFD_CTRL_PKT, /* BFD control packet to CPU. */ + CLX_PKT_RX_REASON_INVALID_BFD_PKT, /* Invalid BFD control packet to CPU. */ + CLX_PKT_RX_REASON_SA_LEARN_FAIL, /* Add to l2fdb fail to CPU. */ + CLX_PKT_RX_REASON_TUNNEL_ECN_CU, /* The current unused ECN combination defined in RFC6040. */ + CLX_PKT_RX_REASON_FCOE_CLASS_2_F, /* Copy FCoE Class 2 packet to cpu when packet is dropped. */ + CLX_PKT_RX_REASON_URPF_CHECK_FAIL, /* L3 URPF check fail to CPU. */ + CLX_PKT_RX_REASON_L3_LKP_MISS, /* L3 lookup miss to CPU. */ + CLX_PKT_RX_REASON_ICMP_REDIRECT, /* The same L3 interface for ingress and egress to CPU. */ + CLX_PKT_RX_REASON_IPV4_HDR_OPTION, /* IPv4 header with option to CPU. */ + CLX_PKT_RX_REASON_VCLAG_INVALID, /* VM tag invalid to CPU. */ + CLX_PKT_RX_REASON_VM_RPF_FAIL, /* VM RPF check fail to CPU. */ + /* 16 */ + CLX_PKT_RX_REASON_VM_L2_FDB_MISS, /* VM l2fdb lookup miss to CPU. */ + CLX_PKT_RX_REASON_IGR_PORT_SFLOW, /* Ingress port-based sflow hit. */ + CLX_PKT_RX_REASON_EGR_PORT_SFLOW, /* Egress port-based sflow hit. */ + CLX_PKT_RX_REASON_IGR_FD_SFLOW, /* Ingress fd-based sflow hit. */ + CLX_PKT_RX_REASON_ICIA_SFLOW, /* Ingress flow-based sflow hit. */ + CLX_PKT_RX_REASON_IPSG_CHK, /* IPSG check fail to CPU. */ + CLX_PKT_RX_REASON_FCOE_IFR_TO_CPU, /* FCoE extend header include IFR header. */ + CLX_PKT_RX_REASON_TTL_EXPIRE, /* L3 TTL check fail to CPU. */ + CLX_PKT_RX_REASON_L3MC_RPF_CHECK, /* L3MC RPF check fail to CPU */ + CLX_PKT_RX_REASON_IPV6_HOP_BY_HOP_EXT_HDR, /* IPv6 with hop by hop extension header to CPU. */ + CLX_PKT_RX_REASON_VM_PDU, /* Received frames whose E-CID matches the IBR upstream Port's PCID. */ + CLX_PKT_RX_REASON_PIM_REGISTER, /* For source hit and group miss, send to CPU for PIM-registration. */ + CLX_PKT_RX_REASON_TUNNEL_TERM_LKP_MISS, /* Tunnel term lookup failed with bank error or entry miss. */ + CLX_PKT_RX_REASON_PP, /* Protocol/Management packet for SDN. */ + CLX_PKT_RX_REASON_EGR_FD_SFLOW, /* Egress fd-based sflow hit. */ + CLX_PKT_RX_REASON_VXLAN_ROUTER_ALERT, /* VXLAN packet with router alert to CPU. */ + /* 32 */ + CLX_PKT_RX_REASON_NVGRE_ROUTER_ALERT, /* NVGRE packet with router alert to CPU. */ + CLX_PKT_RX_REASON_EX_PMOD_LIMIT, /* Packet modification is excess PMOD's limitation. */ + CLX_PKT_RX_REASON_L3MC_SPT_READY_UNSET, /* L3MC to CPU to trigger setting Shortest Path Tree ready bit. */ + CLX_PKT_RX_REASON_IGR_MTU_FAIL, /* Ingress MTU check fail to CPU. */ + CLX_PKT_RX_REASON_EGR_MTU_FAIL, /* Egress MTU check fail to CPU. */ + CLX_PKT_RX_REASON_VXLAN_PING, /* VXLAN packet to CPU. */ + CLX_PKT_RX_REASON_REDIRECT_TO_CPU_L2MC, /* L2MC Redirect to CPU. */ + CLX_PKT_RX_REASON_REDIRECT_TO_CPU_L3MC, /* L3MC Redirect to CPU. */ + CLX_PKT_RX_REASON_REDIRECT_TO_CPU_L2UC, /* L2UC Redirect to CPU. */ + CLX_PKT_RX_REASON_REDIRECT_TO_CPU_L3UC, /* L3UC Redirect to CPU. */ + CLX_PKT_RX_REASON_SDN_IGR_FLOW_SFLOW, /* SDN ingress flow-based sflow hit. */ + CLX_PKT_RX_REASON_SDN_EGR_FLOW_SFLOW, /* SDN egress flow-based sflow hit. */ + CLX_PKT_RX_REASON_SDN_HW_LIMITATION, /* SDN hardware limitation to CPU. */ + CLX_PKT_RX_REASON_SDN_OTHERS, /* SDN other exceptions to CPU. */ + CLX_PKT_RX_REASON_SDN_PKT_IN, /* SDN output controller port (packet-in) to CPU. */ + CLX_PKT_RX_REASON_SDN_TO_LOCAL, /* SDN output local port to CPU. */ + /* 48 */ + CLX_PKT_RX_REASON_CIA_0, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_1, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_2, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_3, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_4, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_5, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_6, /* CIA To CPU. */ + CLX_PKT_RX_REASON_CIA_7, /* CIA To CPU. */ + CLX_PKT_RX_REASON_USR_DEFINE_0, + CLX_PKT_RX_REASON_USR_DEFINE_1, + CLX_PKT_RX_REASON_USR_DEFINE_2, + CLX_PKT_RX_REASON_USR_DEFINE_3, + CLX_PKT_RX_REASON_USR_DEFINE_4, + CLX_PKT_RX_REASON_USR_DEFINE_5, + CLX_PKT_RX_REASON_USR_DEFINE_6, + CLX_PKT_RX_REASON_USR_DEFINE_7, + /* 64 */ + CLX_PKT_RX_REASON_USR_DEFINE_8, + CLX_PKT_RX_REASON_USR_DEFINE_9, + CLX_PKT_RX_REASON_USR_DEFINE_10, + CLX_PKT_RX_REASON_USR_DEFINE_11, + CLX_PKT_RX_REASON_USR_DEFINE_12, + CLX_PKT_RX_REASON_USR_DEFINE_13, + CLX_PKT_RX_REASON_L2_LKP_MISS, /* L2 lookup failed with the bank error or entry miss. */ + CLX_PKT_RX_REASON_L2_HDR_MISS, /* l2 bridge copy without ingress Ethernet header. */ + CLX_PKT_RX_REASON_L2_SA_MISS, /* L2 lookup SA miss. */ + CLX_PKT_RX_REASON_L2_SA_MOVE, /* L2 lookup SA hit but interface move. */ + CLX_PKT_RX_REASON_IPV4_VER_ERR, /* IPv4 packet has bad version. */ + CLX_PKT_RX_REASON_IPV4_OPT, /* IPv4 packet has options. */ + CLX_PKT_RX_REASON_IPV4_LEN_ERR, /* IPv4 packet Internet Header Length is unmatched to payload length. */ + CLX_PKT_RX_REASON_IPV4_CHKSM_ERR, /* IPv4 packet checksum error. */ + CLX_PKT_RX_REASON_IPV4_MC_MALFORMED, /* IPv4 multicast packet is malformed from RFC. */ + CLX_PKT_RX_REASON_IPV4_MC_LKP_MISS, /* IPv4 multicast packet lookup miss. */ + /* 80 */ + CLX_PKT_RX_REASON_IPV6_VER_ERR, /* IPv6 packet has bad version. */ + CLX_PKT_RX_REASON_IPV6_LEN_ERR, /* IPv6 packet total length does not cover 40-Bytes IPv6 base header. */ + CLX_PKT_RX_REASON_IPV6_MC_MALFORMED, /* IPv6 multicast packet is malformed from RFC. */ + CLX_PKT_RX_REASON_IPV6_MC_LKP_MISS, /* IPv6 multicast packet lookup miss. */ + CLX_PKT_RX_REASON_FCOE_VER_ERR, /* FCoE packet has bad version. */ + CLX_PKT_RX_REASON_FCOE_LKP_MISS, /* FCoE DID lookup failed, bank error or entry miss. */ + CLX_PKT_RX_REASON_FCOE_ZONING_FAIL, /* FCoE zoning check failed to CPU. */ + CLX_PKT_RX_REASON_MPLS_CTRL_PKT, /* MPLS control packets to CPU. */ + CLX_PKT_RX_REASON_MPLS_INVALID_PKT, /* MPLS packet is illegal from RFC. */ + CLX_PKT_RX_REASON_MPLS_LKP_MISS, /* MPLS lookup failed with the bank error or entry miss. */ + CLX_PKT_RX_REASON_MPLS_UHP_P2P_MISS, /* */ + CLX_PKT_RX_REASON_MPLS_UHP_TTL_0, /* MPLS UHP packet TTL is 0. */ + CLX_PKT_RX_REASON_MPLS_UHP_TTL_1, /* MPLS UHP packet TTL is 1. */ + CLX_PKT_RX_REASON_MPLS_TRANSIT_TTL_0, /* MPLS transit packet TTL is 0. */ + CLX_PKT_RX_REASON_MPLS_TRANSIT_TTL_1, /* MPLS transit packet TTL is 1. */ + CLX_PKT_RX_REASON_MPLS_TERM_TTL_0, /* MPLS term packet TTL is 0. */ + /* 96 */ + CLX_PKT_RX_REASON_MPLS_TERM_TTL_1, /* MPLS term packet TTL is 1. */ + CLX_PKT_RX_REASON_IP_TUNNEL_CTRL_PKT, /* IP tunnel control packets to CPU. */ + CLX_PKT_RX_REASON_IP_TUNNEL_INNER_IPV4_UC_LCL, /* IP tunnel packet has inner IPv4 unicast link local address. */ + CLX_PKT_RX_REASON_IP_TUNNEL_INNER_IPV6_UC_LCL, /* IP tunnel packet has inner IPv6 unicast link local address. */ + CLX_PKT_RX_REASON_IP_TUNNEL_INNER_MC_LCL, /* IP tunnel packet has inner multicast link local address. */ + CLX_PKT_RX_REASON_IP_TUNNEL_INNER_VER_ERR, /* IP tunnel packet inner is not IPv4 and IPv6. */ + CLX_PKT_RX_REASON_IP_TUNNEL_INNER_L3_ROUTE, /* Not allow GRE, IPoMPLS or MPLS VPN routed by inner header. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV4_FRAG, /* IP tunnel packet outer IPv4 fragment offset is not 0. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV4_OPT, /* IP tunnel packet outer IPv4 has options. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV4_AH, /* IP tunnel packet outer IPv4 has authentication header. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV4_TTL_0, /* IP tunnel packet outer IPv4 TTL is 0. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV4_TTL_1, /* IP tunnel packet outer IPv4 TTL is 1. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV6_FRAG, /* IP tunnel packet outer IPv6 fragment offset is not 0. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV6_OPT, /* IP tunnel packet outer IPv6 has extension header. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV6_AH, /* IP tunnel packet outer IPv6 has authentication header. */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV6_TTL_0, /* IP tunnel packet outer IPv6 TTL is 0. */ + /* 112 */ + CLX_PKT_RX_REASON_IP_TUNNEL_OUTER_IPV6_TTL_1, /* IP tunnel packet outer IPv6 TTL is 1. */ + CLX_PKT_RX_REASON_IPUC_TUNNEL_INNER_VLAN_MISS, /* IP unicast tunnel packet inner VLAN miss. */ + CLX_PKT_RX_REASON_IPMC_TUNNEL_INNER_VLAN_MISS, /* IP multicast tunnel packet inner VLAN miss. */ + CLX_PKT_RX_REASON_AUTO_TUNNEL_DIP_MISS, /* Auto tunnel outer IPv4 and inner IPv6 DIP are unmatched. */ + CLX_PKT_RX_REASON_AUTO_TUNNEL_SIP_MISS, /* Auto tunnel outer IPv4 and inner IPv6 SIP are unmatched. */ + CLX_PKT_RX_REASON_ETHER_IP_VER_ERR, /* Ethernet-within-IP tunnel version is illegal from RFC 3378. */ + CLX_PKT_RX_REASON_GRE_VER_ERR, /* GRE tunnel version is illegal from RFC 2784. */ + CLX_PKT_RX_REASON_GRE_RSVD_NON_ZERO, /* GRE tunnel reserved fields is illegal from RFC 2784. */ + CLX_PKT_RX_REASON_GRE_CTRL_FLAG_ERR, /* GRE tunnel control flag is illegal from RFC 2784. */ + CLX_PKT_RX_REASON_GRE_ERSPAN_TYP2_VER_ERR, /* GRE ERSPAN type II tunnel version is illegal from ERSPAN draft. */ + CLX_PKT_RX_REASON_GRE_ERSPAN_TYP3_VER_ERR, /* GRE ERSPAN type III tunnel version is illegal from ERSPAN draft. */ + CLX_PKT_RX_REASON_GRE_ERSPAN_TYP3_FT_ERR, /* GRE ERSPAN type III tunnel frame type is illegal from ERSPAN draft.*/ + CLX_PKT_RX_REASON_GRE_ERSPAN_TERM_LKP_MISS, /* GRE ERSPAN tunnel term lookup miss. */ + CLX_PKT_RX_REASON_VXLAN_BAS_RSVD_NON_ZERO, /* VXLAN Basic header reserved fields is illegal from RFC. */ + CLX_PKT_RX_REASON_VXLAN_BAS_VNI_FLAG_ERR, /* VXLAN Basic header VNI flag is illegal from RFC. */ + CLX_PKT_RX_REASON_VXLAN_BAS_CTRL_FLAG_ERR, /* VXLAN Basic header control flag is illegal from RFC. */ + /* 128 */ + CLX_PKT_RX_REASON_VXLAN_BAS_UDP_CHKSM_ERR, /* VXLAN Basic header UDP checksum is abnormal. */ + CLX_PKT_RX_REASON_VXLAN_GPE_VNI_FLAG_ERR, /* VXLAN GRE header VNI flag is illegal from RFC. */ + CLX_PKT_RX_REASON_VXLAN_GPE_CTRL_FLAG_ERR, /* VXLAN GPE header control flag is illegal from RFC. */ + CLX_PKT_RX_REASON_VXLAN_GPE_UDP_CHKSM_ERR, /* VXLAN GPE header UDP checksum is abnormal. */ + CLX_PKT_RX_REASON_TRILL_VER_ERR, /* TRILL version is illegal from RFC. */ + CLX_PKT_RX_REASON_TRILL_MC_FLAG_ERR, /* TRILL multicast flag is unmatched DMAC. */ + CLX_PKT_RX_REASON_TRILL_OPT, /* TRILL packet has option or option header length is illegal. */ + CLX_PKT_RX_REASON_TRILL_LKP_MISS, /* TRILL lookup failed with the bank error or entry miss. */ + CLX_PKT_RX_REASON_TRILL_TRANSIT_TTL_0, /* TRILL transit packet TTL is 0. */ + CLX_PKT_RX_REASON_TRILL_TRANSIT_TTL_1, /* TRILL transit packet TTL is 1. */ + CLX_PKT_RX_REASON_TRILL_TERM_TTL_0, /* TRILL term packet TTL is 0. */ + CLX_PKT_RX_REASON_TRILL_TERM_TTL_1, /* TRILL term packet TTL is 1. */ + CLX_PKT_RX_REASON_TRILL_MRPF_CHECK_FAIL, /* TRILL multicast RPF check failed. */ + CLX_PKT_RX_REASON_NSH_CTRL_PKT, /* NSH control packets to CPU. */ + CLX_PKT_RX_REASON_NSH_INVALID_PKT, /* NSH packet is illegal from RFC. */ + CLX_PKT_RX_REASON_NSH_LKP_MISS, /* NSH lookup failed with the bank error or entry miss. */ + /* 144 */ + CLX_PKT_RX_REASON_ECMP_LKP_MISS, /* ECMP lookup failed with the bank error or entry miss. */ + CLX_PKT_RX_REASON_ACL_LKP_MISS, /* ACL lookup failed with the bank error or entry miss. */ + CLX_PKT_RX_REASON_FLOW_LKP_MISS, /* Flow lookup failed with the bank error or entry miss. */ + CLX_PKT_RX_REASON_IGR_FLOW_SFLOW, /* Ingress flow-based sflow hit. */ + CLX_PKT_RX_REASON_EGR_FLOW_SFLOW, /* Egress flow-based sflow hit. */ + CLX_PKT_RX_REASON_HW_ERROR, /* HW error. e.g. ECC. */ + CLX_PKT_RX_REASON_1588_RX_PKT, /* User spcified the 1588 packets. */ + CLX_PKT_RX_REASON_STP_BLOCK, /* STP block packets to CPU. */ + CLX_PKT_RX_REASON_STACKING_NEIGHBOR, /* The stacking packets from neighbor. */ + CLX_PKT_RX_REASON_STACKING_BROADCAST, /* The stacking broadcast packets. */ + CLX_PKT_RX_REASON_STACKING_LOOP, /* The stacking path is loop. */ + CLX_PKT_RX_REASON_STORM_CONTROL, /* Storm Control packets to CPU. */ + CLX_PKT_RX_REASON_TUNNEL_INIT_LKP_MISS, /* Tunnel init lookup failed with bank error or entry miss. */ + CLX_PKT_RX_REASON_TUNNEL_INNER_VLAN_MISS, /* IP Tunnel or TRILL packets miss inner VLAN. */ + CLX_PKT_RX_REASON_TUNNEL_INNER_VLAN_UNEXP, /* IP Tunnel or TRILL packets not allowed inner VLAN. */ + CLX_PKT_RX_REASON_IGR_L3_MTU_FAIL, /* Ingress L3 MTU check fail to CPU. */ + /* 160 */ + CLX_PKT_RX_REASON_EGR_L3_MTU_FAIL, /* Egress L3 MTU check fail to CPU. */ + CLX_PKT_RX_REASON_IGR_TUNNEL_MTU_FAIL, /* Ingress Tunnel MTU check fail to CPU. */ + CLX_PKT_RX_REASON_EGR_TUNNEL_MTU_FAIL, /* Egress Tunnel MTU check fail to CPU. */ + CLX_PKT_RX_REASON_EGR_IPV4_TTL_1, /* Egress IPv4 interface configure TTL 1. */ + CLX_PKT_RX_REASON_EGR_IPV6_TTL_1, /* Egress IPv6 interface configure TTL 1. */ + CLX_PKT_RX_REASON_COPY_TO_CPU_L2MC, /* L2MC Copy to CPU. */ + CLX_PKT_RX_REASON_COPY_TO_CPU_L3MC, /* L3MC Copy to CPU. */ + CLX_PKT_RX_REASON_COPY_TO_CPU_L2UC, /* L2UC Copy to CPU. */ + CLX_PKT_RX_REASON_COPY_TO_CPU_L3UC, /* L3UC Copy to CPU. */ + CLX_PKT_RX_REASON_FLEX_TUNNEL_UDP_CHKSM_ERR, /* Flex tunnel packet UDP checksum is abnormal. */ + CLX_PKT_RX_REASON_FLEX_TUNNEL_0_CHK, /* Flex tunnel 0 with sanity, type, or length check fail. */ + CLX_PKT_RX_REASON_FLEX_TUNNEL_1_CHK, /* Flex tunnel 1 with sanity, type, or length check fail. */ + CLX_PKT_RX_REASON_FLEX_TUNNEL_2_CHK, /* Flex tunnel 2 with sanity, type, or length check fail. */ + CLX_PKT_RX_REASON_FLEX_TUNNEL_3_CHK, /* Flex tunnel 3 with sanity, type, or length check fail. */ + CLX_PKT_RX_REASON_EGR_SFLOW_HIGH_LATENCY, /* Sample high latency packet. */ + CLX_PKT_RX_REASON_DPP_LOOPBACK, /* DPP loopback packet */ + /* 176 */ + CLX_PKT_RX_REASON_PPPOE_SRV_UNKNOWN, /* PPPOE service unknown */ + CLX_PKT_RX_REASON_PPPOE_HDR_ERR, /* PPPOE header error */ + CLX_PKT_RX_REASON_PPPOE_ENCAP_ERR, /* PPPOE encap error */ + CLX_PKT_RX_REASON_IP_TUNNEL_IPV4_ERR, /* IP tunnel IPv4 header error */ + CLX_PKT_RX_REASON_IP_TUNNEL_IPV6_ERR, /* IP tunnel IPv6 header error */ + CLX_PKT_RX_REASON_DECAP_NSH_TTL_1, /* NSH TLL 1 error */ + CLX_PKT_RX_REASON_TRANSIT_NSH_TTL_1, /* NSH TLL 1 error */ + CLX_PKT_RX_REASON_PORT_MTR_DROP, /* Meter over rate drop */ + CLX_PKT_RX_REASON_WECMP, /* WECMP config error */ + CLX_PKT_RX_REASON_IOAM_NODE_LEN_INVALID_IPV6, /* IOAM over IPv6 node len not align */ + CLX_PKT_RX_REASON_IOAM_NODE_LEN_INVALID_GRE, /* IOAM over GRE node len not align */ + CLX_PKT_RX_REASON_IOAM_NODE_LEN_INVALID_GPE, /* IOAM over GPE node len not align */ + CLX_PKT_RX_REASON_OTHERS, /* None of the above reasons */ + + CLX_PKT_RX_REASON_LAST +} CLX_PKT_RX_REASON_T; + +#define CLX_PKT_RX_REASON_BITMAP_SIZE (CLX_BITMAP_SIZE(CLX_PKT_RX_REASON_LAST)) + +/* The data structure is the reason bitmap for "to CPU" reason codes. */ +typedef UI32_T CLX_PKT_RX_REASON_BITMAP_T[CLX_PKT_RX_REASON_BITMAP_SIZE]; + + +/* ----------------------------------------------------------------------------------- struct */ +typedef struct +{ + UI32_T tx_pkt; + UI32_T tx_queue_full; + UI32_T tx_error; + UI32_T rx_pkt; + +} CLX_NETIF_INTF_CNT_T; + +typedef struct +{ + /* unique key */ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + CLX_PORT_T port; /* only support unit port and local port */ + + /* metadata */ + CLX_MAC_T mac; + +#define CLX_NETIF_INTF_FLAGS_MAC (1UL << 0) + UI32_T flags; + +} CLX_NETIF_INTF_T; + + +#if defined(NETIF_EN_NETLINK) +typedef struct +{ + C8_T name[CLX_NETIF_NAME_LEN]; + C8_T mc_group_name[CLX_NETIF_NAME_LEN]; +} CLX_NETIF_RX_DST_NETLINK_T; +#endif + +typedef enum +{ + CLX_NETIF_RX_DST_SDK = 0, +#if defined(NETIF_EN_NETLINK) + CLX_NETIF_RX_DST_NETLINK, +#endif + CLX_NETIF_RX_DST_LAST +} CLX_NETIF_RX_DST_TYPE_T; + +typedef struct +{ + /* unique key */ + UI32_T id; + C8_T name[CLX_NETIF_NAME_LEN]; + UI32_T priority; + + /* match fields */ + CLX_PORT_T port; /* only support unit port and local port */ + CLX_PKT_RX_REASON_BITMAP_T reason_bitmap; + UI8_T pattern[CLX_NETIF_PROFILE_PATTERN_NUM][CLX_NETIF_PROFILE_PATTERN_LEN]; + UI8_T mask[CLX_NETIF_PROFILE_PATTERN_NUM][CLX_NETIF_PROFILE_PATTERN_LEN]; + UI32_T offset[CLX_NETIF_PROFILE_PATTERN_NUM]; + + /* for each flag 1:must hit, 0:don't care */ +#define CLX_NETIF_PROFILE_FLAGS_PORT (1UL << 0) +#define CLX_NETIF_PROFILE_FLAGS_REASON (1UL << 1) +#define CLX_NETIF_PROFILE_FLAGS_PATTERN_0 (1UL << 2) +#define CLX_NETIF_PROFILE_FLAGS_PATTERN_1 (1UL << 3) +#define CLX_NETIF_PROFILE_FLAGS_PATTERN_2 (1UL << 4) +#define CLX_NETIF_PROFILE_FLAGS_PATTERN_3 (1UL << 5) + UI32_T flags; + + CLX_NETIF_RX_DST_TYPE_T dst_type; +#if defined(NETIF_EN_NETLINK) + CLX_NETIF_RX_DST_NETLINK_T netlink; +#endif + +} CLX_NETIF_PROFILE_T; + +/* NAMING CONSTANT DECLARATIONS + */ +/* Keep these values applied to different modules. */ +#define HAL_PKT_IPP_EXCPT_NUM (256) +#define HAL_PKT_EPP_EXCPT_NUM (64) +#define HAL_PKT_IPP_L3_EXCPT_NUM (6) +#define HAL_PKT_IPP_RSN_NUM (16) +#define HAL_PKT_IPP_COPY2CPU_NUM (16) +#define HAL_PKT_EPP_COPY2CPU_NUM (8) + +/* IEV_CFG_EXCPT_EN_W1_SDK_REDIRECT_TO_CPU_L2UC_FIELD_ID */ +#define HAL_PKT_IPP_EXCPT_IEV_SDK_REDIRECT_TO_CPU_L2UC (192 + 23) + +/* IEV_CFG_EXCPT_EN_W1_SDK_REDIRECT_TO_CPU_L3UC_FIELD_ID */ +#define HAL_PKT_IPP_EXCPT_IEV_SDK_REDIRECT_TO_CPU_L3UC (192 + 24) + +/* IEV_CFG_EXCPT_EN_W1_SDK_L3UC_DA_MISS_FIELD_ID */ +#define HAL_PKT_IPP_EXCPT_IEV_SDK_L3UC_DA_MISS (192 + 30) + +/* IEV_CFG_EXCPT_EN_W1_SDK_L3MC_PIM_REGISTER_FIELD_ID */ +#define HAL_PKT_IPP_EXCPT_IEV_SDK_L3MC_PIM_REGISTER (192 + 31) + +/* IEV_CFG_EXCPT_EN_W0_SDK_FLEX_DECAP_0_REASON_0_FIELD_ID */ +#define HAL_PKT_IPP_EXCPT_IEV_SDK_FLEX_DECAP_0_REASON_0 (224 + 8) + +/* HW define offset + * Module write IEV.cp_to_cpu_idx=1-3 + * Module write IEV_CFG_CP_TO_CPU_BIT_POS[offset + cp_to_cpu_idx - 1] + */ +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_L2UC_DA (0) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_L2MC_DA (3) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_L2SA (6) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_MPLS (9) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_TRILL (12) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_FCOE (15) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_L3UC_DA (18) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_L3UC_SA (21) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_L3MC (24) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_FLW_UC (27) +#define HAL_PKT_IEV_CP_TO_CPU_BIT_POS_FLW_MC (30) + +/* capacities are the same between CL8360 and CL8570 */ +#define HAL_PKT_IPP_EXCPT_BITMAP_SIZE (CLX_BITMAP_SIZE(HAL_PKT_IPP_EXCPT_NUM)) +#define HAL_PKT_IPP_L3_EXCPT_BITMAP_SIZE (CLX_BITMAP_SIZE(HAL_PKT_IPP_L3_EXCPT_NUM)) +#define HAL_PKT_EPP_EXCPT_BITMAP_SIZE (CLX_BITMAP_SIZE(HAL_PKT_EPP_EXCPT_NUM)) +#define HAL_PKT_IPP_RSN_BITMAP_SIZE (CLX_BITMAP_SIZE(HAL_PKT_IPP_RSN_NUM)) +#define HAL_PKT_IPP_COPY2CPU_BITMAP_SIZE (CLX_BITMAP_SIZE(HAL_PKT_IPP_COPY2CPU_NUM)) +#define HAL_PKT_EPP_COPY2CPU_BITMAP_SIZE (CLX_BITMAP_SIZE(HAL_PKT_EPP_COPY2CPU_NUM)) + +typedef UI32_T HAL_PKT_IPP_EXCPT_BITMAP_T[HAL_PKT_IPP_EXCPT_BITMAP_SIZE]; +typedef UI32_T HAL_PKT_IPP_L3_EXCPT_BITMAP_T[HAL_PKT_IPP_L3_EXCPT_BITMAP_SIZE]; +typedef UI32_T HAL_PKT_EPP_EXCPT_BITMAP_T[HAL_PKT_EPP_EXCPT_BITMAP_SIZE]; +typedef UI32_T HAL_PKT_IPP_RSN_BITMAP_T[HAL_PKT_IPP_RSN_BITMAP_SIZE]; +typedef UI32_T HAL_PKT_IPP_COPY2CPU_BITMAP_T[HAL_PKT_IPP_COPY2CPU_BITMAP_SIZE]; +typedef UI32_T HAL_PKT_EPP_COPY2CPU_BITMAP_T[HAL_PKT_EPP_COPY2CPU_BITMAP_SIZE]; + +typedef struct +{ + /* excpt */ + HAL_PKT_IPP_EXCPT_BITMAP_T ipp_excpt_bitmap; + HAL_PKT_IPP_L3_EXCPT_BITMAP_T ipp_l3_excpt_bitmap; + HAL_PKT_EPP_EXCPT_BITMAP_T epp_excpt_bitmap; + + /* cp */ + HAL_PKT_IPP_RSN_BITMAP_T ipp_rsn_bitmap; + HAL_PKT_IPP_COPY2CPU_BITMAP_T ipp_copy2cpu_bitmap; + HAL_PKT_EPP_COPY2CPU_BITMAP_T epp_copy2cpu_bitmap; + +} HAL_PKT_RX_REASON_BITMAP_T; + +#endif /* End of NETIF_KNL_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/netif_nl.h b/platform/clounix/clounix-modules/modules/src/inc/netif_nl.h new file mode 100755 index 000000000000..cb46cfa5d92f --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/netif_nl.h @@ -0,0 +1,105 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_nl.h + * PURPOSE: + * It provide xxx API. + * NOTES: + */ + +#ifndef NETIF_NL_H +#define NETIF_NL_H + +#include + +#define NETIF_NL_NETLINK_MC_GROUP_NUM (32) +#define NETIF_NL_NETLINK_NAME_LEN (16) + +typedef enum +{ + NETIF_NL_INTF_PROPERTY_IGR_SAMPLING_RATE, + NETIF_NL_INTF_PROPERTY_EGR_SAMPLING_RATE, + NETIF_NL_INTF_PROPERTY_LAST +} NETIF_NL_INTF_PROPERTY_T; + +/* must be the same with CLX_NETIF_RX_DST_NETLINK_T */ +typedef struct +{ + C8_T name[NETIF_NL_NETLINK_NAME_LEN]; + C8_T mc_group_name[NETIF_NL_NETLINK_NAME_LEN]; +} NETIF_NL_RX_DST_NETLINK_T; + +/* must be the same with CLX_NETIF_NETLINK_MC_GROUP_T */ +typedef struct +{ + C8_T name[NETIF_NL_NETLINK_NAME_LEN]; + +} NETIF_NL_NETLINK_MC_GROUP_T; + +/* must be the same with CLX_NETIF_NETLINK_T */ +typedef struct +{ + UI32_T id; + C8_T name[NETIF_NL_NETLINK_NAME_LEN]; + NETIF_NL_NETLINK_MC_GROUP_T mc_group[NETIF_NL_NETLINK_MC_GROUP_NUM]; + UI32_T mc_group_num; + +} NETIF_NL_NETLINK_T; + +CLX_ERROR_NO_T +netif_nl_rxSkb( + const UI32_T unit, + struct sk_buff *ptr_skb, + void *ptr_cookie); + +CLX_ERROR_NO_T +netif_nl_setIntfProperty( + const UI32_T unit, + const UI32_T id, + const NETIF_NL_INTF_PROPERTY_T property, + const UI32_T param0, + const UI32_T param1); + +CLX_ERROR_NO_T +netif_nl_getIntfProperty( + const UI32_T unit, + const UI32_T port, + const NETIF_NL_INTF_PROPERTY_T property, + UI32_T *ptr_param0, + UI32_T *ptr_param1); + +CLX_ERROR_NO_T +netif_nl_createNetlink( + const UI32_T unit, + NETIF_NL_NETLINK_T *ptr_netlink, + UI32_T *ptr_netlink_id); + +CLX_ERROR_NO_T +netif_nl_destroyNetlink( + const UI32_T unit, + const UI32_T group_id); + +CLX_ERROR_NO_T +netif_nl_getNetlink( + const UI32_T unit, + const UI32_T netlink_id, + NETIF_NL_NETLINK_T *ptr_netlink); + + +CLX_ERROR_NO_T +netif_nl_init(void); + +#endif /* end of NETIF_NL_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/netif_osal.h b/platform/clounix/clounix-modules/modules/src/inc/netif_osal.h new file mode 100755 index 000000000000..3f210b88e667 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/netif_osal.h @@ -0,0 +1,380 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_osal.h + * PURPOSE: + * It provide customer linux API. + * NOTES: + */ + +#ifndef NETIF_OSAL_H +#define NETIF_OSAL_H + +/* + * ENOMEM : 12 - Out of memory + * EFAULT : 14 - Bad address + * EBUSY : 16 - Device or resource busy + * ENODEV : 19 - No such device + * EINVAL : 22 - Invalid argument + + * + * NETDEV_TX_OK : 0x00 + * NETDEV_TX_BUSY : 0x10 + + * + * ETH_HLEN : 14 dmac + smac + etyp + * ETH_ZLEN : 60 minimum ethernet frame size + * ETH_DATA_LEN : 1500 + * ETH_FRAME_LEN : 1514 + * ETH_FCS_LEN : 4 + * + * ETH_P_IP : 0x0800 + * ETH_P_ARP : 0x0806 + * ETH_P_IPV6 : 0x86DD + * ETH_P_SLOW : 0x8809 + * ETH_P_1588 : 0x88F7 + + * + * NET_IP_ALIGN : 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* ----------------------------------------------------------------------------------- macro value */ +/* Thread */ +#define OSAL_THREAD_NAME_LEN (16) +#define OSAL_THREAD_DFT_NAME ("Unknown") + +/* Semaphore */ +#define OSAL_SEMA_NAME_LEN (16) +#define OSAL_SEMA_DFT_NAME ("Unknown") + +/* Event */ +#define OSAL_EVENT_NAME_LEN (16) +#define OSAL_EVENT_DFT_NAME ("Unknown") + +/* Spinlock */ +#define OSAL_SPIN_NAME_LEN (16) +#define OSAL_SPIN_DFT_NAME ("Unknown") + +/* Queue */ +#define OSAL_QUEUE_NAME_LEN (16) +#define OSAL_QUEUE_DFT_NAME ("Unknown") + +#define OSAL_PRN_BUF_SZ (256) +#define OSAL_TICKS_PER_SEC (1000000) + +/* ----------------------------------------------------------------------------------- struct */ +typedef struct linux_thread_s +{ + char name[OSAL_THREAD_NAME_LEN + 1]; + struct task_struct *ptr_task; + unsigned int is_stop; + struct linux_thread_s *ptr_prev; + struct linux_thread_s *ptr_next; + +} linux_thread_t; + +typedef struct +{ + char name[OSAL_SEMA_NAME_LEN + 1]; + struct semaphore lock; + +} linux_sema_t; + +typedef struct +{ + char name[OSAL_EVENT_NAME_LEN + 1]; + wait_queue_head_t wait_que; + unsigned int condition; + +} linux_event_t; + +typedef struct +{ + char name[OSAL_SPIN_NAME_LEN + 1]; + spinlock_t spinlock; + +} linux_isrlock_t; + +typedef struct +{ + void *ptr_data; +} linux_queue_entry_t; + +typedef struct +{ + char name[OSAL_QUEUE_NAME_LEN + 1]; + int head; /* index of the queue head entry can be read */ + int tail; /* index of the queue tail entry can be write */ + unsigned int wr_cnt; /* enqueue total count */ + unsigned int rd_cnt; /* dequeue total count */ + unsigned int capacity; /* the queue size */ + linux_queue_entry_t *ptr_entry; /* the queue entry buffer */ + +} linux_queue_t; + +typedef struct +{ + unsigned int size; + dma_addr_t phy_addr; + char data[0]; + +} linux_dma_t; + +/* ----------------------------------------------------------------------------------- function */ +void * +osal_memset( + void *ptr_mem, + const I32_T value, + const UI32_T num); + +void * +osal_memcpy( + void *ptr_dst, + const void *ptr_src, + const UI32_T num); + +UI32_T +osal_strlen( + const C8_T *ptr_str); + +void +osal_printf( + const C8_T *ptr_fmt, + ...); + +void * +osal_alloc( + const UI32_T size); + +void +osal_free( + const void *ptr_mem); + +/* thread */ +CLX_ERROR_NO_T +osal_init(void); + +CLX_ERROR_NO_T +osal_deinit(void); + +CLX_ERROR_NO_T +osal_createThread ( + const C8_T *ptr_thread_name, + const UI32_T stack_size, + const UI32_T priority, + void (function)(void*), + void *ptr_arg, + CLX_THREAD_ID_T *ptr_thread_id); + +CLX_ERROR_NO_T +osal_stopThread( + CLX_THREAD_ID_T *ptr_thread_id); + +CLX_ERROR_NO_T +osal_destroyThread( + CLX_THREAD_ID_T *ptr_thread_id); + +void +osal_initRunThread( + void); + +CLX_ERROR_NO_T +osal_isRunThread( + void); + +void +osal_exitRunThread( + void); + +/* semaphore */ +CLX_ERROR_NO_T +osal_createSemaphore( + const C8_T *ptr_sema_name, + const UI32_T sema_count, + CLX_SEMAPHORE_ID_T *ptr_semaphore_id); + +CLX_ERROR_NO_T +osal_takeSemaphore( + CLX_SEMAPHORE_ID_T *ptr_semaphore_id, + UI32_T time_out); + +CLX_ERROR_NO_T +osal_giveSemaphore( + CLX_SEMAPHORE_ID_T *ptr_semaphore_id); + +CLX_ERROR_NO_T +osal_destroySemaphore( + CLX_SEMAPHORE_ID_T *ptr_semaphore_id); + +/* event */ +CLX_ERROR_NO_T +osal_createEvent( + const C8_T *ptr_event_name, + CLX_SEMAPHORE_ID_T *ptr_event_id); + +CLX_ERROR_NO_T +osal_waitEvent( + CLX_SEMAPHORE_ID_T *ptr_event_id); + +CLX_ERROR_NO_T +osal_triggerEvent( + CLX_SEMAPHORE_ID_T *ptr_event_id); + +CLX_ERROR_NO_T +osal_destroyEvent( + CLX_SEMAPHORE_ID_T *ptr_event_id); + +/* isr_lock */ +CLX_ERROR_NO_T +osal_createIsrLock( + const C8_T *ptr_isrlock_name, + CLX_ISRLOCK_ID_T *ptr_isrlock_id); + +CLX_ERROR_NO_T +osal_takeIsrLock( + CLX_ISRLOCK_ID_T *ptr_isrlock_id, + CLX_IRQ_FLAGS_T *ptr_irq_flags); + +CLX_ERROR_NO_T +osal_giveIsrLock( + CLX_ISRLOCK_ID_T *ptr_isrlock_id, + CLX_IRQ_FLAGS_T *ptr_irq_flags); + +CLX_ERROR_NO_T +osal_destroyIsrLock( + CLX_ISRLOCK_ID_T *ptr_isrlock_id); + +/* timer */ +CLX_ERROR_NO_T +osal_sleepThread( + const UI32_T usecond); + +CLX_ERROR_NO_T +osal_getTime( + CLX_TIME_T *ptr_time); + +/* queue */ +CLX_ERROR_NO_T +osal_que_create( + CLX_HUGE_T *ptr_queue_id, + UI32_T capacity); + +CLX_ERROR_NO_T +osal_que_enque( + CLX_HUGE_T *ptr_queue_id, + void *ptr_data); + +CLX_ERROR_NO_T +osal_que_deque( + CLX_HUGE_T *ptr_queue_id, + void **pptr_data); + +CLX_ERROR_NO_T +osal_que_destroy( + CLX_HUGE_T *ptr_queue_id); + +CLX_ERROR_NO_T +osal_que_getCount( + CLX_HUGE_T *ptr_queue_id, + unsigned int *ptr_count); + +/* IO */ +int +osal_io_copyToUser( + void *ptr_usr_buf, + void *ptr_knl_buf, + unsigned int size); + +int +osal_io_copyFromUser( + void *ptr_knl_buf, + void *ptr_usr_buf, + unsigned int size); + +/* dma */ +void * +osal_dma_alloc( + const UI32_T size); + +CLX_ERROR_NO_T +osal_dma_free( + void *ptr_dma_mem); + +dma_addr_t +osal_dma_convertVirtToPhy( + void *ptr_virt_addr); + +void * +osal_dma_convertPhyToVirt( + const dma_addr_t phy_addr); + +int +osal_dma_flushCache( + void *ptr_virt_addr, + const unsigned int size); + +int +osal_dma_invalidateCache( + void *ptr_virt_addr, + const unsigned int size); + +/* skb */ +struct sk_buff * +osal_skb_alloc( + UI32_T size); + +void +osal_skb_free( + struct sk_buff *ptr_skb); + +dma_addr_t +osal_skb_mapDma( + struct sk_buff *ptr_skb, + enum dma_data_direction dir); + +void +osal_skb_unmapDma( + const dma_addr_t phy_addr, + UI32_T size, + enum dma_data_direction dir); + +void +osal_skb_send( + struct sk_buff *ptr_skb); + +void +osal_skb_recv( + struct sk_buff *ptr_skb); + +#endif /* end of NETIF_OSAL_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/netif_perf.h b/platform/clounix/clounix-modules/modules/src/inc/netif_perf.h new file mode 100755 index 000000000000..fab397ccebec --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/netif_perf.h @@ -0,0 +1,82 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: netif_perf.h + * PURPOSE: + * It provide customer performance test API. + * NOTES: + */ + +#ifndef NETIF_PERF_H +#define NETIF_PERF_H + +/* #define PERF_EN_TEST */ + +/* FUNCTION NAME: perf_rxCallback + * PURPOSE: + * To count the Rx-gpd for Rx-test. + * INPUT: + * len -- To check if the Rx-gpd length equals to test length. + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successful operation. + * NOTES: + * None + */ +CLX_ERROR_NO_T +perf_rxCallback( + const UI32_T len); + +/* FUNCTION NAME: perf_rxTest + * PURPOSE: + * To check if Rx-test is going. + * INPUT: + * None + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successful operation. + * NOTES: + * None + */ +CLX_ERROR_NO_T +perf_rxTest( + void); + +/* FUNCTION NAME: perf_test + * PURPOSE: + * To do Tx-test or Rx-test. + * INPUT: + * len -- Test length + * tx_channel -- Test Tx channel numbers + * rx_channel -- Test Rx channel numbers + * test_skb -- Test GPD or SKB + * OUTPUT: + * None + * RETURN: + * CLX_E_OK -- Successful operation. + * NOTES: + * None + */ +CLX_ERROR_NO_T +perf_test( + UI32_T len, + UI32_T tx_channel, + UI32_T rx_channel, + BOOL_T test_skb); + +#endif /* end of NETIF_PERF_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/osal/osal_mdc.h b/platform/clounix/clounix-modules/modules/src/inc/osal/osal_mdc.h new file mode 100644 index 000000000000..086740ed8672 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/osal/osal_mdc.h @@ -0,0 +1,262 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: osal_mdc.h + * PURPOSE: + * 1. Provide device operate from AML interface + * NOTES: + * + */ + +#ifndef OSAL_MDC_H +#define OSAL_MDC_H + +/* INCLUDE FILE DECLARATIONS */ +#if !defined(CLX_LINUX_KERNEL_MODE) +#include +#endif +#include +#define CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM (16) +#include + +#define OSAL_MDC_DRIVER_NAME "clx_dev" +#define OSAL_MDC_DRIVER_MISC_MAJOR_NUM (10) +#define OSAL_MDC_DRIVER_MISC_MINOR_NUM (250) +#define OSAL_MDC_PCI_BUS_WIDTH (4) + +#define OSAL_MDC_DMA_LIST_SZ_UNLIMITED (0) +#define OSAL_MDC_DMA_LIST_NAME "RSRV_DMA" +#define OSAL_MDC_DMA_SEMAPHORE_NAME "DMALIST" + +/* NAMING CONSTANT DECLARATIONS + */ + +/* linked list node */ +#if defined(CLX_LINUX_KERNEL_MODE) + +typedef struct OSAL_MDC_LIST_NODE_S +{ + void *ptr_data; /* node data */ + struct OSAL_MDC_LIST_NODE_S *ptr_next; /* point to next link node */ + struct OSAL_MDC_LIST_NODE_S *ptr_prev; /* point to previous link node */ +} OSAL_MDC_LIST_NODE_T; + +/* linked list head */ +typedef struct OSAL_MDC_LIST_S +{ + OSAL_MDC_LIST_NODE_T *ptr_head_node; /* linked list head node */ + OSAL_MDC_LIST_NODE_T *ptr_tail_node; /* linked list tail node */ + UI32_T capacity; /* max count of nodes in list + * size=0: the capacity is unlimited. + * size>0: the capacity is limited. + */ + UI32_T node_cnt; /* the count of nodes in the list */ +} OSAL_MDC_LIST_T; + +#endif /* End of defined(CLX_LINUX_KERNEL_MODE) */ + +typedef struct +{ + CLX_ADDR_T phy_addr; + void *ptr_virt_addr; + CLX_ADDR_T size; + +#if defined(CLX_EN_DMA_RESERVED) + BOOL_T available; +#endif + +} OSAL_MDC_DMA_NODE_T; + +typedef struct +{ +#if defined(CLX_EN_DMA_RESERVED) + void *ptr_rsrv_virt_addr; + CLX_ADDR_T rsrv_phy_addr; + CLX_ADDR_T rsrv_size; +#else + struct device *ptr_dma_dev; /* for allocate/free system memory */ +#endif + +#if defined(CLX_LINUX_KERNEL_MODE) + OSAL_MDC_LIST_T *ptr_dma_list; +#else + CMLIB_LIST_T *ptr_dma_list; +#endif + + CLX_SEMAPHORE_ID_T sema; + +} OSAL_MDC_DMA_INFO_T; + +#if defined(CLX_LINUX_USER_MODE) + +/* Data type of IOCTL argument for DMA management */ +typedef struct +{ +#if defined(CLX_EN_DMA_RESERVED) + CLX_ADDR_T rsrv_dma_phy_addr; /* information of reserved memory */ + CLX_ADDR_T rsrv_dma_size; +#else + CLX_ADDR_T phy_addr; /* information of system memory */ + CLX_ADDR_T size; +#endif +} OSAL_MDC_IOCTL_DMA_DATA_T; + +/* Data type of IOCTL argument for device initialization */ +#pragma pack (push,1) +typedef struct +{ + AML_DEV_ID_T id[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; + CLX_ADDR_T pci_mmio_phy_start[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; + CLX_ADDR_T pci_mmio_size[CLX_CFG_MAXIMUM_CHIPS_PER_SYSTEM]; + UI32_T dev_num; +} OSAL_MDC_IOCTL_DEV_DATA_T; +#pragma pack (pop) + +typedef enum +{ + OSAL_MDC_IOCTL_ACCESS_READ = 0, + OSAL_MDC_IOCTL_ACCESS_WRITE, + OSAL_MDC_IOCTL_ACCESS_READ_WRITE, + OSAL_MDC_IOCTL_ACCESS_NONE, + OSAL_MDC_IOCTL_ACCESS_LAST + +} OSAL_MDC_IOCTL_ACCESS_T; + +typedef enum +{ + OSAL_MDC_IOCTL_TYPE_MDC_INIT_DEV = 0, + OSAL_MDC_IOCTL_TYPE_MDC_DEINIT_DEV, + OSAL_MDC_IOCTL_TYPE_MDC_INIT_RSRV_DMA_MEM, + OSAL_MDC_IOCTL_TYPE_MDC_DEINIT_RSRV_DMA_MEM, + OSAL_MDC_IOCTL_TYPE_MDC_ALLOC_SYS_DMA_MEM, + OSAL_MDC_IOCTL_TYPE_MDC_FREE_SYS_DMA_MEM, + OSAL_MDC_IOCTL_TYPE_MDC_CONNECT_ISR, + OSAL_MDC_IOCTL_TYPE_MDC_DISCONNECT_ISR, + OSAL_MDC_IOCTL_TYPE_MDC_SAVE_PCI_CONFIG, + OSAL_MDC_IOCTL_TYPE_MDC_RESTORE_PCI_CONFIG, + OSAL_MDC_IOCTL_TYPE_LAST + +} OSAL_MDC_IOCTL_TYPE_T; + +typedef union +{ + UI32_T value; + struct + { + UI32_T access : 2; /* 0:read, 1:write, 2:read and write, 3:none */ + UI32_T unit : 6; /* Maximum unit number is 64. */ + UI32_T size :14; /* Maximum IOCTL data size is 16KB. */ + UI32_T type :10; /* Maximum 1024 IOCTL types */ + } field; +} OSAL_MDC_IOCTL_CMD_T; + +typedef CLX_ERROR_NO_T +(*OSAL_MDC_IOCTL_CALLBACK_FUNC_T)( + const UI32_T unit, + void *ptr_data); + +#endif /* End of CLX_LINUX_USER_MODE */ + + +/* MACRO FUNCTION DECLARATIONS + */ + +/* DATA TYPE DECLARATIONS + */ + +/* EXPORTED SUBPROGRAM SPECIFICATIONS + */ +CLX_ERROR_NO_T +osal_mdc_readPciReg( + const UI32_T unit, + const UI32_T offset, + UI32_T *ptr_data, + const UI32_T len); + +CLX_ERROR_NO_T +osal_mdc_writePciReg( + const UI32_T unit, + const UI32_T offset, + const UI32_T *ptr_data, + const UI32_T len); + +CLX_ERROR_NO_T +osal_mdc_initDevice( + AML_DEV_T *ptr_dev_list, + UI32_T *ptr_dev_num); + +CLX_ERROR_NO_T +osal_mdc_deinitDevice(void); + +CLX_ERROR_NO_T +osal_mdc_initDmaMem(void); + +CLX_ERROR_NO_T +osal_mdc_deinitDmaMem(void); + +void * +osal_mdc_allocDmaMem( + const UI32_T size); + +CLX_ERROR_NO_T +osal_mdc_freeDmaMem( + void *ptr_virt_addr); + +CLX_ERROR_NO_T +osal_mdc_convertVirtToPhy( + void *ptr_virt_addr, + CLX_ADDR_T *ptr_phy_addr); + +CLX_ERROR_NO_T +osal_mdc_convertPhyToVirt( + const CLX_ADDR_T phy_addr, + void **pptr_virt_addr); + +CLX_ERROR_NO_T +osal_mdc_registerIsr( + const UI32_T unit, + AML_DEV_ISR_FUNC_T handler, + void *ptr_cookie); + +CLX_ERROR_NO_T +osal_mdc_connectIsr( + const UI32_T unit, + AML_DEV_ISR_FUNC_T handler, + AML_DEV_ISR_DATA_T *ptr_cookie); + +CLX_ERROR_NO_T +osal_mdc_disconnectIsr( + const UI32_T unit); + +CLX_ERROR_NO_T +osal_mdc_flushCache( + void *ptr_virt_addr, + const UI32_T size); + +CLX_ERROR_NO_T +osal_mdc_invalidateCache( + void *ptr_virt_addr, + const UI32_T size); + +CLX_ERROR_NO_T +osal_mdc_savePciConfig( + const UI32_T unit); + +CLX_ERROR_NO_T +osal_mdc_restorePciConfig( + const UI32_T unit); + +#endif /* OSAL_MDC_H */ diff --git a/platform/clounix/clounix-modules/modules/src/inc/osal/osal_types.h b/platform/clounix/clounix-modules/modules/src/inc/osal/osal_types.h new file mode 100644 index 000000000000..1bcea9a83a79 --- /dev/null +++ b/platform/clounix/clounix-modules/modules/src/inc/osal/osal_types.h @@ -0,0 +1,318 @@ +/* + * Copyright 2022 Clounix + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation (the "GPL"). + * + * 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 version 2 (GPLv2) for more details. + * + * You should have received a copy of the GNU General Public License + * version 2 (GPLv2) along with this source code. + */ + +/* FILE NAME: osal_types.h + * PURPOSE: + * Define the commom data type in CLX SDK. + * NOTES: + */ + +#ifndef OSAL_TYPES_H +#define OSAL_TYPES_H + +/* INCLUDE FILE DECLARATIONS + */ + +/* NAMING CONSTANT DECLARATIONS + */ + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef NULL +#define NULL (void *)0 +#endif + +#if defined(CLX_EN_HOST_64_BIT_BIG_ENDIAN) +#define UI64_MSW 0 +#define UI64_LSW 1 +#elif defined(CLX_EN_HOST_64_BIT_LITTLE_ENDIAN) +#define UI64_MSW 1 +#define UI64_LSW 0 +#else +#define UI64_MSW 1 +#define UI64_LSW 0 +#endif + +/* DATA TYPE DECLARATIONS + */ +typedef int BOOL_T; +typedef signed char I8_T; +typedef unsigned char UI8_T; +typedef signed short I16_T; +typedef unsigned short UI16_T; +typedef signed int I32_T; +typedef unsigned int UI32_T; +typedef char C8_T; + +#if defined(CLX_EN_COMPILER_SUPPORT_LONG_LONG) +typedef signed long long int I64_T; +typedef unsigned long long int UI64_T; +#else +typedef struct +{ + I32_T i64[2]; +} I64_T; + +typedef struct +{ + UI32_T ui64[2]; +} UI64_T; +#endif + +#if defined(CLX_EN_COMPILER_SUPPORT_LONG_LONG) +#define UI64_HI(dst) ((UI32_T)((dst) >> 32)) +#define UI64_LOW(dst) ((UI32_T)((dst) & 0xffffffff)) +#define UI64_ASSIGN(dst, high, low) ((dst) = (((UI64_T)(high)) << 32 | (UI64_T)(low))) +#define UI64_SET(dst, src) ((dst) = (src)) +#define UI64_ADD_UI32(dst, src) ((dst) += ((UI64_T)(src))) +#define UI64_SUB_UI32(dst, src) ((dst) -= ((UI64_T)(src))) +#define UI64_ADD_UI64(dst, src) ((dst) += (src)) +#define UI64_SUB_UI64(dst, src) ((dst) -= (src)) +#define UI64_AND(dst, src) ((dst) &= (src)) +#define UI64_OR(dst, src) ((dst) |= (src)) +#define UI64_XOR(dst, src) ((dst) ^= (src)) +#define UI64_NOT(dst) ((dst) = ~(dst)) +#define UI64_MULT_UI32(dst, src) ((dst) *= (src)) +#define UI64_MULT_UI64(dst, src) ((dst) *= (src)) +/* UI64_T type data comparion: + * if data1 > data2 return 1 + * if data1 < data2 return -1 + * if data1 == data2 return 0 + */ +#define UI64_CMP(data1, data2) (((data1) > (data2)) ? 1 : (((data1) < (data2)) ? -1 : 0)) + +#else +#define UI64_HI(dst) ((dst).ui64[UI64_MSW]) +#define UI64_LOW(dst) ((dst).ui64[UI64_LSW]) +#define UI64_ASSIGN(dst, high, low) \ + do \ + { \ + UI64_HI(dst) = (high); \ + UI64_LOW(dst) = (low); \ + } while(0) + +#define UI64_SET(dst, src) \ + do \ + { \ + UI64_HI(dst) = UI64_HI(src); \ + UI64_LOW(dst) = UI64_LOW(src); \ + } while(0) + + +#define UI64_ADD_UI32(dst, src) \ + do \ + { \ + UI32_T _i_ = UI64_LOW(dst); \ + UI64_LOW(dst) += (src); \ + if (UI64_LOW(dst) < _i_) \ + { \ + UI64_HI(dst)++; \ + } \ + } while(0) + +#define UI64_SUB_UI32(dst, src) \ + do \ + { \ + UI32_T _i_ = UI64_LOW(dst); \ + UI64_LOW(dst) -= src; \ + if (UI64_LOW(dst) > _i_) \ + { \ + UI64_HI(dst)--; \ + } \ + } while(0) + + +#define UI64_ADD_UI64(dst, src) \ + do \ + { \ + UI32_T _i_ = UI64_LOW(dst); \ + UI64_LOW(dst) += UI64_LOW(src); \ + if (UI64_LOW(dst) < _i_) \ + { \ + UI64_HI(dst)++; \ + } \ + UI64_HI(dst) += UI64_HI(src); \ + } while(0) + +#define UI64_SUB_UI64(dst, src) \ + do { \ + UI32_T _i_ = UI64_LOW(dst); \ + UI64_LOW(dst) -= UI64_LOW(src); \ + if (UI64_LOW(dst) > _i_) \ + { \ + UI64_HI(dst)--; \ + } \ + UI64_HI(dst) -= UI64_HI(src); \ + } while(0) + + +#define UI64_AND(dst, src) \ + do { \ + UI64_HI(dst) &= UI64_HI(src); \ + UI64_LOW(dst) &= UI64_LOW(src); \ + } while(0) + +#define UI64_OR(dst, src) \ + do { \ + UI64_HI(dst) |= UI64_HI(src); \ + UI64_LOW(dst) |= UI64_LOW(src); \ + } while(0) + +#define UI64_XOR(dst, src) \ + do { \ + UI64_HI(dst) ^= UI64_HI(src); \ + UI64_LOW(dst) ^= UI64_LOW(src); \ + } while(0) + +#define UI64_NOT(dst) \ + do { \ + UI64_HI(dst) = ~UI64_HI(dst); \ + UI64_LOW(dst) = ~UI64_LOW(dst); \ + } while(0) + +/* UI64_T type data comparion: + * if data1 > data2 return 1 + * if data1 < data2 return -1 + * if data1 == data2 return 0 + */ +#define UI64_CMP(data1, data2) \ + (((data1).ui64[UI64_MSW] > (data2).ui64[UI64_MSW]) \ + ? 1 : (((data1).ui64[UI64_MSW] == (data2).ui64[UI64_MSW]) \ + ? (((data1).ui64[UI64_LSW] == (data2).ui64[UI64_LSW]) \ + ? 0 :(((data1).ui64[UI64_LSW] > (data2).ui64[UI64_LSW]) \ + ? 1 : -1)) : -1)) + +#define UI64_MULT_UI64(dst, src) \ + do \ + { \ + UI32_T _ret_low_ = 0; \ + UI32_T _ret_high_ = 0; \ + UI32_T _i_ = 0; \ + UI32_T _j_ = 0; \ + UI32_T _temp_ = 0; \ + UI32_T dst_t[4] = {0, 0, 0, 0}; \ + UI32_T src_t[4] = {0, 0, 0, 0}; \ + dst_t[0] = UI64_LOW(dst) & 0xFFFF; \ + dst_t[1] = UI64_LOW(dst) >> 16; \ + dst_t[2] = UI64_HI(dst) & 0xFFFF; \ + dst_t[3] = UI64_HI(dst) >> 16; \ + src_t[0] = UI64_LOW(src) & 0xFFFF; \ + src_t[1] = UI64_LOW(src) >> 16; \ + src_t[2] = UI64_HI(src) & 0xFFFF; \ + src_t[3] = UI64_HI(src) >> 16; \ + for(_i_ = 0; _i_ < 4; _i_++) \ + { \ + for(_j_ = 0; _j_ < 4; _j_++) \ + { \ + if((dst_t[_i_] != 0) && (src_t[_j_] != 0)) \ + { \ + _temp_ = dst_t[_i_] * src_t[_j_]; \ + if(0 == (_i_ + _j_)) \ + { \ + _ret_low_ += _temp_; \ + if (_ret_low_ < _temp_) \ + { \ + _ret_high_++; \ + } \ + } \ + if(1 == (_i_ + _j_)) \ + { \ + _ret_low_ += (_temp_ << 16); \ + if (_ret_low_ < (_temp_ << 16)) \ + { \ + _ret_high_++; \ + } \ + _ret_high_ += (_temp_ >> 16); \ + } \ + if(2 == (_i_+_j_)) \ + { \ + _ret_high_ += _temp_; \ + } \ + if(3 == (_i_ + _j_)) \ + { \ + _ret_high_ += (_temp_ << 16); \ + } \ + } \ + } \ + } \ + UI64_HI(dst) = _ret_high_; \ + UI64_LOW(dst) = _ret_low_; \ + } while(0) + +#define UI64_MULT_UI32(dst, src) \ + do \ + { \ + UI32_T _ret_low_ = 0; \ + UI32_T _ret_high_ = 0; \ + UI32_T _i_ = 0; \ + UI32_T _j_ = 0; \ + UI32_T _temp_ = 0; \ + UI32_T dst_t[4] = {0, 0, 0, 0}; \ + UI32_T src_t[2] = {0, 0}; \ + dst_t[0] = UI64_LOW(dst) & 0xFFFF; \ + dst_t[1] = UI64_LOW(dst) >> 16; \ + dst_t[2] = UI64_HI(dst) & 0xFFFF; \ + dst_t[3] = UI64_HI(dst) >> 16; \ + src_t[0] = src & 0xFFFF; \ + src_t[1] = src >> 16; \ + for(_i_ = 0; _i_ < 4; _i_++) \ + { \ + for(_j_ = 0; _j_ < 2; _j_++) \ + { \ + if((dst_t[_i_] != 0) && (src_t[_j_] != 0)) \ + { \ + _temp_ = dst_t[_i_] * src_t[_j_]; \ + if(0 == (_i_ + _j_)) \ + { \ + _ret_low_ += _temp_; \ + if (_ret_low_ < _temp_) \ + { \ + _ret_high_++; \ + } \ + } \ + if(1 == (_i_ + _j_)) \ + { \ + _ret_low_ += (_temp_ << 16); \ + if (_ret_low_ < (_temp_ << 16)) \ + { \ + _ret_high_++; \ + } \ + _ret_high_ += (_temp_ >> 16); \ + } \ + if(2 == (_i_ + _j_)) \ + { \ + _ret_high_ += _temp_; \ + } \ + if(3 == (_i_ + _j_)) \ + { \ + _ret_high_ += (_temp_ << 16); \ + } \ + } \ + } \ + } \ + UI64_HI(dst) = _ret_high_; \ + UI64_LOW(dst) = _ret_low_; \ + } while(0) + +#endif + +#endif /* OSAL_TYPES_H */ diff --git a/platform/clounix/clx-utils.dep b/platform/clounix/clx-utils.dep new file mode 100644 index 000000000000..683255bd4227 --- /dev/null +++ b/platform/clounix/clx-utils.dep @@ -0,0 +1,9 @@ + +SPATH := $($(CLX_UTILS)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/clx-utils.mk platform/clounix/clx-utils.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(SPATH)) + +$(CLX_UTILS)_CACHE_MODE := GIT_CONTENT_SHA +$(CLX_UTILS)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(CLX_UTILS)_DEP_FILES := $(DEP_FILES) diff --git a/platform/clounix/clx-utils.mk b/platform/clounix/clx-utils.mk new file mode 100644 index 000000000000..455bea19611b --- /dev/null +++ b/platform/clounix/clx-utils.mk @@ -0,0 +1,4 @@ +CLX_UTILS = python-clx-utils_0.1-1_all.deb +$(CLX_UTILS)_SRC_PATH = $(PLATFORM_PATH)/clx-utils + +SONIC_MAKE_DEBS += $(CLX_UTILS) diff --git a/platform/clounix/clx-utils/Makefile b/platform/clounix/clx-utils/Makefile new file mode 100644 index 000000000000..4960c050841f --- /dev/null +++ b/platform/clounix/clx-utils/Makefile @@ -0,0 +1,16 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +MAIN_TARGET = python-clx-utils_0.1-1_all.deb + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + pushd ./clounix-utils + + # Build source and Debian packages + rm -rf deb_dist/* + python setup.py --command-packages=stdeb.command bdist_deb + popd + + # Move the newly-built .deb package to the destination directory + mv ./clounix-utils/deb_dist/$* $(DEST)/ diff --git a/platform/clounix/clx-utils/clounix-utils/port_breakout/__init__.py b/platform/clounix/clx-utils/clounix-utils/port_breakout/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/clounix/clx-utils/clounix-utils/port_breakout/api_libpcfgparsing.txt b/platform/clounix/clx-utils/clounix-utils/port_breakout/api_libpcfgparsing.txt new file mode 100644 index 000000000000..5d17b08b854d --- /dev/null +++ b/platform/clounix/clx-utils/clounix-utils/port_breakout/api_libpcfgparsing.txt @@ -0,0 +1,42 @@ + +# parse_port_config_ini(config_file_path) +{ + 'phy_port_info':{ + physical port:{ + 'user_port':{ name:{ + 'lanes':[logic_lane1, logic_lane2...], + 'alias':'', + 'max-speed':dd + } + } + 'lane_list': [logic_lane1, logic_lane2] + } + } + 'logical_lane_2_phy_port':{ + logic_lane: physical port + } + 'user_port_2_phy_port': { + user_port: phy port + } +} + +# parse_clx_dsh(config_file_path) +{ + 'clx_port_2_logic_lane': { + clx_port(unit,port): [logic_lane1, logic_lane2] + }, + 'logic_lane_2_clx_port': { + logic_lane: clx_port(unit,port) + }, + 'pre-emphasis': { + # key: value + (logic_lane, property): hex + }, + 'polarity-rev': + # key: value + (logic_lane, property): hex + 'lane-swap': + # key: value + (logic_lane, property): hex +} + diff --git a/platform/clounix/clx-utils/clounix-utils/port_breakout/libpcfgparsing.py b/platform/clounix/clx-utils/clounix-utils/port_breakout/libpcfgparsing.py new file mode 100644 index 000000000000..042f6d58e899 --- /dev/null +++ b/platform/clounix/clx-utils/clounix-utils/port_breakout/libpcfgparsing.py @@ -0,0 +1,616 @@ +#import os.path +import re +import logging +import subprocess +#from pprint import pprint, pformat +from pprint import pprint +#from collections import OrderedDict + +KEY_CLX_PORT_INFO = 'clx_port_info' +KEY_CLX_PORT_INFO_V_ETH_MACRO = 'eth-macro' +KEY_CLX_PORT_INFO_V_CLX_LANE = 'clx-lane' +KEY_CLX_PORT_INFO_V_MAX_SPEED = 'max-speed' +KEY_CLX_PORT_INFO_V_PLANE = 'plane' +KEY_CLX_PORT_INFO_V_PPID = 'ppid' + +KEY_PRE_EMPHASIS = 'pre-emphasis' +KEY_POLARITY_REV = 'polarity-rev' +KEY_LANE_SWAP = 'lane-swap' +KEY_MEDIUM_TYPE = 'medium-type' +KEY_AN = 'an' +KEY_ADVER = 'adver' +KEY_ADMIN = 'admin' +KEY_CPI_PORT_INFO = 'cpi_port_info' + +KEY_PHY_PORT_INFO = 'phy_port_info' +KEY_PHY_PORT_INFO_V_LANE_LIST = 'lane_list' +KEY_PHY_PORT_INFO_V_USER_PORT = 'user_port' +KEY_PHY_PORT_INFO_V_USER_PORT_V_ALIAS = 'alias' +KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES = 'lanes' +KEY_PHY_PORT_INFO_V_USER_PORT_V_MAX_SPEED = 'max-speed' + +KEY_LOGIC_LANE_2_PHY_PORT = 'logical_lane_2_phy_port' +KEY_USER_PORT_2_PHY_PORT = 'user_port_2_phy_port' +KEY_CLX_PORT_2_LOGIC_LANE = 'clx_port_2_logic_lane' +KEY_LOGIC_LANE_2_CLX_PORT = 'logic_lane_2_clx_port' +KEY_CPI_PORT_MAP_DATA = 'cpi_port_map_data' +CPI_PORT_LIST = ["129", "130"] + +logger=logging.getLogger() + + +def _run_diag_command(command, verbose=False): + cmd = ['clx_diag', command ] + mapping_str_buffer = subprocess.check_output(cmd) + if verbose: + print pprint(mapping_str_buffer) + return mapping_str_buffer + + +def _diag_show_info_port(): + """ + run clx_diag cmd to get clx_port and macro lane mapping + :return: + """ + + # get clx_port to macro and lane mapping + # unit/port eth-macro lane max-speed act gua bin plane hw-mac tm-mac mpid ppid + # 0/ 0 0 0 100000 1 0 0 1 16 0 0 0 + cmd = 'diag show info port' + mapping_str_buffer = _run_diag_command(cmd) + return mapping_str_buffer + + +def parse_diag_show_info_port(): + """ + parsing diag show info port output + :param: None + :return: + {'clx_port_info':{ clx_port: { + 'eth-macro': eth-macro, + 'clx-lane': clx-lane, + 'max-speed': max-speed, + 'plane': plane, + 'ppid': ppid + } + } + } + """ + diag_show = _diag_show_info_port() + # unit/port eth-macro lane max-speed act gua bin plane hw-mac tm-mac mpid ppid + # 0/ 0 0 0 100000 1 0 0 1 16 0 0 0 + pr_str = r'''^\s+(?P\d+)\s*/\s*(?P\d+)\s+ #0/0 + (?P\d+)\s+ #eth-macro + (?P\d+)\s+ #lane + (?P\d+)\s+ #max-speed + \d+\s+ #act + \d+\s+ #gua + \d+\s+ #bin + (?P\d+)\s+ #plane + \d+\s+ #hw-mac + \d+\s+ #tm-mac + \d+\s+ #mpid + (?P\d+) #ppid + .*$''' + pat = re.compile(pr_str, re.I | re.M | re.X) + result = pat.finditer(diag_show) + + data = { + KEY_CLX_PORT_INFO: dict() + } + for p in result: + unit = p.group('unit') + port = p.group('port') + eth_macro = p.group('macro') + clx_lane = p.group('clx_lane') + max_speed = p.group('speed') + plane = p.group('plane') + ppid = p.group('ppid') + + data[KEY_CLX_PORT_INFO][(unit, port)] = { + KEY_CLX_PORT_INFO_V_ETH_MACRO: eth_macro, + KEY_CLX_PORT_INFO_V_CLX_LANE: clx_lane, + KEY_CLX_PORT_INFO_V_MAX_SPEED: max_speed, + KEY_CLX_PORT_INFO_V_PLANE: plane, + KEY_CLX_PORT_INFO_V_PPID: ppid + } + return data + + +def parse_port_config_ini(port_config_file): + """ + parse phy port to (eth-group, lane) mapping from config file + :param: port_config_file + :return: + { + 'phy_port_info':{ + physical port:{ + 'user_port':{ name:{ + 'lanes':[logic_lane1, logic_lane2...], + 'alias':'', + 'max-speed':dd + } + } + 'lane_list': [logic_lane1, logic_lane2] + } + } + 'logical_lane_2_phy_port':{ + logic_lane: physical port + } + 'user_port_2_phy_port': { + user_port: phy port + } + } + """ + with open(port_config_file, mode='r') as f: + config = f.read() + + # match content of port_config.ini: + # name lanes alias index speed + # Ethernet0 0,1,2,3 Ethernet1/1 0 100000 + title = [] + data_dict = { + KEY_PHY_PORT_INFO: dict(), + KEY_LOGIC_LANE_2_PHY_PORT: dict(), + KEY_USER_PORT_2_PHY_PORT: dict() + } + for line in config.split('\n'): + if re.search('^#', line): + # The current format is: # name lanes alias index speed + title = line.split()[1:] + continue + content = line.split() + if len(content) == 0 or len(content) != len(title) : # skip blank or invalid line + continue + user_port_name = content[title.index('name')] + logic_lanes = content[title.index('lanes')] + logic_lane_list = logic_lanes.split(',') + user_port_alias = content[title.index('alias')] + phy_port = content[title.index('index')] + if 'speed' in title: + max_speed = content[title.index('speed')] + else: + max_speed = str(25000 * len(logic_lane_list)) + + # update user_port_2_phy_port_mapping + data_dict[KEY_USER_PORT_2_PHY_PORT][user_port_name] = phy_port + + # update logical_lane_2_phy_port mapping + for logic_lane in logic_lane_list: + data_dict[KEY_LOGIC_LANE_2_PHY_PORT][logic_lane] = phy_port + + # -- update phy_port_info -- + # phy_port_info->value + phy_port_info = data_dict[KEY_PHY_PORT_INFO] + if phy_port not in phy_port_info: + phy_port_info[phy_port] = dict() + phy_port_info_value = phy_port_info[phy_port] + + # phy_port_info->value->user_port->value + k = KEY_PHY_PORT_INFO_V_USER_PORT + if k not in phy_port_info_value: + phy_port_info_value[k] = OrderedDict() + all_user_port_value = phy_port_info_value[k] + + # get phy_port_info->value->user_port->value->(port_name)->value + if user_port_name not in all_user_port_value: + all_user_port_value[user_port_name] = dict() + cur_user_port_value = all_user_port_value[user_port_name] + + # update phy_port_info->value->user_port->value->(port_name)->value->alias->value + cur_user_port_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_ALIAS] = user_port_alias + + # update phy_port_info->value->user_port->value->(port_name)->value->max-speed->value + cur_user_port_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_MAX_SPEED] = max_speed + + # update phy_port_info->value->user_port->value->(port_name)->value->lanes->value + cur_user_port_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES] = logic_lane_list[:] + + # updte phy_port_info->value->lane_list->value + k=KEY_PHY_PORT_INFO_V_LANE_LIST + if k not in phy_port_info_value: + phy_port_info_value[k] = list() + phy_port_info_value[k].extend(logic_lane_list) + + return data_dict + + +def _parse_port_map(config_file): + """ + :return: + { + 'clx_port_2_logical_lane': { + clx_port(unit,port): [logic_lane1, logic_lane2] + }, + 'logical_lane_2_clx_port': { + logic_lane: clx_port(unit,port) + }, + 'cpi_port_map_data':{ + 'init set port-map port=129 eth-macro=0 lane=1 max-speed=10g active=true guarantee=true cpi=true', + 'init set port-map port=130 eth-macro=0 lane=0 max-speed=10g active=true guarantee=true cpi=true init-done=true' + } + } + """ + with open(config_file, mode='r') as f: + config_content = f.read() + + #init set port-map port=0 eth-macro=2 lane=0 max-speed=25g active=true + pat_str = r'''^init\s+set\s+port-map\s+ + (unit=(?P\d+)\s+){0,1} # unit=0 + port=(?P\d+)\s+ # port=0 + eth-macro=(?P\d+)\s+ #eth-macro=4 + lane=(?P\d+)\s+ #lane=0 + .*$ + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + result = pat.finditer(config_content) + data_dict={ + KEY_CLX_PORT_2_LOGIC_LANE: dict(), + KEY_LOGIC_LANE_2_CLX_PORT: dict(), + KEY_CPI_PORT_MAP_DATA: list() + } + for pre in result: + unit = pre.group('unit') + if unit is None: + unit = '0' + + port = pre.group('port') + if port in CPI_PORT_LIST: # skip cpi ports + data_dict[KEY_CPI_PORT_MAP_DATA].append(pre.group(0)) + continue + + eth_macro = pre.group('eth_macro') + + lane = pre.group('lane') + + logic_lane = macro_lane_2_logic_lane(eth_macro, lane) + + clx_port_tuple = (unit, port) + + clx_port_2_logic_lane = data_dict[KEY_CLX_PORT_2_LOGIC_LANE] + if clx_port_tuple not in clx_port_2_logic_lane: + clx_port_2_logic_lane[clx_port_tuple] = list() + clx_port_2_logic_lane[clx_port_tuple].append(logic_lane) + + data_dict[KEY_LOGIC_LANE_2_CLX_PORT][logic_lane] = clx_port_tuple + + return data_dict + + +def _parse_phy_attr_from_file(config_file, clx_port_2_logic_lane): + """ + parse pre-emphasis|lane-swap/polarity-rev of phy port from clx/dsh file + :param config_file: + :return: + { + 'pre-emphasis': { + # key: value + (logic_lane, property): hex_value, + cpi_port_info: [ + 'phy set pre-emphasis portlist=129 lane-cnt=1 property=c2 data=0x01', + 'phy set pre-emphasis portlist=130 lane-cnt=1 property=c1 data=0x03' + ] + }, + 'polarity-rev': { + # key: value + (logic_lane, property): hex_value, + cpi_port_info: [ + 'phy set polarity-rev portlist=129 lane-cnt=1 property=tx data=0x0' + 'phy set polarity-rev portlist=130 lane-cnt=1 property=tx data=0x0' + ] + } + 'lane-swap': { + # key: value + (logic_lane, property): hex_value + cpi_port_info: [ + 'phy set lane-swap portlist=129 lane-cnt=1 property=tx data=0x1', + 'phy set lane-swap portlist=130 lane-cnt=1 property=tx data=0x0' + ] + } + } + """ + # content of lane-swap config file: + # phy set lane-swap portlist=48-53 lane-cnt=4 property=tx data=0x03.02.01.00 + # phy set polarity-rev portlist=53 lane-cnt=4 property=rx data=0x0.0.0.0 + with open(config_file, mode='r') as f: + config_content = f.read() + + pat_str = r'''^phy\s+set\s+(?Plane-swap|polarity-rev|pre-emphasis)\s+ #pre-emphasis|phy set lane-swap/polarity-rev + (unit=(?P\d+)\s+){0,1} #unit=0 + portlist=(?P[\d\-,]+)\s+ #portlist=0 + lane-cnt=(?P\d+)\s+ #lane-cnt=4 + property=(?P\w+)\s+ #property=tx/rx/c2/c1/c0/cn1 + data=(?P[\w\.]+) #data=0x01.01.01.01 + .*?$ + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + result = pat.finditer(config_content) + data_dict={ + KEY_PRE_EMPHASIS: dict(), + KEY_LANE_SWAP: dict(), + KEY_POLARITY_REV: dict() + } + for pre in result: + phy_attr = pre.group('phy_attr') + unit = pre.group('unit') + if unit is None: + unit = '0' + portlist = pre.group('portlist') + lane_cnt = pre.group('lane_cnt') + property_data = pre.group('property') + data = pre.group('data') + data_hl = [hex(y)[2:] for y in [int(x, 16) for x in data.split('.')]] + if int(lane_cnt) != len(data_hl): + logger.error("lane count mismatch value : {}\n".format(pre.group(0))) + continue + + for p in parse_portlist_range(portlist): + # if CPI ports, just mark down and continue parsing next match + if p in CPI_PORT_LIST: + if phy_attr == 'pre-emphasis': + attr_value = data_dict[KEY_PRE_EMPHASIS] + elif phy_attr == 'lane-swap': + attr_value = data_dict[KEY_LANE_SWAP] + elif phy_attr == 'polarity-rev': + attr_value = data_dict[KEY_POLARITY_REV] + if KEY_CPI_PORT_INFO not in attr_value: + attr_value[KEY_CPI_PORT_INFO] = list() + attr_value[KEY_CPI_PORT_INFO].append(pre.group(0)) + break + + # get first logic_lane number from clx_port(unit,port) + k = (unit, p) + if k not in clx_port_2_logic_lane: + logger.error("(unit {},port {}) is not in clx_port_2_logic_lane\n".format(unit, p)) + continue + logic_lane_start = int(clx_port_2_logic_lane[k][0]) + + # store all data with key (logic_lane, property) + for index, logic_lane in enumerate(range(logic_lane_start, logic_lane_start + int(lane_cnt))): + if phy_attr == 'pre-emphasis': + attr_value = data_dict[KEY_PRE_EMPHASIS] + elif phy_attr == 'lane-swap': + attr_value = data_dict[KEY_LANE_SWAP] + elif phy_attr == 'polarity-rev': + attr_value = data_dict[KEY_POLARITY_REV] + k = (str(logic_lane), property_data) + attr_value[k] = data_hl[index] + + return data_dict + + +def parse_clx_dsh(config_file): + """ + :return: + { + 'clx_port_2_logical_lane': { + clx_port(unit,port): [logic_lane1, logic_lane2] + }, + 'logical_lane_2_clx_port': { + logic_lane: clx_port(unit,port) + }, + 'cpi_port_map_data':[ + 'init set port-map port=129 eth-macro=0 lane=1 max-speed=10g active=true guarantee=true cpi=true', + 'init set port-map port=130 eth-macro=0 lane=0 max-speed=10g active=true guarantee=true cpi=true init-done=true' + ], + 'pre-emphasis': { + # key: value + (logic_lane, property): hex_value, + cpi_port_info: [ + 'phy set pre-emphasis portlist=129 lane-cnt=1 property=c2 data=0x01', + 'phy set pre-emphasis portlist=130 lane-cnt=1 property=c1 data=0x03' + ] + }, + 'polarity-rev': { + # key: value + (logic_lane, property): hex_value, + cpi_port_info: [ + 'phy set polarity-rev portlist=129 lane-cnt=1 property=tx data=0x0' + 'phy set polarity-rev portlist=130 lane-cnt=1 property=tx data=0x0' + ] + }, + 'lane-swap': { + # key: value + (logic_lane, property): hex_value + cpi_port_info: [ + 'phy set lane-swap portlist=129 lane-cnt=1 property=tx data=0x1', + 'phy set lane-swap portlist=130 lane-cnt=1 property=tx data=0x0' + ] + }, + 'medium-type': { + clx_port(unit,port): 'sr', + cpi_port_info: [ + 'port set property portlist=129-130 medium-type=kr' + ] + }, + 'an': { + clx_port(unit,port): 'enable', + cpi_port_info: [ + 'port set property portlist=129-130 an=enable' + ] + }, + 'adver': { + clx_port(unit,port): ['speed-100g','speed-25g'], + cpi_port_info: [ + 'port set adver portlist=129-130 speed-10g-kr' + ] + }, + 'admin': { + clx_port(unit,port): 'enable', + cpi_port_info: [ + 'port set property portlist=129-130 admin=enable' + ] + } + } + """ + data_dict = dict() + data_port_map = _parse_port_map(config_file) + data_phy_attribute = _parse_phy_attr_from_file(config_file, data_port_map[KEY_CLX_PORT_2_LOGIC_LANE]) + data_port_property = _parse_port_property_from_file(config_file) + data_dict.update(data_port_map) + data_dict.update(data_phy_attribute) + data_dict.update(data_port_property) + return data_dict + + +def _parse_port_property_from_file(config_file): + """ + parse adver | medium-type | an | admin status of port from clx/dsh file + + :param : config_file + :return: + { + 'medium-type': { + clx_port(unit,port): 'sr', + cpi_port_info: [ + 'port set property portlist=129-130 medium-type=kr' + ] + }, + 'an': { + clx_port(unit,port): 'enable', + cpi_port_info: [ + 'port set property portlist=129-130 an=enable' + ] + }, + 'adver': { + clx_port(unit,port): ['speed-100g','speed-25g'], + cpi_port_info: [ + 'port set adver portlist=129-130 speed-10g-kr' + ] + }, + 'admin': { + clx_port(unit,port): 'enable', + cpi_port_info: [ + 'port set property portlist=129-130 admin=enable' + ] + } + } + """ + # content of config file: + + # port set property portlist=129-130 medium-type=kr + # port set adver portlist=129-130 speed-10g-kr + # port set property portlist=129-130 an=enable + # port set property portlist=129-130 admin=enable + + with open(config_file, mode='r') as f: + config_content = f.read() + + data_dict={ + KEY_MEDIUM_TYPE: dict(), + KEY_AN: dict(), + KEY_ADMIN: dict(), + KEY_ADVER: dict() + } + + pat_str = r'''^port\s+set\s+property\s+ #port set property + (unit=(?P\d+)\s+){0,1} #unit=0 + portlist=(?P[\d\-,]+)\s+ #portlist=0 + (?Pmedium-type|an|admin)=(?P[\w]+) + .*?$ + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + result = pat.finditer(config_content) + for pre in result: + unit = pre.group('unit') + if unit is None: + unit = '0' + portlist = pre.group('portlist') + property_data = pre.group('property') + data = pre.group('data') + + for p in parse_portlist_range(portlist): + if property_data == 'medium-type': + attr_value = data_dict[KEY_MEDIUM_TYPE] + elif property_data == 'an': + attr_value = data_dict[KEY_AN] + elif property_data == 'admin': + attr_value = data_dict[KEY_ADMIN] + # CPI ports + if p in CPI_PORT_LIST: + if KEY_CPI_PORT_INFO not in attr_value: + attr_value[KEY_CPI_PORT_INFO] = list() + attr_value[KEY_CPI_PORT_INFO].append(pre.group(0)) + break + # clx ports + attr_value[(unit, p)] = data + + pat_str = r'''^port\s+set\s+adver\s+ #port set adver + (unit=(?P\d+)\s+){0,1} #unit=0 + portlist=(?P[\d\-,]+)\s+ #portlist=0 + (?P.*?$) + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + result = pat.finditer(config_content) + for pre in result: + unit = pre.group('unit') + if unit is None: + unit = '0' + portlist = pre.group('portlist') + data = pre.group('data') + + for p in parse_portlist_range(portlist): + attr_value = data_dict[KEY_ADVER] + # CPI ports + if p in CPI_PORT_LIST: + if KEY_CPI_PORT_INFO not in attr_value: + attr_value[KEY_CPI_PORT_INFO] = list() + attr_value[KEY_CPI_PORT_INFO].append(pre.group(0)) + break + # clx ports + attr_value[(unit, p)] = data.split() + + return data_dict + +def parse_portlist_range(portlist_str): + portlist=list() + if not portlist_str: + return portlist + # validation check + invaild_chr = r'[^\d,-]' + if re.search(invaild_chr, portlist_str): + raise Exception('Invalid portlist range! {}'.format(portlist_str)) + for p_range in portlist_str.split(','): + res = p_range.split('-') + if len(res) == 1: + portlist.extend(res) + elif len(res) != 2: + continue + else: + portlist.extend( + str(x) for x in range(int(res[0]), int(res[1])+1) + ) + # sort and filter duplicate item + portlist = sorted(set(portlist),key=int) + return portlist + + +def create_portlist_range(portlist): + if len(portlist) == 0: + return '' + plist = sorted(set(portlist),key=int) # filter duplicate item + tmp_result = list() + tmp_range = list() + tmp_result.append(tmp_range) + for index, p in enumerate(plist): + if index == 0 : + tmp_range.append(p) + elif int(plist[index-1]) +1 == int(p): + tmp_range.append(p) + else: + tmp_range = list() + tmp_range.append(p) + tmp_result.append(tmp_range) + portlist_str = ','.join( + x[0] if len(x)==1 else x[0] + '-' + x[-1] for x in tmp_result + ) + return portlist_str + + +def logic_lane_2_macro_lane(logic_lane): + logic_lane = int(logic_lane) + return (str(logic_lane // 4), str(logic_lane % 4)) + + +def macro_lane_2_logic_lane(macro, clx_lane): + return str(int(macro)*4 + int(clx_lane)) diff --git a/platform/clounix/clx-utils/clounix-utils/port_breakout/main.py b/platform/clounix/clx-utils/clounix-utils/port_breakout/main.py new file mode 100644 index 000000000000..e3cffafb7f97 --- /dev/null +++ b/platform/clounix/clx-utils/clounix-utils/port_breakout/main.py @@ -0,0 +1,1122 @@ +#!/usr/bin/python3 +# +# Terminology +# fpport: Front Panel Port +# user_port: Port name which configured in port_config.ini +# clx_port: Port index which used by clx sdk + +import sys +import os +import os.path +import logging +import logging.handlers +import shutil +import subprocess +import re +import jinja2 +import datetime +import json +from pprint import pformat +from collections import OrderedDict, defaultdict +from tabulate import tabulate +import click + +import libpcfgparsing as PCFG +from sonic_py_common.device_info import get_machine_info +from sonic_py_common.device_info import get_platform_info +#from swsssdk import ConfigDBConnector, SonicV2Connector +from swsssdk import SonicV2Connector + +LOG_IDENTIFIER = 'clx_port_breakout' +LOG_FORMAT = "%(levelname)s: [%(funcName)s] %(message)s" +SCRIPT_DIR = os.path.dirname(__file__) + +PORT_BREAKOUT_TYPE_NONE = "NO_BREAKOUT" +PORT_BREAKOUT_TYPE_2X = "BREAKOUT_2X" +PORT_BREAKOUT_TYPE_4X = "BREAKOUT_4X" +PORT_BREAKOUT_TYPE_2_NUM_MAP = { + PORT_BREAKOUT_TYPE_NONE: 1, + PORT_BREAKOUT_TYPE_2X: 2, + PORT_BREAKOUT_TYPE_4X: 4 +} +PORT_BREAKOUT_NUM_2_TYPE_MAP = dict(zip(PORT_BREAKOUT_TYPE_2_NUM_MAP.values(), PORT_BREAKOUT_TYPE_2_NUM_MAP.keys())) +PORT_BREAKOUT_TYPE_LIST = PORT_BREAKOUT_TYPE_2_NUM_MAP.keys() + +PLANE_PORTS_MAX_COUNT = 32 +DEFAULT_MEDIA_PREFIX = 'sr' # for fiber +DEFAULT_MDIO_DEVAD = '0x1E' +DEFAULT_MDIO_ADDR = '0x2' +DEFAULT_MDIO_VALUE = '0x8000' # for fiber + +PLATFORM_PATH_TEMPLATE = "/usr/share/sonic/device/{platform}" +HWSKU_PATH_TEMPLATE = PLATFORM_PATH_TEMPLATE + "/{hwsku}" +USER_DEFINED_HWSKU_TEMPLATE = "{hwsku}-UD" +PORT_CONFIG_INI = 'port_config.ini' +PORT_CONFIG_CLX = 'port_config.clx' +DEFAULT_SKU = 'default_sku' +ORIG_DEFAULT_SKU = 'default_sku.origin' +CONFIG_DB_JSON_FILE = '/etc/sonic/config_db.json' +BAK_CONFIG_DB_JSON_FILE = CONFIG_DB_JSON_FILE + '-' + LOG_IDENTIFIER + +TMP_USER_PORT_NAME_PREFIX = 'tmp_port' +TMP_USER_PORT_NAME_TEMPLATE = TMP_USER_PORT_NAME_PREFIX + '{fpport}/{usr_port_num}' + +# Return Value Enum +NOOP = None +BREAK_SUCCESS = 0 +ERR_NOTSUPPORT = -1 +ERR_UNKOWN_BREAKOUT_TYPE = -2 +ERR_OVER_MAXCOUNT = -3 +ERR_UNKNOWN_PORT = -4 +ERR_PORT_DISABLED = -5 +ERR_VALIDATION_CHECK_FAILED = -6 + +# Render Template +PORT_CONFIG_CLX_TEMPLATE = 'port_config.clx.j2' + +PORT_BREAKOUT_TABLE_NAME = 'PORT_BREAKOUT' +PORT_BREAKOUT_JSON_FILE = '/etc/sonic/port_breakout.json' + +# STATE DB Schema +PORT_CFG_STATE_NAME = 'PORT_CFG_STATE' +STATE_MODIFIED = 'modified' + + +# --- init logger --- +logger = logging.getLogger(LOG_IDENTIFIER) +logger.setLevel(logging.INFO) +logger.addHandler(logging.NullHandler()) + + +def init_logger(log_level=logging.INFO, stdout=True): + global logger + if stdout: + stdout_handler=logging.StreamHandler(sys.stdout) + stdout_handler.setFormatter(logging.Formatter(LOG_FORMAT)) + logger.addHandler(stdout_handler) + logger.setLevel(log_level) + + +def m_print(msg, *arg, **kwargs): + click.echo(msg) + + +def get_hwsku_from_default_sku(default_sku): + with open(default_sku, 'r') as fh: + content = fh.read() + hwsku, _ = content.split(' ') + return hwsku + + +def get_port_config_ini(platform, hwsku): + hwsku_dir = HWSKU_PATH_TEMPLATE.format(platform=platform, hwsku=hwsku) + return os.path.join(hwsku_dir, PORT_CONFIG_INI) + + +def get_port_config_clx(platform, hwsku): + hwsku_dir = HWSKU_PATH_TEMPLATE.format(platform=platform, hwsku=hwsku) + return os.path.join(hwsku_dir, PORT_CONFIG_CLX) + + +def get_platform(): + machine_info = get_machine_info() + platform = get_platform_info(machine_info) + return platform + + +def render(src_tpl, *args, **kargs): + env = jinja2.Environment(loader=jinja2.FileSystemLoader(os.path.dirname(src_tpl))) + t = env.get_template(os.path.basename(src_tpl)) + return t.render(*args, **kargs) + + +def write_file(dst_file, content): + logger.debug("write content to {}".format(dst_file)) + with open(dst_file, 'w+') as fh: + fh.write(content) + + +def logic_lane_2_macro_lane(logic_lane): + return PCFG.logic_lane_2_macro_lane(logic_lane) + + +def make_tabulate(list1, list2, headers=None): + if not headers: + headers=['From', 'to'] + data = [('\n'.join(list1), '\n'.join(list2))] + return tabulate(data, + headers=headers, + tablefmt="simple", + missingval="", + disable_numparse=True) + +def state_db(op, name, value=''): + db = SonicV2Connector() + db.connect(db.STATE_DB) + res = -1 + client = db.redis_clients[db.STATE_DB] + if op == 'set': + res = client.set(name, value) + elif op == 'del': + res = client.delete(name, value) + elif op == 'get': + res = client.get(name) + if res == -1: + raise Exception('Unsupport action!') + return res + + +def set_state_db(name, value): + return state_db('set', name, value) + + +def get_state_db(name): + return state_db('get', name) + + +class PortBreakout: + def __init__(self): + self._dryrun_ = True + self.platform = get_platform() + self.platform_dir = PLATFORM_PATH_TEMPLATE.format(platform=self.platform) + self.default_sku = os.path.join(self.platform_dir, DEFAULT_SKU) + self.orig_default_sku = os.path.join(self.platform_dir, ORIG_DEFAULT_SKU) + if self.is_firsttime_running: + self._create_usr_defined_hwsku_dir() + self.default_hwsku = get_hwsku_from_default_sku(self.default_sku) + self.default_hwsku_dir = HWSKU_PATH_TEMPLATE.format( + platform=self.platform, + hwsku=self.default_hwsku) + self.orig_default_hwsku = get_hwsku_from_default_sku(self.orig_default_sku) + self.orig_default_hwsku_dir = HWSKU_PATH_TEMPLATE.format( + platform=self.platform, + hwsku=self.orig_default_hwsku) + self._init_port_profile() + + def _init_port_profile(self): + self.cur_port_profile = PortProfile(self.platform, self.default_hwsku) + self.orig_port_profile = PortProfile(self.platform, self.orig_default_hwsku) + + # --- Breakout APIs --- + @property + def is_firsttime_running(self): + return not os.path.exists(self.orig_default_sku) + + def show(self, fpport_index_list=None, show_index_0based=True, print_msg=True): + if fpport_index_list and len(fpport_index_list) != 0: + self.validation_check(fpport_index_list, is_valid=True) + all_fp_list = fpport_index_list + else: + all_fp_list = self.orig_port_profile.get_fpports() + cur_fp_list = self.cur_port_profile.get_fpports() + headers = ['FrontPannelPort(0-based)' if show_index_0based else 'FrontPannelPort(1-based)', 'BreakoutPorts', 'Lanes'] + data = [] + + for fp in all_fp_list: + #FrontPannelPort + item= [fp] if show_index_0based else [str(int(fp)+1)] + if fp not in cur_fp_list: # disabled ports + item[0] = item[0] + ' (disabled)' + data.append(item) + continue + fp_breakout_ports = self.cur_port_profile.get_fpport_user_ports(fp) + if TMP_USER_PORT_NAME_PREFIX in fp_breakout_ports[0]: # modified(enable/breakout) ports + item[0] = item[0] + ' (modified)' + # BreakoutPorts + item.append("\n".join(fp_breakout_ports)) + # Lanes + item.append("\n".join( + ",".join(self.cur_port_profile.get_user_port_lanes(p, fp)) for p in fp_breakout_ports)) + data.append(item) + + msg = tabulate(data, + headers=headers, + tablefmt="simple", + missingval="", + disable_numparse=True) + if print_msg: + m_print(msg) + return msg + + def is_port_breakable(self, fpport_index): + """ + Breakable port should have more than 1 logic lane + :param : fpport_index + :return: + """ + return self.is_valid_port(fpport_index) and len(self.orig_port_profile.get_fpport_lanes(fpport_index)) > 1 + + def is_valid_port(self, fpport_index): + """ + Return true if port in original port config ini + """ + return fpport_index in self.orig_port_profile.get_fpports() + + def is_enabled_port(self, fpport_index): + fp_ports = self.cur_port_profile.get_fpports() + return fpport_index in fp_ports + + def breakout_fpports(self, fpport_index_list, breakout_type=PORT_BREAKOUT_TYPE_4X): + self.validation_check(fpport_index_list, is_valid=True, is_enabled=True, is_breakable=True) + for fpport_index in fpport_index_list: + if breakout_type not in PORT_BREAKOUT_TYPE_2_NUM_MAP: + logger.error('Unsupport breakout type {}!'.format(breakout_type)) + return ERR_UNKOWN_BREAKOUT_TYPE + if self.cur_port_profile.is_over_plane_ports_cnt_limit(fpport_index, breakout_type): + logger.error('Over limitation of max plane ports({}) when try to breakout fp port {}(0-based), Abort!'.format(PLANE_PORTS_MAX_COUNT, fpport_index)) + return ERR_OVER_MAXCOUNT + self._do_breakout(fpport_index, breakout_type) + self._genereate_cfg() + + def _do_breakout(self, fpport_index, breakout_type): + fp_usr_ports = self.cur_port_profile.get_fpport_user_ports(fpport_index) + cur_port_breakout_count = len(fp_usr_ports) + exp_port_breakout_count = PORT_BREAKOUT_TYPE_2_NUM_MAP[breakout_type] + if cur_port_breakout_count == exp_port_breakout_count: + logger.warning('Front pannel port {}(0-based) has been setted to be {}).'.format(fpport_index, breakout_type)) + return NOOP + logger.info('Front pannel port {}(0-based) breakout type change from {} to {} '.format(fpport_index, PORT_BREAKOUT_NUM_2_TYPE_MAP[cur_port_breakout_count], breakout_type)) + fp_max_speed = sum(int(self.cur_port_profile.get_user_port_speed(usr_port, fpport_index)) for usr_port in fp_usr_ports) + fp_lanes_reverse = sorted(self.cur_port_profile.get_fpport_lanes(fpport_index), key=int, reverse=True) + p_alias_prefix = self.cur_port_profile.get_user_port_alias(fp_usr_ports[0], fpport_index).rpartition('/')[0] + p_lane_count = len(fp_lanes_reverse) / PORT_BREAKOUT_TYPE_2_NUM_MAP[breakout_type] + tmp_usr_port_infos = OrderedDict() + for port_cnt in range(1, PORT_BREAKOUT_TYPE_2_NUM_MAP[breakout_type] + 1): + p_name = TMP_USER_PORT_NAME_TEMPLATE.format(fpport=fpport_index, usr_port_num=str(port_cnt)) + p_lanes = [fp_lanes_reverse.pop() for i in range(p_lane_count)] + p_alias = p_alias_prefix + '/' + str(port_cnt) + p_speed = fp_max_speed / PORT_BREAKOUT_TYPE_2_NUM_MAP[breakout_type] + tmp_usr_port_infos[p_name] = { + 'lanes': p_lanes, + 'alias': p_alias, + 'max-speed': p_speed + } + self.cur_port_profile.update_fpport_user_port_info(fpport_index, tmp_usr_port_infos) + logger.info('Breakout front panel port {}(0-based): \n'.format(fpport_index) + make_tabulate(fp_usr_ports, tmp_usr_port_infos.keys())) + + + def disable_fpports(self, fpport_index_list): + self.validation_check(fpport_index_list, is_valid=True) + for fpport_index in fpport_index_list: + if not self.is_enabled_port(fpport_index): + logger.warning('Front panel port {}(0-based) has been disabled!!'.format(fpport_index)) + continue + self._disable_fpport(fpport_index) + self._genereate_cfg() + + def _disable_fpport(self, fpport_index): + self.cur_port_profile.disable_fpport(fpport_index) + logger.info('Disable Front panel port {}(0-based)'.format(fpport_index)) + + def enable_fpports(self, fpport_index_list): + self.validation_check(fpport_index_list, is_valid=True) + for fpport_index in fpport_index_list: + if self.is_enabled_port(fpport_index): + logger.warning('Front panel port {}(0-based) has been enabled!!'.format(fpport_index)) + continue + # check is over plane ports limitation after enable a fp port. + exp_breakout_count = PORT_BREAKOUT_TYPE_2_NUM_MAP[PORT_BREAKOUT_TYPE_NONE] + fp_plane = self.orig_port_profile.get_fpport_plane(fpport_index) + cur_plane_ports_cnt = self.cur_port_profile.get_plane_port_count(fp_plane) + if cur_plane_ports_cnt + exp_breakout_count > PLANE_PORTS_MAX_COUNT: + logger.error('Over limitation of max plane ports({}) when try to enable fp port {}(0-based), Abort!'.format(PLANE_PORTS_MAX_COUNT, fpport_index)) + return ERR_OVER_MAXCOUNT + self._enable_fpport(fpport_index) + self._genereate_cfg() + + def _enable_fpport(self, fpport_index): + # generate user ports info of the fp port. + # use front panel port info from origin port_config.ini + fp_usr_ports = self.orig_port_profile.get_fpport_user_ports(fpport_index) + fp_max_speed = sum(int(self.orig_port_profile.get_user_port_speed(usr_port, fpport_index)) for usr_port in fp_usr_ports) + fp_lanes = self.orig_port_profile.get_fpport_lanes(fpport_index) + p_alias_prefix = self.orig_port_profile.get_user_port_alias(fp_usr_ports[0], fpport_index).rpartition('/')[0] + tmp_usr_port_infos = OrderedDict() + tmp_usr_port_name = TMP_USER_PORT_NAME_TEMPLATE.format(fpport=fpport_index, usr_port_num=1) + tmp_usr_port_infos[tmp_usr_port_name] = { + 'lanes': fp_lanes, + 'alias': p_alias_prefix + '/1', + 'max-speed': fp_max_speed + } + # update current port profile with the new user ports info + self.cur_port_profile.update_fpport_user_port_info(fpport_index, tmp_usr_port_infos) + logger.info('Enable Front panel port {}(0-based)'.format(fpport_index)) + + def reset_fpports(self, fpport_index_list): + self.validation_check(fpport_index_list, is_valid=True, is_enabled=True) + for fpport_index in fpport_index_list: + self._do_breakout(fpport_index, breakout_type=PORT_BREAKOUT_TYPE_NONE) + logger.info('Reset Front panel port {}(0-based)'.format(fpport_index)) + self._genereate_cfg() + + def reset_all(self): + shutil.rmtree(self.default_hwsku_dir) + shutil.copytree(self.orig_default_hwsku_dir, self.default_hwsku_dir) + self.reset_config_db_json() + logger.warning('Reset all front panel ports breakout configuration!') + + def reset_config_db_json(self): + """ + Trigger to regenerate configuration as firsttime on next booting. + Last configuration will be backuped. + :return: + """ + # backup config db json + if os.path.exists(CONFIG_DB_JSON_FILE): + now = datetime.datetime.now() + timestamp = str(now.year) + str(now.month) + str(now.day) + str(now.hour) + str(now.minute) + "_" + str(now.second) + bak_cfg_json = BAK_CONFIG_DB_JSON_FILE + '-' + timestamp + shutil.copy(CONFIG_DB_JSON_FILE, bak_cfg_json) + os.remove(CONFIG_DB_JSON_FILE) + logger.warning("Set default!! Previous config_db.json is stored to - {}.".format(bak_cfg_json)) + else: + logger.info("config_db.json not found! Skip backup!") + + # touch firsttime + res = subprocess.check_output('sonic_installer list', shell=True, stderr=subprocess.STDOUT) + boot_image = re.search(r"Current: SONiC-OS-([^\s]*)", res).group(1) + first_time_flag = '/host/image-{}/platform/firsttime'.format(boot_image) + with open(first_time_flag, 'w+') as fh: + pass + logger.warning("Touch firsttime booting flag!") + + def _generate_port_config_ini(self): + header = ('# name', 'lanes', 'alias', 'index', 'speed') + name_template = "Ethernet{}" + next_name_index = 0 + alias_tpl = "Ethernet{}/{}" + data = list() + cur_fpports = self.cur_port_profile.get_fpports() + orig_fpports = self.orig_port_profile.get_fpports() + for fpport_index in orig_fpports: + if fpport_index not in cur_fpports: + next_name_index += len(self.orig_port_profile.get_fpport_lanes(fpport_index)) + continue + usr_ports = self.cur_port_profile.get_fpport_user_ports(fpport_index) + # user ports of front panel port should be stored in a OrderedDict + for index, usr_p in enumerate(usr_ports, start=1): + usr_port_lanes = self.cur_port_profile.get_user_port_lanes(usr_p, fpport_index) + item = [ + name_template.format(next_name_index), + ','.join(usr_port_lanes), + alias_tpl.format(int(fpport_index)+1, index), + fpport_index, + self.cur_port_profile.get_user_port_speed(usr_p, fpport_index) + ] + data.append(item) + next_name_index += len(usr_port_lanes) + self.new_port_config_ini = tabulate(data, headers=header, tablefmt='plain') + logger.info('Generated new port config ini content.') + logger.debug('New port config ini content \n' + self.new_port_config_ini) + + def _generate_port_config_clx(self): + port_map_list = list() + lane_swap_list = list() + polarity_rev_list = list() + pre_emphasis_list = list() + port_mdio_list = list() + port_medium_list = list() + port_speed_list = list() + + user_port_2_clx_port = dict() + next_unit_port_index = dict() + + # generate clx_port id + for fpport_index in self.cur_port_profile.get_fpports(): + for usr_p in self.cur_port_profile.get_fpport_user_ports(fpport_index): + unit = self.cur_port_profile.get_user_port_unit(usr_p, fpport_index) + if unit not in next_unit_port_index: + next_unit_port_index[unit] = 0 + port = next_unit_port_index[unit] + user_port_2_clx_port[usr_p] = (unit, port) + next_unit_port_index[unit] += 1 + + for fpport_index in self.cur_port_profile.get_fpports(): + user_ports = self.cur_port_profile.get_fpport_user_ports(fpport_index) + # port-map & mdio & speed & medium + for usr_p in user_ports: + p_unit, p_port = user_port_2_clx_port[usr_p] + p_lanes = self.cur_port_profile.get_user_port_lanes(usr_p, fpport_index) + p_macro, p_lane = logic_lane_2_macro_lane(p_lanes[0]) + p_max_speed = int(self.cur_port_profile.get_user_port_speed(usr_p, fpport_index)) // 1000 # convert speed unit from 1 to k + port_map_list.append( + {'unit': p_unit, + 'clx_port': p_port, + 'macro': p_macro, + 'clx_lane': p_lane, + 'max_speed': p_max_speed + } + ) + # mdio + port_mdio_list.append( + {'unit': p_unit, + 'clx_port': p_port, + 'devad': DEFAULT_MDIO_DEVAD, + 'addr': DEFAULT_MDIO_ADDR, + 'value': DEFAULT_MDIO_VALUE + } + ) + # speed + port_speed_list.append( + {'unit': p_unit, + 'clx_port': p_port, + 'speed': p_max_speed + } + ) + # medium + p_medium = DEFAULT_MEDIA_PREFIX + if len(p_lanes) > 1: + p_medium += str(len(p_lanes)) # sr2, sr4 + port_medium_list.append( + {'unit': p_unit, + 'clx_port': p_port, + 'medium': p_medium + } + ) + + fp_lane_list = self.cur_port_profile.get_fpport_lanes(fpport_index) + fp_1st_p_unit, fp_1st_p_clx_port= user_port_2_clx_port[user_ports[0]] + # lane-swap + fp_lane_swap_data = self.cur_port_profile.get_fpport_lane_swap(fpport_index) + lane_swap_list.append( + {"unit": fp_1st_p_unit, + "clx_port": fp_1st_p_clx_port, + "lane_cnt": len(fp_lane_list), + "data": fp_lane_swap_data} + ) + # polarity-rev + fp_polarity_rev_data = self.cur_port_profile.get_fpport_polarity_rev(fpport_index) + polarity_rev_list.append( + {"unit": fp_1st_p_unit, + "clx_port": fp_1st_p_clx_port, + "lane_cnt": len(fp_lane_list), + "data": fp_polarity_rev_data} + ) + # pre-emphasis + fp_pre_emphasis_data = self.cur_port_profile.get_fpport_pre_emphasis(fpport_index) + pre_emphasis_list.append( + {"unit": fp_1st_p_unit, + "clx_port": fp_1st_p_clx_port, + "lane_cnt": len(fp_lane_list), + "data": fp_pre_emphasis_data} + ) + cpi_data = self._generate_cpi_port_config_clx() + self.new_port_config_clx = render( + src_tpl=os.path.join(SCRIPT_DIR, PORT_CONFIG_CLX_TEMPLATE), + port_map=port_map_list, + lane_swap=lane_swap_list, + polarity_rev=polarity_rev_list, + pre_emphasis=pre_emphasis_list, + port_speed=port_speed_list, + port_medium=port_medium_list, + port_mdio=port_mdio_list, + **cpi_data + ) + logger.info('Generated new port config clx content.') + logger.debug("New port config clx content \n" + self.new_port_config_clx ) + + def _generate_cpi_port_config_clx(self): + data_dict = { + 'cpi_port_map': self.cur_port_profile.port_clx[PCFG.KEY_CPI_PORT_MAP_DATA], + 'cpi_lane_swap': self.cur_port_profile.port_clx[PCFG.KEY_LANE_SWAP].get(PCFG.KEY_CPI_PORT_INFO, []), + 'cpi_polarity_rev': self.cur_port_profile.port_clx[PCFG.KEY_POLARITY_REV].get(PCFG.KEY_CPI_PORT_INFO, []), + 'cpi_pre_emphasis': self.cur_port_profile.port_clx[PCFG.KEY_PRE_EMPHASIS].get(PCFG.KEY_CPI_PORT_INFO, []), + 'cpi_medium_type': self.cur_port_profile.port_clx[PCFG.KEY_MEDIUM_TYPE].get(PCFG.KEY_CPI_PORT_INFO, []), + 'cpi_adver': self.cur_port_profile.port_clx[PCFG.KEY_ADVER].get(PCFG.KEY_CPI_PORT_INFO, []), + 'cpi_an': self.cur_port_profile.port_clx[PCFG.KEY_AN].get(PCFG.KEY_CPI_PORT_INFO, []), + 'cpi_admin': self.cur_port_profile.port_clx[PCFG.KEY_ADMIN].get(PCFG.KEY_CPI_PORT_INFO, []) + } + return data_dict + + def save_breakout_cfg(self, write_to_json=True, set_state=True): + p_ini_file = get_port_config_ini(self.platform, self.default_hwsku) + p_clx_file = get_port_config_clx(self.platform, self.default_hwsku) + logger.info('save port config ini to {}'.format(p_ini_file)) + write_file(p_ini_file, self.new_port_config_ini) + logger.info('save port config clx to {}'.format(p_clx_file)) + write_file(p_clx_file, self.new_port_config_clx) + if set_state: + logger.info('Set STATE_DB(6) {}:{}'.format(PORT_CFG_STATE_NAME, STATE_MODIFIED)) + self._set_portcfg_state(STATE_MODIFIED) + if write_to_json: + self.write_to_json() + + def _create_usr_defined_hwsku_dir(self): + if not os.path.exists(self.default_sku): + raise Exception('default_sku not found: {}'.format(self.default_sku)) + cur_hwsku = get_hwsku_from_default_sku(self.default_sku) + cur_hwsku_dir = HWSKU_PATH_TEMPLATE.format(platform=self.platform, hwsku=cur_hwsku) + usr_defined_hwsku = USER_DEFINED_HWSKU_TEMPLATE.format(hwsku=cur_hwsku) + usr_defined_hwsku_dir = HWSKU_PATH_TEMPLATE.format(platform=self.platform, hwsku=usr_defined_hwsku) + + # bakup origin default_sku file + shutil.copy(self.default_sku, self.orig_default_sku) + # update hwsku to user defined hwsku in default_sku + with open(self.default_sku, "w") as fh: + fh.write(usr_defined_hwsku + " t1") + logger.info("Change hwsku from '{}' to '{}' ".format(cur_hwsku, usr_defined_hwsku)) + # copy hwsku dir to user defined hwsku dir for later use + shutil.copytree(cur_hwsku_dir, usr_defined_hwsku_dir) + logger.info("Copy hwsku dir from '{}' to '{}'".format(cur_hwsku_dir, usr_defined_hwsku_dir)) + + + def _genereate_cfg(self): + self._generate_port_config_ini() + self._generate_port_config_clx() + if not self.dryrun: + self.save_breakout_cfg() + self.reset_config_db_json() + else: + logger.info('Dryrun mode, skip saving the breakout configuration!') + + @property + def dryrun(self): + return self._dryrun_ + + @dryrun.setter + def dryrun(self, val): + self._dryrun_ = bool(val) + + def validation_check(self, fpport_index_list, is_valid=False, is_enabled=False, is_breakable=False, is_disabled=False): + validation_msg = 'Front pannel port should be -' + validation_msg += ' Valid,' if is_valid else '' + validation_msg += ' Enabled,' if is_enabled else '' + validation_msg += ' Breakable,' if is_breakable else '' + validation_msg += ' Disabled,' if is_disabled else '' + logger.info(validation_msg) + logger.info("Checking front panel ports index(0-based) - {}".format(fpport_index_list)) + check_pass = True + check_result_dict = { + 'invalid_port_list': list(), + 'enabled_port_list': list(), + 'disabled_port_list': list(), + 'unbreakable_port_list': list() + } + for fpport_index in fpport_index_list: + if is_valid and not self.is_valid_port(fpport_index): + check_result_dict['invalid_port_list'].append(fpport_index) + check_pass = False + continue + if is_enabled and not self.is_enabled_port(fpport_index): + check_result_dict['disabled_port_list'].append(fpport_index) + check_pass = False + continue + if is_disabled and self.is_enabled_port(fpport_index): + check_result_dict['enabled_port_list'].append(fpport_index) + check_pass = False + continue + if is_breakable and not self.is_port_breakable(fpport_index): + check_result_dict['unbreakable_port_list'].append(fpport_index) + check_pass = False + continue + if not check_pass: + logger.warning("Validation check failed !") + for k, v in check_result_dict.iteritems(): + if len(v) == 0 : + continue + if k == 'invalid_port_list': + logger.warning('Invalid front panel port index(0-based) - {}'.format(str(v))) + if k == 'enabled_port_list': + logger.warning('Invalid action for enabled front panel port index(0-based) - {}'.format(str(v))) + if k == 'disabled_port_list': + logger.warning('Invalid action for disabled front panel port index(0-based) - {}'.format(str(v))) + if k == 'unbreakable_port_list': + logger.warning('Unbreakable front panel port index(0-based) - {}'.format(str(v))) + raise Exception('Validation check failed !') + else: + logger.info("Validation check pass.") + return True + + def recover_from_json(self, json_file=PORT_BREAKOUT_JSON_FILE): + ''' + recover port breakout configuration from presaved port breakout json file. + this method should be called only by clounix service. + this method should be executed only on sonic first time booting. + ''' + logger.info('Start recover port breakout configuration from {}'.format(json_file)) + if not os.path.exists(json_file): + raise Exception('Not found {}!!'.format(json_file)) + with open(json_file, 'r') as fh: + pb_cfg_from_db = json.load(fh).get(PORT_BREAKOUT_TABLE_NAME) + if not pb_cfg_from_db: + return + + #all_fp_list = self.orig_port_profile.get_fpports() + params = pb_cfg_from_db['parameters'] + fp_index_0based = params['fp_index_0based_flag'] + fpports_cfg = pb_cfg_from_db['fpports'] + disabled_fp_list = [] + enabled_fp_list = [] + breakout_fp_dict = defaultdict(list) + for fp, fv in fpports_cfg.iteritems(): + fp_index = fp if fp_index_0based else str(int(fp) - 1) # convert fp to 0based fp_index + if not self.is_valid_port(fp_index): + raise Exception('Unknown front pannel {}(0based)'.format(fp_index)) + if fv['status'] == 'disabled': + disabled_fp_list.append(fp_index) + else: + enabled_fp_list.append(fp_index) + breakou_type = PORT_BREAKOUT_NUM_2_TYPE_MAP[int(fv['breakout_num'])] + breakout_fp_dict[breakou_type].append(fp_index) + + logger.info('Disable front panel port list(0based): {} '.format(PCFG.create_portlist_range(disabled_fp_list))) + for p in sorted(disabled_fp_list, key=int): + self._disable_fpport(p) + logger.info('Enable front panel port list(0based): {}' .format(PCFG.create_portlist_range(enabled_fp_list))) + for p in sorted(enabled_fp_list, key=int): + self._enable_fpport(p) + for b_type, p_list in breakout_fp_dict.iteritems(): + logger.info('Beakout type: {}, breakout front panel port list(0based): {}'.format(b_type, PCFG.create_portlist_range(p_list))) + for p in sorted(p_list, key=int): + self._do_breakout(p, b_type) + + # Should not reset config db and wirte port breakout configuration to json as it's recovering configuration + self._generate_port_config_ini() + self._generate_port_config_clx() + self.save_breakout_cfg(write_to_json=False, set_state=False) + logger.info('End recover port breakout configuration from config_db.json') + + + def write_to_json(self, fp_index_0based=False): + ''' + write port breakout configuration to json file; + :params: bool fp_index_0based, write with 0based fp port index if set True else with 1based port index. + ''' + logger.info('write breakout configuration to {}. Use `config save -y` if you want to save the configuration.'.format(PORT_BREAKOUT_JSON_FILE)) + port_breakout_table = { PORT_BREAKOUT_TABLE_NAME: { 'parameters': {'fp_index_0based_flag': fp_index_0based}, + 'fpports': {} } } + all_fp_list = self.orig_port_profile.get_fpports() + for fp in all_fp_list: + fv={} + if self.is_enabled_port(fp): # disabled front panel ports + fv['status'] = 'enabled' + fv['breakout_num'] = len(self.cur_port_profile.get_fpport_user_ports(fp)) + else: # modified or enabled front panel ports + fv['status'] = 'disabled' + fp_1based_index = fp if fp_index_0based else str(int(fp) + 1) + port_breakout_table[PORT_BREAKOUT_TABLE_NAME]['fpports'][fp_1based_index] = fv + if not os.path.exists(os.path.dirname(PORT_BREAKOUT_JSON_FILE)): + os.makedirs(os.path.dirname(PORT_BREAKOUT_JSON_FILE)) + with open(PORT_BREAKOUT_JSON_FILE, 'w+') as fh: + fh.write(json.dumps(port_breakout_table)) + + def _set_portcfg_state(self, state): + set_state_db(PORT_CFG_STATE_NAME, state) + + +class PortProfile: + """ + # parse_port_config_ini(config_file_path) + { + 'phy_port_info':{ + physical port:{ + 'user_port':{ name:{ + 'lanes':[logic_lane1, logic_lane2...], + 'alias':'', + 'max-speed':dd + } + } + 'lane_list': [logic_lane1, logic_lane2] + } + } + 'logical_lane_2_phy_port':{ + logic_lane: physical port + } + 'user_port_2_phy_port': { + user_port: phy port + } + } + + # parse_clx_dsh(config_file_path) + { + 'clx_port_2_logic_lane': { + clx_port(unit,port): [logic_lane1, logic_lane2] + }, + 'logic_lane_2_clx_port': { + logic_lane: clx_port(unit,port) + }, + 'pre-emphasis': { + # key: value + (logic_lane, property): hex + }, + 'polarity-rev': + # key: value + (logic_lane, property): hex + 'lane-swap': + # key: value + (logic_lane, property): hex + } + """ + def __init__(self, platform, hwsku): + PCFG.logger = logger + self.platform = platform + self.hwsku = hwsku + self.port_config = PCFG.parse_port_config_ini(get_port_config_ini(self.platform, self.hwsku)) + self.phy_port_info = self.port_config[PCFG.KEY_PHY_PORT_INFO] + self.port_clx = PCFG.parse_clx_dsh(get_port_config_clx(self.platform, self.hwsku)) + logger.debug( "{} - port_config - \n {}".format(self.hwsku,pformat(self.port_config))) + logger.debug( "{} - port_clx - \n {}".format(self.hwsku, pformat(self.port_clx))) + + def get_fpports(self): + return sorted(self.phy_port_info.keys(), key=int) + + def is_over_plane_ports_cnt_limit(self, fpport_index, breakout_type): + port_plane = self.get_fpport_plane(fpport_index) + plane_port_count = self.get_plane_port_count(port_plane) + fp_breakout_count = len(self.get_fpport_user_ports(fpport_index)) + fp_expect_breakout_count = PORT_BREAKOUT_TYPE_2_NUM_MAP[breakout_type] + return (plane_port_count - fp_breakout_count + fp_expect_breakout_count) > PLANE_PORTS_MAX_COUNT + + def get_fpport_info(self, fpport_index): + return self.phy_port_info.get(fpport_index) + + def get_user_port_lanes(self, user_port_name, fpport_index=None): + v = self.get_user_port_item(user_port_name, + PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES, + fpport_index) + return sorted(v, key=int) + + def get_user_port_alias(self, user_port_name, fpport_index=None): + v = self.get_user_port_item(user_port_name, + PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_ALIAS, + fpport_index) + return v + + def get_user_port_speed(self, user_port_name, fpport_index=None): + v = self.get_user_port_item(user_port_name, + PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_MAX_SPEED, + fpport_index) + if not v: + v ='0' + return v + + def get_user_port_unit(self, user_port_name, fpport_index=None): + if not fpport_index: + fpport_index = self.port_config[PCFG.KEY_USER_PORT_2_PHY_PORT].get(user_port_name) + if not fpport_index: + raise Exception('Can not find front panel index of user port {}'.format(user_port_name)) + fp_lanes = self.get_fpport_lanes(fpport_index) + clx_port = None + for logic_lane in fp_lanes: + clx_port = self.port_clx[PCFG.KEY_LOGIC_LANE_2_CLX_PORT].get(logic_lane) + if clx_port: + return clx_port[0] + return None + + def get_user_port_clx_port(self, user_port_name, fpport_index=None): + usr_p_lanes = self.get_user_port_lanes(user_port_name, fpport_index) + clx_port = None + for logic_lane in usr_p_lanes: + clx_port = self.port_clx[PCFG.KEY_LOGIC_LANE_2_CLX_PORT].get(logic_lane) + if clx_port: + return clx_port[1] + return None + + def get_user_port_item(self, user_port_name, key, fpport_index=None): + user_port = self.get_fpport_user_port_info(user_port_name, fpport_index) + return user_port.get(key) + + def get_fpport_item(self, fpport_index, key): + fp = self.phy_port_info[fpport_index] + return fp.get(key) + + def get_fpport_lanes(self, fpport_index): + return sorted( self.get_fpport_item(fpport_index, PCFG.KEY_PHY_PORT_INFO_V_LANE_LIST), key=int) + + def get_fpport_lane_swap(self, fpport_index): + lane_list = self.get_fpport_lanes(fpport_index) + data = { + 'rx': [], + 'tx': [] + } + t_lane_swap = self.port_clx[PCFG.KEY_LANE_SWAP] + for logic_lane in lane_list: + data['rx'].append(t_lane_swap.get((logic_lane, 'rx'))) + data['tx'].append(t_lane_swap.get((logic_lane, 'tx'))) + return data + + def get_fpport_polarity_rev(self, fpport_index): + lane_list = self.get_fpport_lanes(fpport_index) + data = { + 'rx': [], + 'tx': [] + } + t_polarity_rev = self.port_clx[PCFG.KEY_POLARITY_REV] + for logic_lane in lane_list: + data['rx'].append(t_polarity_rev.get((logic_lane, 'rx'))) + data['tx'].append(t_polarity_rev.get((logic_lane, 'tx'))) + return data + + def get_fpport_pre_emphasis(self, fpport_index): + """ + return pre-emphasis configuration from default config file(clounix_opt.dsh). + """ + DEFAULT_PRE_EMPHASIS_OPT_CFG_FILE_NAME = 'clounix_opt.dsh' + pre_emphasis_cfg_file = os.path.join( + '/usr/share/sonic/device', + self.platform, + self.hwsku, + DEFAULT_PRE_EMPHASIS_OPT_CFG_FILE_NAME + ) + t_pre_emphasis = PCFG.parse_clx_dsh(pre_emphasis_cfg_file)[PCFG.KEY_PRE_EMPHASIS] + lane_list = self.get_fpport_lanes(fpport_index) + data = { + 'c2': [], + 'cn1': [], + 'c1': [], + 'c0': [] + } + for logic_lane in lane_list: + for p in data.keys(): + data[p].append(t_pre_emphasis.get((logic_lane, p))) + return data + + def get_fpport_user_port_info(self, user_port_name, fpport_index=None): + if fpport_index: + fp = self.phy_port_info[fpport_index] + return fp[PCFG.KEY_PHY_PORT_INFO_V_USER_PORT].get(user_port_name) + else: + user_port = None + for v in self.phy_port_info.itervalues(): + user_port = v[PCFG.KEY_PHY_PORT_INFO_V_USER_PORT].get(user_port_name) + if user_port: + break + return user_port + + def get_fpport_user_ports(self, fpport_index): + fp = self.phy_port_info[fpport_index] + usr_p_infos = fp[PCFG.KEY_PHY_PORT_INFO_V_USER_PORT].items() + # sort user port name by logic_lane + usr_p_infos.sort( + key=lambda x: int(x[1][PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES][0]) + ) + usr_ports = [p[0] for p in usr_p_infos] + return usr_ports + + def get_fpport_plane(self, fpport_index): + fp_1st_lane = self.get_fpport_lanes(fpport_index)[0] + fp_plane = str(int(fp_1st_lane)//64) + return fp_plane + + def get_plane_port_count(self, plane): + count = 0 + for fp in self.get_fpports(): + if self.get_fpport_plane(fp) == plane: + count += len(self.get_fpport_user_ports(fp)) + return count + + def set_user_port_item(self, user_port_name, key, value, fpport_index=None): + u = self.get_fpport_user_port_info(user_port_name, fpport_index) + u[key] = value + + def update_fpport_user_port_info(self, fpport_index, usr_port_infos): + tmp_usr_port_odict = OrderedDict() + tmp_fp_lane_list = [] + for usr_p, v in usr_port_infos.iteritems(): + tmp_usr_port_odict[usr_p] = { + PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES: v['lanes'], + PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_ALIAS: v['alias'], + PCFG.KEY_PHY_PORT_INFO_V_USER_PORT_V_MAX_SPEED: v['max-speed'] + } + for lane in v['lanes']: + if lane not in tmp_fp_lane_list: + tmp_fp_lane_list.append(lane) + tmp_fp_lane_list.sort(key=int) + fp = self.get_fpport_info(fpport_index) + if not fp: # disabled fp + fp = dict() + fp[PCFG.KEY_PHY_PORT_INFO_V_LANE_LIST] = tmp_fp_lane_list + self.phy_port_info[fpport_index] = fp + fp[PCFG.KEY_PHY_PORT_INFO_V_USER_PORT] = tmp_usr_port_odict + + def disable_fpport(self, fpport_index): + if fpport_index in self.phy_port_info: + self.phy_port_info.pop(fpport_index) + +def get_fp_ports_4_click(ctx, args, incomplete): + # available until click version >=7.0 + pb = ctx.obj['pb'] + cur_fpports = pb.cur_port_profile.get_fpports() + orig_fpports = pb.orig_port_profile.get_fpports() + content = 'Current front panel ports(0-based): {}\n'.format(PCFG.create_portlist_range(cur_fpports)) + content += 'All front panel ports(0-based): {}'.format(PCFG.create_portlist_range(orig_fpports)) + + +# +# 'cli' group (root group) +# + +@click.group() +@click.pass_context +@click.option('-l','--log-level', + type=click.Choice(('DEBUG', 'INFO', 'WARN', 'ERROR')), + help='Set log level. Default is WARN.') +@click.option('-0','--fp-index-0based', is_flag=True, default=False, + help='Default use 1-based port index.') +@click.option('-d','--dryrun', is_flag=True, + help='Change would not be saved.') +def cli(ctx, log_level, fp_index_0based, dryrun): + """ + Port breakout related configuration. + """ + if os.geteuid() != 0: + exit("Root privileges are required for this operation") + + context = { + "pb": PortBreakout() + } + context.update(ctx.params) # store parameters for subcommand used. + ctx.obj = context + + LOG_LEVEL_MAP = { + 'ERROR': logging.ERROR, + 'WARN': logging.WARN, + 'INFO': logging.INFO, + 'DEBUG': logging.DEBUG + } + log_level = LOG_LEVEL_MAP.get(str(log_level), logging.WARN) + init_logger(log_level) + pb = ctx.obj['pb'] + pb.dryrun = dryrun + +# +# 'port-breakout' command ("port-breakout breakout") +# + +@cli.command() +@click.pass_context +@click.argument('fpport_range', + metavar='', + required=True) +@click.argument('breakout_num', + metavar='[]', + default=PORT_BREAKOUT_TYPE_2_NUM_MAP[PORT_BREAKOUT_TYPE_4X], + type=click.Choice(map(str, PORT_BREAKOUT_TYPE_2_NUM_MAP.values())), + required=False) +def breakout(ctx, fpport_range, breakout_num): + """ + Port breakout configuration. + Breakout front panel ports to 2 or 4 sub-ports. + """ + pb = ctx.obj["pb"] + fpport_list = PCFG.parse_portlist_range(fpport_range) + # convert front panel port index from 1based to 0based + if not ctx.obj['fp_index_0based']: + fpport_list = map(lambda x: str(int(x)-1), fpport_list) + breakout_type = PORT_BREAKOUT_NUM_2_TYPE_MAP[int(breakout_num)] + pb.breakout_fpports(fpport_list, breakout_type) + +# +# 'port-breakout' command ("port-breakout enable") +# + +@cli.command() +@click.pass_context +@click.argument('fpport_range', + metavar='', + required=True) +def enable(ctx, fpport_range): + """ + Enable front panel ports. + Disabe front panel ports would not get initialized. + """ + pb = ctx.obj["pb"] + fpport_list = PCFG.parse_portlist_range(fpport_range) + # convert front panel port index from 1based to 0based + if not ctx.obj['fp_index_0based']: + fpport_list = map(lambda x: str(int(x)-1), fpport_list) + pb.enable_fpports(fpport_list) + +# +# 'port-breakout' command ("port-breakout disable") +# + +@cli.command() +@click.pass_context +@click.argument('fpport_range', + metavar='', + required=True) +def disable(ctx, fpport_range): + """ + Disable front panel ports. + Disabe front panel ports would not get initialized. + """ + pb = ctx.obj["pb"] + fpport_list = PCFG.parse_portlist_range(fpport_range) + # convert front panel port index from 1based to 0based + if not ctx.obj['fp_index_0based']: + fpport_list = map(lambda x: str(int(x)-1), fpport_list) + pb.disable_fpports(fpport_list) + +# +# 'port-breakout' command ("port-breakout reset") +# + +@cli.command() +@click.pass_context +@click.argument('fpport_range', + metavar='', + required=True) +def reset(ctx, fpport_range): + """ + Reset breakout configuration for specified ports. + """ + pb = ctx.obj["pb"] + fpport_list = PCFG.parse_portlist_range(fpport_range) + # convert front panel port index from 1based to 0based + if not ctx.obj['fp_index_0based']: + fpport_list = map(lambda x: str(int(x)-1), fpport_list) + pb.reset_fpports(fpport_list) + +# +# 'port-breakout' command ("port-breakout reset-all") +# + +@cli.command('reset-all') +@click.pass_context +@click.option('-y','--yes', is_flag=True) +def reset_all(ctx, yes): + """ + Reset breakout configuration for all ports. + """ + if not yes: + click.confirm('Reset all ports breakout configuration?', abort=True, default=False) + pb = ctx.obj["pb"] + pb.reset_all() + +# +# 'port-breakout' command ("port-breakout show") +# + +@cli.command() +@click.pass_context +@click.argument('fpport_range', + metavar='', + required=False) +def show(ctx, fpport_range): + """Show port breakout related information.""" + pb = ctx.obj["pb"] + fp_index_0based = ctx.obj['fp_index_0based'] + fpport_list = PCFG.parse_portlist_range(fpport_range) + if not fp_index_0based: + fpport_list = map(lambda x: str(int(x)-1), fpport_list) + pb.show(fpport_list, fp_index_0based) + +# +# 'port-breakout' command ("port-breakout recover-from-json") +# + +@cli.command('recover-from-json') +@click.pass_context +@click.option('-j', '--json-file', + metavar='', + required=False, + default=PORT_BREAKOUT_JSON_FILE) +def recover_from_json(ctx, json_file): + """Recover port breakout configuration from json.""" + pb = ctx.obj["pb"] + pb.recover_from_json(json_file) + +if __name__=='__main__': + cli() + diff --git a/platform/clounix/clx-utils/clounix-utils/port_breakout/port_config.clx.j2 b/platform/clounix/clx-utils/clounix-utils/port_breakout/port_config.clx.j2 new file mode 100644 index 000000000000..3e92a02a93cf --- /dev/null +++ b/platform/clounix/clx-utils/clounix-utils/port_breakout/port_config.clx.j2 @@ -0,0 +1,87 @@ +init start stage low-level + +{# port-map #} +{%- for pm in port_map -%} +init set port-map unit={{ pm.unit }} port={{ pm.clx_port }} eth-macro={{ pm.macro }} lane={{ pm.clx_lane }} max-speed={{pm.max_speed}}g active=true +{% endfor -%} +{# cpi port-map #} +{%- for c_pm in cpi_port_map -%} +{{ c_pm }} +{% endfor %} + +init start stage task-rsrc +init start stage module +init start stage task + +{# lane-swap #} +{%- for ls in lane_swap -%} +phy set lane-swap unit={{ ls.unit }} portlist={{ ls.clx_port }} lane-cnt={{ ls.lane_cnt }} property=tx data=0x{{ls.data['tx'] | join('.')}} +{% endfor %} +{%- for ls in lane_swap -%} +phy set lane-swap unit={{ ls.unit }} portlist={{ ls.clx_port }} lane-cnt={{ ls.lane_cnt }} property=rx data=0x{{ls.data['rx'] | join('.')}} +{% endfor %} +{# cpi lane-swap #} +{%- for c_ls in cpi_lane_swap -%} +{{ c_ls }} +{% endfor %} + +{# polarity-rev #} +{%- for pr in polarity_rev -%} +phy set polarity-rev unit={{ pr.unit }} portlist={{ pr.clx_port }} lane-cnt={{ pr.lane_cnt }} property=tx data=0x{{pr.data['tx'] | join('.')}} +{% endfor %} +{%- for pr in polarity_rev -%} +phy set polarity-rev unit={{ pr.unit }} portlist={{ pr.clx_port }} lane-cnt={{ pr.lane_cnt }} property=rx data=0x{{pr.data['rx'] | join('.')}} +{% endfor %} +{# cpi polarity-rev #} +{%- for c_pr in cpi_polarity_rev -%} +{{ c_pr }} +{% endfor %} + +{# pre_emphasis #} +{%- for pe in pre_emphasis -%} +phy set pre-emphasis unit={{ pe.unit }} portlist={{ pe.clx_port }} lane-cnt={{ pe.lane_cnt }} property=c2 data=0x{{pe.data['c2'] | join('.')}} +phy set pre-emphasis unit={{ pe.unit }} portlist={{ pe.clx_port }} lane-cnt={{ pe.lane_cnt }} property=cn1 data=0x{{pe.data['cn1'] | join('.')}} +phy set pre-emphasis unit={{ pe.unit }} portlist={{ pe.clx_port }} lane-cnt={{ pe.lane_cnt }} property=c1 data=0x{{pe.data['c1'] | join('.')}} +phy set pre-emphasis unit={{ pe.unit }} portlist={{ pe.clx_port }} lane-cnt={{ pe.lane_cnt }} property=c0 data=0x{{pe.data['c0'] | join('.')}} +{% endfor %} +{# cpi pre_emphasis #} +{%- for c_pe in cpi_pre_emphasis -%} +{{ c_pe }} +{% endfor %} + +{# mdio #} +{%- for m in port_mdio -%} +phy set mdio unit={{ m.unit }} portlist={{ m.clx_port }} devad={{ m.devad }} addr={{ m.addr }} data={{ m.value }} +{% endfor %} + +{# port-speed #} +{%- for ps in port_speed -%} +port set property unit={{ ps.unit }} portlist={{ ps.clx_port }} speed={{ ps.speed }}g +{% endfor %} + +{# port-medium-type #} +{%- for pm in port_medium -%} +port set property unit={{ pm.unit }} portlist={{ pm.clx_port }} medium-type={{pm.medium}} +{% endfor %} + +{# cpi medium-type #} +{%- for c_mt in cpi_medium_type -%} +{{ c_mt }} +{% endfor -%} +{# cpi adver #} +{%- for c_adver in cpi_adver -%} +{{ c_adver }} +{% endfor -%} +{# cpi an #} +{%- for c_an in cpi_an -%} +{{ c_an }} +{% endfor -%} +{# cpi admin #} +{%- for c_admin in cpi_admin -%} +{{ c_admin }} +{% endfor %} + +{# disable all ports #} +{%- for pm in port_map -%} +port set property unit={{pm.unit}} portlist={{pm.clx_port}} admin=disable +{% endfor %} diff --git a/platform/clounix/clx-utils/clounix-utils/scripts/sfpdet b/platform/clounix/clx-utils/clounix-utils/scripts/sfpdet new file mode 100644 index 000000000000..bdd01693aee9 --- /dev/null +++ b/platform/clounix/clx-utils/clounix-utils/scripts/sfpdet @@ -0,0 +1,2144 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright (C) 2018 Clounix, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import os +import sys +import time +import subprocess +import re +import logging +import logging.handlers +import imp +import operator +import timeit +import threading +import shutil +import functools +import collections +import click +import traceback +from port_breakout import libpcfgparsing as cfg_parser +from port_breakout.main import get_state_db, PORT_CFG_STATE_NAME, STATE_MODIFIED +from tabulate import tabulate +import itertools +import json + +# python version +if sys.version > '3': + import queue as que +else: + import Queue as que + +# +START_UP_CFG_FILE = '/etc/sonic/sfpdet_cfg.json' + +# platform path +PLATFORM_ROOT_PATH = '/usr/share/sonic/device' +PLATFORM_PLUGINS = 'plugins' +PLATFORM_SPECIFIC_MODULE_NAME = 'sfputil' +PLATFORM_SPECIFIC_CLASS_NAME = "SfpUtil" + +# Global platform-specific sfputil class instance +g_platform_sfputil = None + +# port config file path +PORT_MAP_FILE_NAME = 'port_map.ini.' +PORT_CFG_FILE_NAME = 'port_config.ini' +PORT_CFG_CLX_FILE_NAME = 'port_config.clx' + +# pre emphasis config filename extension +PRE_EMPHASIS_FILENAME_EXT = '.dsh' + +# clounix default pre-emphasis config file name +DEFAULT_PRE_EMPHASIS_OPT_CFG_FILE_NAME = 'clounix_opt' + PRE_EMPHASIS_FILENAME_EXT +DEFAULT_PRE_EMPHASIS_DAC_CFG_FILE_NAME = 'clounix_dac' + PRE_EMPHASIS_FILENAME_EXT + +""" +key:user logic lane num +vlaue:phy port num +""" +g_logical_lane_2_phy_port_info = dict() + +""" +key:user logic port name +vlaue:phy port num +""" +g_user_port_2_phy_port_info = dict() + +""" +key:clx_port=>(unit, port) +vlaue:[laneObj1, laneObj2] +""" +g_clx_port_2_logical_lane_info = dict() + +""" +key: logic lane +vlaue:clx_port=>(unit, port) +""" +g_logical_lane_2_clx_port_info = dict() + +""" +#global port info dict +#key:physical port +#value:{ + 'user_port':{name:{ + 'lanes':[logic_lane1, logic_lane2...], + 'alias':'', + 'clx_port':(unit, port) + 'max-speed':dd + 'media':'XRd'} + 'mdio':{(devad, addr):value}} + 'lane_list': [logic_lane1, logic_lane2] + 'present_sfp_info':{'Vendor Name':'', + 'Vendor PN':'', + 'Identifier':'', + 'Connector':'' + 'Complance Code'}, + 'pre_emphasis':{(sfp info key):{(unit, clx port, lane count, property): data) + 'usr_config_media':'opt'/'dac' + }} + } +""" +g_phy_port_info = dict() + + +def key_2_str(key): + return str(key) + + +KEY_PHY_PORT_INFO = key_2_str +KEY_PHY_PORT_INFO_V_USER_PORT = cfg_parser.KEY_PHY_PORT_INFO_V_USER_PORT +KEY_PHY_PORT_INFO_V_LANE_LIST = cfg_parser.KEY_PHY_PORT_INFO_V_LANE_LIST +KEY_PHY_PORT_INFO_V_USER_PORT_V = key_2_str +KEY_PHY_PORT_INFO_V_USER_PORT_V_ALIAS = cfg_parser.KEY_PHY_PORT_INFO_V_USER_PORT_V_ALIAS +KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES = cfg_parser.KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES +KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT = 'clx_port' +KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA = 'media' +KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO = 'mdio' +KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES_V = key_2_str +KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES_V_ETH_MACRO = 'eth_macro' +KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO = 'present_sfp_info' +KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_VENDOR_NAME = 'Vendor Name' +KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_VENDOR_PN = 'Vendor PN' +KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_IDENTIFIER = 'Identifier' +KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_CONNECTOR = 'Connector' +KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_COMPLIANCE_CODE = 'Specification compliance' +KEY_PHY_PORT_INFO_V_PRE_EMPHASIS = 'pre_emphasis' +KEY_PHY_PORT_INFO_V_USR_CFG_MEDIA = 'usr_config_media' +KEY_PHY_PORT_INFO_V_USR_CFG_DSH = 'usr_config_dsh' + +g_platform_name = '' +g_hwsku_name = '' + + +def _get_key_fuzzy_match_in_obj(key_str, obj): + """ + case and space ignore match + :param key_str: a string key + :param obj: iterable obj + :return: + """ + key_slice = str(key_str).lower().split(' ') + pt = re.compile(r'[\s\-_~.!@#%$&]*'.join(key_slice)) + + for key in obj: + if pt.search(key.lower()) is not None: + return key + return None + + +def _get_func_meta(): + import sys + try: + raise Exception() + except Exception: + exc_info = sys.exc_info() + trace_obj = exc_info[2] + trace_obj = trace_obj.tb_frame + up_frame = trace_obj.f_back + + return __name__ + '-->' + up_frame.f_code.co_name + '(line ' + str(up_frame.f_lineno) + ')' + + +def decro_timeit(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + worker_id = threading.current_thread().name + t0 = timeit.default_timer() + ret = func(*args, **kwargs) + t1 = timeit.default_timer() + g_sfp_logger.debug('of worker {} {} cost time: {}s\n'.format( + func.__name__, worker_id, t1 - t0)) + g_sfp_logger.debug('args: {}s\n'.format(list(args) + list(kwargs))) + + return ret + + return wrapper + + +g_sfp_logger = None + + +@decro_timeit +def _init_logging(logging_level=logging.INFO): + global g_sfp_logger + + logger_file_name = '/var/log/transceiver.log' + logger_fize_size = 10 + logger_file_num = 5 + + # init already, just return + if g_sfp_logger is None: + # create logger + logger_name = 'sfp_monitor_logger' + g_sfp_logger = logging.getLogger(logger_name) + g_sfp_logger.setLevel(logging_level) + + # create file handler + fh = logging.handlers.RotatingFileHandler(logger_file_name, mode='a+', maxBytes=logger_fize_size * 1024 * 1024, + backupCount=logger_file_num, delay=0) + fh.setLevel(logging_level) + + # create formatter + fmt = "%(asctime)-15s %(levelname)s %(filename)s[%(lineno)d]: %(funcName)s - %(message)s" + # datefmt = "%a %d %b %Y %H:%M:%S" + formatter = logging.Formatter(fmt) + + # add handler and formatter to _sys_logger + fh.setFormatter(formatter) + g_sfp_logger.addHandler(fh) + + +@decro_timeit +def _get_platform_and_hwsku(): + """ + get hardware sku + :return: (platform, hwsku) + """ + global g_platform_name + global g_hwsku_name + + if g_platform_name != '' and g_hwsku_name != '': + return g_platform_name, g_hwsku_name + + platform = "" + hwsku = "" + cmd = ['show', 'platform', 'summary'] + cmd_out = subprocess.check_output(cmd) + g_sfp_logger.debug(cmd_out) + pt = re.compile(r'^Platform:\s*([^\n\r\b]*).*HwSKU\s*:\s*([^\n\r\b]*)', re.I | re.M | re.S) + result = pt.search(cmd_out) + if result is not None: + g_sfp_logger.debug("type result:{}, result:{}\nmatch:{}\n".format(type(result), result, result.group())) + platform = result.group(1) + hwsku = result.group(2) + + if platform == "": + cmd = ['show', 'platform', 'syseeprom'] + cmd_out = subprocess.check_output(cmd) + g_sfp_logger.debug(cmd_out) + pt = re.compile(r'^Platform\s+Name\s+\w+\s+\d+\s+([^\n\r\b]*)', re.I | re.M | re.S) + result = pt.search(cmd_out) + if result is not None: + g_sfp_logger.debug("type result:{}, result:{}\nmatch:{}\n".format(type(result), result, result.group())) + platform = result.group(1) + + g_platform_name, g_hwsku_name = platform, hwsku + return platform, hwsku + + +def _get_path_to_platform_hwsku(): + """ + Returns path to platform and hwsku + :return: (path to platform, path to hwsku) + """ + # Get platform and hwsku + (platform, hwsku) = _get_platform_and_hwsku() + + # Load platform module from source + platform_path = "/".join([PLATFORM_ROOT_PATH, platform]) + hwsku_path = "/".join([platform_path, hwsku]) + + return platform_path, hwsku_path + + +@decro_timeit +def _load_platform_sfputil(): + """ + Loads platform specific sfputil module from source + :return: + """ + global g_platform_sfputil + + # Get platform and hwsku path + (platform_path, hwsku_path) = _get_path_to_platform_hwsku() + + try: + module_file = "/".join([platform_path, PLATFORM_PLUGINS, PLATFORM_SPECIFIC_MODULE_NAME + ".py"]) + module = imp.load_source(PLATFORM_SPECIFIC_MODULE_NAME, module_file) + except IOError as e: + g_sfp_logger.error("Failed to load platform module '%s': %s" % (PLATFORM_SPECIFIC_MODULE_NAME, str(e))) + return -1 + + try: + platform_sfputil_class = getattr(module, PLATFORM_SPECIFIC_CLASS_NAME) + g_platform_sfputil = platform_sfputil_class() + + # overwride _sfp_eeprom_present of baseclass for performance + def wrap_sfp_eeprom_present(sysfs_sfp_i2c_client_eeprompath, offset): + return True + + g_platform_sfputil._sfp_eeprom_present = wrap_sfp_eeprom_present + except AttributeError as e: + g_sfp_logger.error("Failed to instantiate '%s' class: %s\n" % (PLATFORM_SPECIFIC_CLASS_NAME, str(e))) + return -2 + + return 0 + + +def _get_path_to_port_config_file(): + """ + Returns path to port config file + :return: + """ + # Get platform and hwsku path + platform_path, hwsku_path = _get_path_to_platform_hwsku() + + # First check for the presence of the new 'port_config.ini' file + port_config_file_path = os.path.join(hwsku_path, PORT_CFG_FILE_NAME) + if os.path.isfile(port_config_file_path): + return port_config_file_path + else: + return '' + + +def _get_path_to_dflt_cfg_clx_file(): + """ + Returns path to default port config clx file + :return: + """ + platform_path, hwsku_path = _get_path_to_platform_hwsku() + clx_cfg_full_path = os.path.join(hwsku_path, PORT_CFG_CLX_FILE_NAME) + if os.path.isfile(clx_cfg_full_path): + return clx_cfg_full_path + else: + return '' + + +@decro_timeit +def _valid_global_data(): + global g_phy_port_info + + for phy_port, phy_port_value in g_phy_port_info.items(): + if KEY_PHY_PORT_INFO_V_USER_PORT not in phy_port_value \ + or KEY_PHY_PORT_INFO_V_PRE_EMPHASIS not in phy_port_value\ + or len(phy_port_value[phy_port_value]) == 0: + err_msg = "invalid phy_port_info[{}] = {}\n".format(phy_port, phy_port_value) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + +def _parse_pre_emphasis_info(dsh_file_path_list): + """ + parse pre-emphasis info from dsh file, if dsh_file_path is None then parse default clounix dsh file + :param dsh_file_path_list: + :return: + """ + global g_phy_port_info + + # generate pre-emphasis cmd for every phy port, like + # phy set pre-emphasis portlist=44 lane-cnt=4 property=c0 data=0x1c.1c.1c.1c + def _my_udf_lane_data_cmp(kx, ky): + if int(kx[0]) < int(ky[0]): + return -1 + elif int(kx[0]) == int(ky[0]): + return 0 + else: + return 1 + + for dsh_file_path in dsh_file_path_list: + parsed_dsh_info = cfg_parser.parse_clx_dsh(dsh_file_path) + dsh_file_name = os.path.split(dsh_file_path)[1] + + # init phy port pre-emphasis configuration + phy_port_emphasis_grouped_by_property = dict() + parsed_pre_emphasis = parsed_dsh_info[cfg_parser.KEY_PRE_EMPHASIS] + if cfg_parser.KEY_CPI_PORT_INFO in parsed_pre_emphasis: + parsed_pre_emphasis.pop(cfg_parser.KEY_CPI_PORT_INFO) + for (lane, prop), data in parsed_pre_emphasis.items(): + if lane not in g_logical_lane_2_phy_port_info: + g_sfp_logger.info("{}: lane {} is not in any phy port".format(_get_func_meta(), lane)) + continue + + key_phy_port = g_logical_lane_2_phy_port_info[lane] + if key_phy_port not in phy_port_emphasis_grouped_by_property: + phy_port_emphasis_grouped_by_property[key_phy_port] = dict() + value_phy_port = phy_port_emphasis_grouped_by_property[key_phy_port] + if prop not in value_phy_port: + value_phy_port.update({prop: [(lane, data)]}) + else: + value_phy_port[prop].append((lane, data)) + + for key_phy_port, value_prop_key_emphasis in phy_port_emphasis_grouped_by_property.items(): + cur_phy_port_pre_emphasis_dict = {dsh_file_name: {}} + for prop, lane_data_list in value_prop_key_emphasis.items(): + sort_lane_data_list = sorted(lane_data_list, key=functools.cmp_to_key(_my_udf_lane_data_cmp)) + lane = sort_lane_data_list[0][0] + unit = g_logical_lane_2_clx_port_info[lane][0] + clx_port = g_logical_lane_2_clx_port_info[lane][1] + lane_cnt = len(sort_lane_data_list) + pre_data = '0x' + '.'.join([d[1] for d in sort_lane_data_list]) + cur_phy_port_pre_emphasis_dict[dsh_file_name].update({(unit, clx_port, lane_cnt, prop): pre_data}) + + if KEY_PHY_PORT_INFO_V_PRE_EMPHASIS not in g_phy_port_info[key_phy_port]: + g_phy_port_info[key_phy_port][KEY_PHY_PORT_INFO_V_PRE_EMPHASIS] = dict() + g_phy_port_info[key_phy_port][KEY_PHY_PORT_INFO_V_PRE_EMPHASIS].update(cur_phy_port_pre_emphasis_dict) + + +@decro_timeit +def _parse_phy_port_info(): + """ + load sfputil module from device and init port phy2logic config mapping + :return: + """ + + global g_platform_sfputil + global g_logical_lane_2_phy_port_info + global g_user_port_2_phy_port_info + global g_clx_port_2_logical_lane_info + global g_logical_lane_2_clx_port_info + global g_phy_port_info + + # clear global database + g_platform_sfputil = None + g_logical_lane_2_phy_port_info.clear() + g_user_port_2_phy_port_info.clear() + g_clx_port_2_logical_lane_info.clear() + g_phy_port_info.clear() + + # load sfputil module + ret = _load_platform_sfputil() + if 0 != ret: + err_msg = "{}:fail({})\n".format(_get_func_meta(), ret) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # init phy port to sonic logical port mappnig of g_platform_sfputil + try: + port_config_file_path = _get_path_to_port_config_file() + g_platform_sfputil.read_porttab_mappings(port_config_file_path) + except Exception as e: + err_msg = "{}:read port config file fail({})".format(_get_func_meta(), str(e)) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # parse config.ini + try: + parsed_phy_port_info = cfg_parser.parse_port_config_ini(port_config_file_path) + if cfg_parser.KEY_PHY_PORT_INFO not in parsed_phy_port_info \ + or len(parsed_phy_port_info[cfg_parser.KEY_PHY_PORT_INFO]) == 0: + raise Exception(cfg_parser.KEY_PHY_PORT_INFO + ' is not in ' + parsed_phy_port_info.keys()) + if cfg_parser.KEY_LOGIC_LANE_2_PHY_PORT not in parsed_phy_port_info \ + or len(parsed_phy_port_info[cfg_parser.KEY_LOGIC_LANE_2_PHY_PORT]) == 0: + raise Exception(cfg_parser.KEY_LOGIC_LANE_2_PHY_PORT + ' is not in ' + parsed_phy_port_info.keys()) + if cfg_parser.KEY_USER_PORT_2_PHY_PORT not in parsed_phy_port_info \ + or len(parsed_phy_port_info[cfg_parser.KEY_USER_PORT_2_PHY_PORT]) == 0: + raise Exception(cfg_parser.KEY_USER_PORT_2_PHY_PORT + ' is not in ' + parsed_phy_port_info.keys()) + except Exception as e: + err_msg = "{}:parse {} fail({})".format(_get_func_meta(), port_config_file_path, e) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # update global phy port--logic user port -- lane database + g_phy_port_info.update(parsed_phy_port_info[cfg_parser.KEY_PHY_PORT_INFO]) + g_logical_lane_2_phy_port_info.update(parsed_phy_port_info[cfg_parser.KEY_LOGIC_LANE_2_PHY_PORT]) + g_user_port_2_phy_port_info.update(parsed_phy_port_info[cfg_parser.KEY_USER_PORT_2_PHY_PORT]) + + # parse config_clx + try: + parsed_dsh_info = cfg_parser.parse_clx_dsh(_get_path_to_dflt_cfg_clx_file()) + if cfg_parser.KEY_CLX_PORT_2_LOGIC_LANE not in parsed_dsh_info \ + or len(parsed_dsh_info[cfg_parser.KEY_CLX_PORT_2_LOGIC_LANE]) == 0: + raise Exception(cfg_parser.KEY_CLX_PORT_2_LOGIC_LANE + ' is not in ' + parsed_dsh_info.keys()) + if cfg_parser.KEY_LOGIC_LANE_2_CLX_PORT not in parsed_dsh_info \ + or len(parsed_dsh_info[cfg_parser.KEY_LOGIC_LANE_2_CLX_PORT]) == 0: + raise Exception(cfg_parser.KEY_LOGIC_LANE_2_CLX_PORT + ' is not in ' + parsed_dsh_info.keys()) + if cfg_parser.KEY_PRE_EMPHASIS not in parsed_dsh_info \ + or len(parsed_dsh_info[cfg_parser.KEY_PRE_EMPHASIS]) == 0: + raise Exception(cfg_parser.KEY_PRE_EMPHASIS + ' is not in ' + parsed_dsh_info.keys()) + except Exception as e: + err_msg = "{}:parse {} fail({})".format(_get_func_meta(), _get_path_to_dflt_cfg_clx_file(), e) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + g_clx_port_2_logical_lane_info.update(parsed_dsh_info[cfg_parser.KEY_CLX_PORT_2_LOGIC_LANE]) + g_logical_lane_2_clx_port_info.update(parsed_dsh_info[cfg_parser.KEY_LOGIC_LANE_2_CLX_PORT]) + + # fill clx port for every user port + for clx_port, clx_port_lanes in g_clx_port_2_logical_lane_info.items(): + # get clx port of every user port + clx_port_lane = clx_port_lanes[0] + phy_port = g_logical_lane_2_phy_port_info[clx_port_lane] + user_port_list = g_phy_port_info[phy_port][KEY_PHY_PORT_INFO_V_USER_PORT] + for user_port_name, user_port_value in user_port_list.items(): + if clx_port_lane in user_port_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES]: + user_port_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT] = clx_port + user_port_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA] =\ + parsed_dsh_info[cfg_parser.KEY_MEDIUM_TYPE][clx_port] + + +def decro_get_docker_exec(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + cmd = ['docker', 'exec', '-i', 'syncd', 'bash'] + popen_obj = subprocess.Popen(cmd, bufsize=1024 * 1024, stdin=subprocess.PIPE, stdout=subprocess.PIPE, + stderr=subprocess.PIPE) + exec_cmd = func(popen_obj, *args, **kwargs) + cmd_out = popen_obj.communicate() + if cmd_out[1] != '': + # cmd exec fail + err_msg = "cmd={} type cmd_out {}, cmd_out:{}\n".format(exec_cmd, type(cmd_out), cmd_out) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + else: + return exec_cmd, cmd_out[0] + + return wrapper + + +@decro_timeit +def _get_port_sfp_present_status(phy_port): + """ + get sfp present status of port + :param phy_port: + :return: True if present + """ + global g_platform_sfputil + + present = g_platform_sfputil.get_presence(phy_port) + + return present + + +def _get_phy_user_port_list(phy_port_value): + k = KEY_PHY_PORT_INFO_V_USER_PORT + if k not in phy_port_value: + g_sfp_logger.error("key {} is not in {}\n".format(k, phy_port_value)) + return {} + return phy_port_value[k] + + +@decro_timeit +def _get_port_sfp_info(phy_port): + """ + get eeprom sfp dict info from sfp moudule + :param phy_port:phy_port + :return: a sfp info dict + """ + global g_platform_sfputil + sfp_info_data = {} + + sfp_info_eeprom = g_platform_sfputil.get_eeprom_dict(phy_port) + if sfp_info_eeprom is None: + err_msg = "can't read sfp info of phy port {}\n".format(phy_port) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # vendor info, ref SFF-8024 Transceiver Management + if ('interface' not in sfp_info_eeprom) or ('data' not in sfp_info_eeprom['interface']): + err_msg = "unknown sfp info {} of phy port {}\n".format(sfp_info_data, phy_port) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + pat = re.compile(r'\s+') + sp_replace = '-' + sfp_info_eeprom_data = sfp_info_eeprom['interface']['data'] + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_VENDOR_NAME + fuzzy_key = _get_key_fuzzy_match_in_obj(k, sfp_info_eeprom_data) + if fuzzy_key is not None: + sfp_info_data[k] = pat.sub(sp_replace, sfp_info_eeprom_data[fuzzy_key]).lower() + else: + g_sfp_logger.info("unknown sfp vendor name {} of phy port {}\n".format(sfp_info_data, phy_port)) + sfp_info_data[k] = 'unknown' + + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_VENDOR_PN + fuzzy_key = _get_key_fuzzy_match_in_obj(k, sfp_info_eeprom_data) + if fuzzy_key is not None: + sfp_info_data[k] = pat.sub(sp_replace, sfp_info_eeprom_data[fuzzy_key]).lower() + else: + g_sfp_logger.info("unknown sfp vendor pn {} of phy port {}\n".format(sfp_info_data, phy_port)) + sfp_info_data[k] = 'unknown' + + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_IDENTIFIER + fuzzy_key = _get_key_fuzzy_match_in_obj(k, sfp_info_eeprom_data) + if fuzzy_key is not None: + sfp_info_data[k] = pat.sub('', sfp_info_eeprom_data[fuzzy_key]).lower() + else: + g_sfp_logger.info("unknown sfp identifier {} of phy port {}\n".format(sfp_info_data, phy_port)) + sfp_info_data[k] = 'unknown' + + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_CONNECTOR + fuzzy_key = _get_key_fuzzy_match_in_obj(k, sfp_info_eeprom_data) + if fuzzy_key is not None: + sfp_info_data[k] = pat.sub('', sfp_info_eeprom_data[fuzzy_key]).lower() + else: + g_sfp_logger.info("unknown sfp connector {} of phy port {}\n".format(sfp_info_data, phy_port)) + sfp_info_data[k] = 'unknown' + + # {'10/40G Ethernet Compliance Code': '40GBASE-CR4'} + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_COMPLIANCE_CODE + fuzzy_key = _get_key_fuzzy_match_in_obj(k, sfp_info_eeprom_data) + if fuzzy_key is not None: + sfp_info_data[k] = str(sfp_info_eeprom_data[fuzzy_key]).lower() + else: + g_sfp_logger.info("unknown sfp specification compliance {} of phy port {}\n".format(sfp_info_data, + phy_port)) + sfp_info_data[k] = 'unknown' + + return sfp_info_data + + +def _get_sfp_type(sfp_info): + """ + get sfp type from sfp eeprom info + :param sfp_info: + :return: 'dac'--copper; 'opt'--fiber + """ + + # default 'opt' + media_type = 'opt' + + dac_connector_dict = {'copperpigtail': 'dac', "noseparableconnector": 'dac'} + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_CONNECTOR + if k in sfp_info: + connector_value = str(sfp_info[k]).lower().replace(' ', '') + if connector_value in dac_connector_dict: + media_type = dac_connector_dict[connector_value] + + media_base = '' + k = KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO_COMPLIANCE_CODE + if k in sfp_info: + pt_str = r'.*-(?P[ceskl]r)(?P\d*)\s*' + pt = re.compile(pt_str, re.I) + result = pt.search(sfp_info[k]) + if result is not None: + media_base = result.group('media_base') + + # ?? + if media_base.lower() == 'cr' and media_type == 'opt': + media_type = 'dac' + elif media_base.lower() == 'sr' and media_type == 'dac': + media_type = 'opt' + + return media_type + + +def _set_phy_port_media_mdio(phy_port_value, media_type='opt'): + """ + set media and mdio to opt of given physical port + :param phy_port_value: + :param media_type: + :return: + """ + + if 'opt' == media_type: + media_config = 'sr' + mdio_config = {('0x1e', '0x2'): '0x8000'} + else: + media_config = 'cr' + mdio_config = {('0x1e', '0x2'): '0x0'} + + # get phy_port_info->value->user_port + k = KEY_PHY_PORT_INFO_V_USER_PORT + all_user_port_value = phy_port_value[k] + + for port in all_user_port_value: + k_lanes = KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES + port_lanes_cnt = len(all_user_port_value[port][k_lanes]) + if port_lanes_cnt == 1: + media_value = media_config + else: + media_value = media_config + str(port_lanes_cnt) + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA + all_user_port_value[port][k] = media_value + + # find current clx port and update mdio value + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO + all_user_port_value[port][k] = mdio_config + + +@decro_timeit +def _get_phy_port_admin_status(user_port_list): + """ + get port status of user logic ports + :param user_port_list: + :return: + """ + port_admin_status = dict() + + cmd = ['show', 'interface', 'status'] + pcmd = subprocess.Popen(cmd, bufsize=-1, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cmd_out = pcmd.communicate() + if cmd_out[1] != '': + # cmd exec fail + err_msg = "cmd={} cmd_out:\n {}\n".format(cmd, cmd_out) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # Interface Lanes Speed MTU Alias Oper Admin + # ----------- ------- ------- ----- ------------ ------ ------- + # Ethernet12 20 10G 9100 Ethernet13/1 up up + pt_str = r'''^\s* + (?P({}))\s+ #interface + (?P[\d,]+)\s+ #lanes + [\w/]+\s+ #speed + \d+\s+ #mtu + (?P[\w/]+)\s+ + [\w/]+\s+ + (?P[\w/]+) + .*$ + ''' + port_name_list = '{}'.format('|'.join(list(user_port_list))) + pt_str = pt_str.format(port_name_list) + pt = re.compile(pt_str, re.I | re.M | re.X) + result = pt.finditer(cmd_out[0]) + if result is None: + err_msg = "port {} cmd={} search fail cmd_out={}\n".format(list(user_port_list), cmd, cmd_out[0]) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + for r in result: + user_port = r.group('port_name') + status = r.group('admin') + clx_port = user_port_list[user_port][KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT] + port_admin_status[user_port] = (status, clx_port) + + return port_admin_status + + +@decro_timeit +@decro_get_docker_exec +def _admin_up_user_ports(popen_obj, port_admin_status): + exec_cmd = [] + + for user_port, (admin, (port_unit, port_index)) in port_admin_status.items(): + if str(admin).lower() == 'up'.lower(): + cmd_str = 'clx_diag port set property unit={} portlist={} admin=enable'.format( + port_unit, port_index) + popen_obj.stdin.write(cmd_str + '\n') + exec_cmd.append(cmd_str) + time.sleep(0.005) + + return exec_cmd + + +@decro_timeit +@decro_get_docker_exec +def _admin_down_user_ports(popen_obj, user_port_list): + exec_cmd = [] + + for port in user_port_list: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + clx_port = user_port_list[port][k] + cmd_str = 'clx_diag port set property unit={} portlist={} admin=disable'.format( + clx_port[0], clx_port[1]) + popen_obj.stdin.write(cmd_str + '\n') + exec_cmd.append(cmd_str) + time.sleep(0.005) + + return exec_cmd + + +def _get_phy_port_media(user_port_list): + media_config = dict() + + for p in user_port_list: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + clx_port = user_port_list[p][k] + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA + media = user_port_list[p][k] + media_config[clx_port] = media + + return media_config + + +def _get_phy_port_mdio(user_port_list): + mdio_config = dict() + + for p in user_port_list: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + clx_port = user_port_list[p][k] + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO + mdio = user_port_list[p][k] + mdio_config[clx_port] = mdio + + return mdio_config + + +# config order should be C2 -> CN1 -> C1 -> C0 +def _my_udf_pre_emphasis_cmp(kx, ky): + order_map = {'c2': 1, 'cn1': 2, 'c1': 3, 'c0': 4} + kx_priority = order_map[kx[3]] + ky_priority = order_map[ky[3]] + if kx_priority < ky_priority: + return -1 + elif kx_priority == ky_priority: + return 0 + else: + return 1 + + +@decro_timeit +def _get_port_running_config_exec_cmd(popen_obj, pre_emphasis_config, user_port_list): + exec_cmd = [] + + # show media + for port_name in user_port_list: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + unit, port = user_port_list[port_name][k] + cmd_str = 'clx_diag port show property unit={0} portlist={1}\n'.format( + unit, port) + popen_obj.stdin.write(cmd_str) + exec_cmd.append(cmd_str) + time.sleep(0.005) + + # show pre-emphasis + ordered_key_list = sorted(list(pre_emphasis_config), key=functools.cmp_to_key(_my_udf_pre_emphasis_cmp)) + for (unit, clx_port, lane_cnt, property_data) in ordered_key_list: + cmd_str = 'clx_diag phy show pre-emphasis unit={0} portlist={1}' \ + ' lane-cnt={2} property={3}'.format(unit, clx_port, lane_cnt, property_data) + '\n' + popen_obj.stdin.write(cmd_str) + exec_cmd.append(cmd_str) + time.sleep(0.005) + + return exec_cmd + + +@decro_timeit +def _get_port_running_config_mdio_exec_cmd(popen_obj, user_port_list): + exec_cmd = [] + + # show mdio + portlist_key_ol = sorted(list(user_port_list)) + for port_name in portlist_key_ol: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + unit, port = user_port_list[port_name][k] + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO + mdio_config_ol = sorted(list(user_port_list[port_name][k])) + for devad, addr in mdio_config_ol: + cmd_str = 'clx_diag phy show mdio unit={0} portlist={1}' \ + ' devad={2} addr={3}'.format(unit, port, devad, addr) + '\n' + popen_obj.stdin.write(cmd_str) + exec_cmd.append(cmd_str) + time.sleep(0.005) + + return exec_cmd + + +@decro_timeit +@decro_get_docker_exec +def _get_port_running_config_check_output(popen_obj, pre_emphasis_config, user_port_list): + return _get_port_running_config_exec_cmd(popen_obj, pre_emphasis_config, user_port_list) + + +@decro_timeit +@decro_get_docker_exec +def _get_port_running_config_mdio_check_output(popen_obj, user_port_list): + return _get_port_running_config_mdio_exec_cmd(popen_obj, user_port_list) + + +@decro_timeit +def _get_port_running_config(show_cmd_buf, pre_emphasis_config, user_port_list): + # get media + # port speed medium admin an eee fec flow-ctrl status loopback cut-through + # ---- ----- ------ ----- --- --- --- --------- ------ -------- ----------- + # 0 100g sr4 en dis dis dis dis down dis dis + running_media = dict() + portlist = [] + for port_name in user_port_list: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + portlist.append(user_port_list[port_name][k][1]) + pt_str = r'''^\s* + (?P{})\s+ #interface + (?P[^\s]+)\s+ #speed + (?P\w+)\s+ #media + (?P\w+)\s+ #admin + .*$ + ''' + pt_str = pt_str.format('|'.join(portlist)) + pt = re.compile(pt_str, re.I | re.M | re.X) + result = pt.finditer(show_cmd_buf) + for r in result: + k = ('0', r.group('port')) + running_media[k] = r.group('media') + + # get pre-emphasis + # clx_diag phy show pre-emphasis unit={0} portlist={1} + # lane-cnt={2} property={3}' + running_pre_emphasis = dict() + ordered_key_list = sorted(list(pre_emphasis_config), key=functools.cmp_to_key(_my_udf_pre_emphasis_cmp)) + pt = re.compile(r'^.*\s+data\s*=\s*(?P[\w.]+).*$', re.I | re.M) + running_pre_emphasis_ol = pt.findall(show_cmd_buf) + for i in range(0, len(running_pre_emphasis_ol)): + hl = [hex(y)[2:] for y in [int(x, 16) for x in running_pre_emphasis_ol[i].split('.')]] + uniform_data = '0x' + '.'.join(hl) + k = ordered_key_list[i] + running_pre_emphasis[k] = uniform_data + + return running_media, running_pre_emphasis + + +@decro_timeit +def _get_port_running_config_mdio(show_cmd_buf, user_port_list): + # get mdio + # admin@switch:~$ _clx_diag phy show mdio unit=0 portlist=0 devad=0x1E addr=0x2 + # port 000: data=0x0000 + running_mdio = dict() + + pt = re.compile(r'^.*\s+data\s*=\s*(?P[\w.]+).*$', re.I | re.M) + portlist_key_ol = sorted(list(user_port_list)) + rst_mdio_ol = pt.findall(show_cmd_buf) + for i in range(0, len(rst_mdio_ol)): + hl = [hex(y)[2:] for y in [int(x, 16) for x in rst_mdio_ol[i].split('.')]] + uniform_data = '0x' + '.'.join(hl) + port_name = portlist_key_ol[i] + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + unit, port = user_port_list[port_name][k] + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO + mdio_config_ol = sorted(list(user_port_list[port_name][k])) + k = (unit, port) + for devad, addr in mdio_config_ol: + if k in running_mdio: + running_mdio[k].update({(devad, addr): uniform_data}) + else: + running_mdio[k] = {(devad, addr): uniform_data} + + return running_mdio + + +def _cmp_running_media_pre_emphasis(running_media, + media_config, + running_mdio, + mdio_config, + running_pre_emphasis, + pre_emphasis_config): + media_changed = 0 + if operator.ne(running_media, media_config): + media_changed = 1 + + mdio_changed = 0 + if operator.ne(running_mdio, mdio_config): + mdio_changed = 1 + + pre_emphasis_changed = 0 + if operator.ne(running_pre_emphasis, pre_emphasis_config): + pre_emphasis_changed = 1 + + return media_changed, mdio_changed, pre_emphasis_changed + + +@decro_timeit +def _check_port_running_config( + media_config, + mdio_config, + pre_emphasis_config, + user_port_list): + exec_cmd, output = _get_port_running_config_check_output(pre_emphasis_config, user_port_list) + running_media, running_pre_emphasis = \ + _get_port_running_config(output, pre_emphasis_config, user_port_list) + + exec_cmd, output = _get_port_running_config_mdio_check_output(user_port_list) + running_mdio = \ + _get_port_running_config_mdio(output, user_port_list) + + if len(running_media) != len(media_config) \ + or len(running_mdio) != len(mdio_config) \ + or len(running_pre_emphasis) != len(pre_emphasis_config): + err_msg = "{}: geting running config failed\n".format(_get_func_meta()) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + media_changed, mdio_changed, pre_emphasis_changed = \ + _cmp_running_media_pre_emphasis(running_media, + media_config, + running_mdio, + mdio_config, + running_pre_emphasis, + pre_emphasis_config) + + return media_changed, mdio_changed, pre_emphasis_changed + + +@decro_timeit +def _set_port_running_media_pre_emphasis_exec_cmd( + popen_obj, + media_changed, + media_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list): + cmd_change = [] + + if 0 != media_changed: + for (unit, clx_port), media in media_config.items(): + # clx_diag port set property unit=0 portlist=26 medium-type=cr4 + cmd_str = 'clx_diag port set property unit={0} portlist={1} medium-type={2}'.format( + unit, clx_port, media) + popen_obj.stdin.write(cmd_str + '\n') + time.sleep(0.005) + cmd_change.append(cmd_str) + + if 0 != pre_emphasis_changed: + ordered_key_list = sorted(list(pre_emphasis_config), key=functools.cmp_to_key(_my_udf_pre_emphasis_cmp)) + for (unit, clx_port, lane_cnt, property_data) in ordered_key_list: + data = pre_emphasis_config[(unit, clx_port, lane_cnt, property_data)] + cmd_str = 'clx_diag phy set pre-emphasis unit={0} portlist={1} lane-cnt={2} ' \ + 'property={3} data={4}'.format(unit, clx_port, lane_cnt, property_data, data) + popen_obj.stdin.write(cmd_str + '\n') + time.sleep(0.005) + cmd_change.append(cmd_str) + + _get_port_running_config_exec_cmd(popen_obj, pre_emphasis_config, user_port_list) + + return cmd_change + + +@decro_timeit +def _set_port_running_mdio_exec_cmd( + popen_obj, + mdio_changed, + mdio_config, + user_port_list): + cmd_change = [] + + if 0 != mdio_changed: + for (unit, clx_port), mdio_values in mdio_config.items(): + # clx_diag phy show mdio portlist=0 devad=0x1E addr=0x2 data=0x8000 + for (devad, addr), v in mdio_values.items(): + cmd_str = 'clx_diag phy set mdio unit={0} portlist={1} devad={2} addr={3} data={4}'.format( + unit, clx_port, devad, addr, v) + popen_obj.stdin.write(cmd_str + '\n') + time.sleep(0.005) + cmd_change.append(cmd_str) + + _get_port_running_config_mdio_exec_cmd(popen_obj, user_port_list) + + return cmd_change + + +@decro_timeit +@decro_get_docker_exec +def _set_port_running_config_check_output( + popen_obj, + media_changed, + media_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list): + # set pre-emphasis in chip + exec_cmd = _set_port_running_media_pre_emphasis_exec_cmd(popen_obj, + media_changed, + media_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list) + + return exec_cmd + + +@decro_timeit +@decro_get_docker_exec +def _set_port_running_config_mdio_check_output( + popen_obj, + mdio_changed, + mdio_config, + user_port_list): + # set pre-emphasis in chip + exec_cmd = _set_port_running_mdio_exec_cmd(popen_obj, mdio_changed, mdio_config, user_port_list) + + return exec_cmd + + +@decro_timeit +def _set_port_running_config_hw(media_changed, + media_config, + mdio_changed, + mdio_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list): + # exec media and pre-emphasis config cmd + cmd_change_media_pre_emphasis, output = _set_port_running_config_check_output(media_changed, + media_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list) + running_media, running_pre_emphasis = _get_port_running_config(output, pre_emphasis_config, user_port_list) + + # exec mdio cmd + cmd_change_mdio, output = _set_port_running_config_mdio_check_output(mdio_changed, mdio_config, user_port_list) + running_mdio = _get_port_running_config_mdio(output, user_port_list) + + check_media_changed, check_mdio_changed, check_pre_emphasis_changed = \ + _cmp_running_media_pre_emphasis(running_media, + media_config, + running_mdio, + mdio_config, + running_pre_emphasis, + pre_emphasis_config) + cmd_change = cmd_change_media_pre_emphasis + cmd_change_mdio + ret = (cmd_change, check_media_changed, running_media, check_mdio_changed, running_mdio, + check_pre_emphasis_changed, running_pre_emphasis) + return ret + + +@decro_timeit +def _set_port_running_config(media_changed, + media_config, + mdio_changed, + mdio_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list): + + ret = _set_port_running_config_hw(media_changed, + media_config, + mdio_changed, + mdio_config, + pre_emphasis_changed, + pre_emphasis_config, + user_port_list) + cmd_change = ret[0] + check_media_changed = ret[1] + running_media = ret[2] + running_mdio = ret[4] + check_pre_emphasis_changed = ret[5] + running_pre_emphasis = ret[6] + if check_media_changed: + err_msg = "{}: change port {} media from {} to {} failed\n".format( + _get_func_meta(), user_port_list, running_media, media_config) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + if check_pre_emphasis_changed: + err_msg = "{}: change port {} pre-emphasis from {} to {} failed\n".format( + _get_func_meta(), user_port_list, running_pre_emphasis, pre_emphasis_config) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + if media_changed: + g_sfp_logger.critical("{}: change port {} media from {} to {} succeed\n".format( + _get_func_meta(), user_port_list, running_media, media_config)) + + if mdio_changed: + g_sfp_logger.critical("{}: change port {} mdio from {} to {} succeed\n".format( + _get_func_meta(), user_port_list, running_mdio, mdio_config)) + + if pre_emphasis_changed: + g_sfp_logger.critical("{}: change port {} pre-emphasis from {} to {} succeed\n".format( + _get_func_meta(), user_port_list, running_pre_emphasis, pre_emphasis_config)) + + return cmd_change + + +def update_phy_port_sfp_info(phy_port_value, sfp_info): + if len(phy_port_value) > 0: + phy_port_value[KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO] = sfp_info + + +@decro_timeit +def _update_phy_port_running_config(phy_port_value): + """ + update media and pre-emphasis config of phy port according to sfp_info + :param phy_port_value: + :return: + """ + user_port_list = _get_phy_user_port_list(phy_port_value) + + # get phy port media config + port_media_config = _get_phy_port_media(user_port_list) + + # get phy port mdio config + port_mdio_config = _get_phy_port_mdio(user_port_list) + + # get phy port sfp specific pre-emphasis config + phy_port_all_pre_emphasis = phy_port_value[KEY_PHY_PORT_INFO_V_PRE_EMPHASIS] + dsh_file = phy_port_value[KEY_PHY_PORT_INFO_V_USR_CFG_DSH] + if dsh_file is not None: + port_pre_emphasis_config = phy_port_all_pre_emphasis[dsh_file] + else: + first_user_port = user_port_list.values()[0] + media_type = first_user_port[KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA] + if 'sr' in media_type: + port_pre_emphasis_config = phy_port_all_pre_emphasis[DEFAULT_PRE_EMPHASIS_OPT_CFG_FILE_NAME] + else: + port_pre_emphasis_config = phy_port_all_pre_emphasis[DEFAULT_PRE_EMPHASIS_DAC_CFG_FILE_NAME] + + # check if running media and pre-emphasis in chip is need to set + media_changed, mdio_changed, pre_emphasis_changed = _check_port_running_config( + port_media_config, port_mdio_config, port_pre_emphasis_config, user_port_list) + + # running config in chip is correct, + if (media_changed == 0) and (mdio_changed == 0) and (pre_emphasis_changed == 0): + g_sfp_logger.critical('{}: port {} are correctly set already\n'.format(_get_func_meta(), + user_port_list)) + return [] + + # get and save user port admin status + user_port_admin_status = _get_phy_port_admin_status(user_port_list) + + # shutdown user ports + try: + _admin_down_user_ports(user_port_list) + except Exception as e: + _admin_up_user_ports(user_port_admin_status) + raise e + + # set port media of phy port + cmd_change = _set_port_running_config(media_changed, + port_media_config, + mdio_changed, + port_mdio_config, + pre_emphasis_changed, + port_pre_emphasis_config, + user_port_list) + + # recover admin status of logical ports + _admin_up_user_ports(user_port_admin_status) + + return cmd_change + + +@decro_timeit +def _is_sys_running(): + """ + check if swss docker is running + :return: True for running, false for not running + """ + + # check redis database to confirm it's running status + pcmd = subprocess.Popen(['redis-cli'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cmd_input = 'select 1\nHLEN HIDDEN\n' + cmd_out = pcmd.communicate(cmd_input) + if cmd_out[1] != '': + # cmd exec fail + err_msg = "{}: cmd={} fail: cmd_out:{}\n)".format(_get_func_meta(), cmd_input, cmd_out) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + pt = re.compile(r'OK.*(\d+).*', re.I | re.S) + result = pt.search(cmd_out[0]) + if result is None: + err_msg = "{}: cmd={} match fail: cmd_out:{}\n)".format(_get_func_meta(), cmd_input, cmd_out[0]) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # check if interface is initialized + cmd = ['show', 'interface', 'status'] + pcmd = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + cmd_out = pcmd.communicate() + if cmd_out[1] != '': + # cmd exec fail + err_msg = "{}: cmd={} fail: cmd_out:{}\n)".format(_get_func_meta(), cmd, cmd_out) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # Interface Lanes Speed MTU Alias Oper Admin + # ----------- ------- ------- ----- ------------ ------ ------- + # Ethernet12 20 10G 9100 Ethernet13/1 up up + pt_str = r'''^\s* + (?P\w+)\s+ #interface + (?P[\d,]+)\s+ #lanes + [\w/]+\s+ #speed + \d+\s+ #mtu + (?P[\w/]+)\s+ + (up|down)\s+ + (?P\w+)\s* + .*$ + ''' + pt = re.compile(pt_str, re.I | re.M | re.X) + result = pt.search(cmd_out[0]) + if result is None: + err_msg = "{}: cmd={} match fail: cmd_out:{}\n)".format(_get_func_meta(), cmd, cmd_out[0]) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + return True + + +def _get_pre_emphasis_change_cmd(cmd_queue): + """ + get all change cmd from msg queue with none block method + :param cmd_queue: + :return: + """ + all_change_cmd = [] + + if cmd_queue is None: + return all_change_cmd + + # do not block! + while not cmd_queue.empty(): + try: + change_cmd = cmd_queue.get(False) + all_change_cmd += change_cmd + except que.Empty: + pass + all_change_cmd = [cmd[len('clx_diag '):] for cmd in all_change_cmd] + return all_change_cmd + + +def _partion_start_up_config(clx_cfg_full_path): + worker_id = threading.current_thread() + + # split content of port_cfg.clx into n partions + pat_str = r'''^\s*port\s+set\s+property\s+ #property + ([\w]+\s*=\s*(?P\d+)\s+){0,1} #unit=0 + [\w]+\s*=\s*(?P[\d\-]+)\s+ #portlist=0 + medium-type\s*=\s*(?P\w+) #media-type=sr + .*$ + ''' + pat_pre_media = re.compile(pat_str, re.M | re.I | re.X) + + pat_str = r'''^\s*phy\s+set\s+mdio\s+ #phy set mdio + ([\w]+\s*=\s*(?P\d+)\s+){0,1} #unit=0 + [\w]+\s*=\s*(?P[\d\-]+)\s+ #portlist=0 + [\w\-]+\s*=\s*(?P\w+)\s+ #devad + [\w]+\s*=\s*(?P\w+)\s+ #addr + .*$ + ''' + pat_pre_mdio = re.compile(pat_str, re.M | re.I | re.X) + + pat_str = r'''^\s*phy\s+set\s+pre-emphasis\s+ #phy set pre-emphasis + ([\w]+\s*=\s*(?P\d+)\s+){0,1} #unit=0 + [\w]+\s*=\s*(?P[\d\-]+)\s+ #portlist=0 + [\w\-]+\s*=\s*(?P\d+)\s+ #lane-cnt=4 + [\w]+\s*=\s*(?P\w+)\s+ #property=cn1 + .*$ + ''' + pat_pre_emphasis = re.compile(pat_str, re.M | re.I | re.X) + + block_reg_dict = {'media': pat_pre_media, 'mdio': pat_pre_mdio, 'emphasis': pat_pre_emphasis} + block_index = {} + + cfg_file_block_buf = [] + with open(clx_cfg_full_path, mode='r') as clx_cfg_fp: + lines_buf = clx_cfg_fp.readlines() + cur_block_index = -1 + last_block_type = 'NULL' + for line in lines_buf: + if line.strip() == '' and last_block_type != 'NULL': + 'keep blank lines' + cur_block_type = last_block_type + else: + cur_block_type = 'other' + for k in block_reg_dict: + result = block_reg_dict[k].search(line) + if result is not None: + cur_block_type = k + break + + if (cur_block_type != last_block_type) and \ + ((cur_block_type not in block_reg_dict) or (cur_block_type not in block_index)): + cur_block_index += 1 + block_index[cur_block_type] = cur_block_index + cfg_file_block_buf.append(line) + else: + dst_index = block_index[cur_block_type] + cfg_file_block_buf[dst_index] += line + + last_block_type = cur_block_type + + for i in range(0, len(cfg_file_block_buf)): + g_sfp_logger.debug('worker {} split {} to {} parts part {} = {}\n'.format( + worker_id, clx_cfg_full_path, len(cfg_file_block_buf), i, cfg_file_block_buf[i])) + + return cfg_file_block_buf, block_index + + +def _update_media_cmd_of_startup_cfg(startup_cfg_buf, block_index, change_cmd_buf): + worker_id = threading.current_thread() + + pat_str = r'''^\s*port\s+set\s+property\s+ + (unit\s*=\s*(?P\d+)\s+){0,1} #unit=0 + [\w]+\s*=\s*(?P[\d\-]+)\s+ #portlist=0 + medium-type\s*=\s*(?P\w+) #media-type=sr + .*$ + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + for cmd in change_cmd_buf: + result = pat.search(cmd) + if result is None: + continue + unit = result.group('unit') + if unit is None: + unit = 0 + clx_port = result.group('portlist') + change_cmd_pat_str = r'''^\s*port\s+set\s+property\s+ + (unit\s*=\s*{}\s+){} #unit=0 + portlist\s*=\s*{}\s+ #portlist=0 + .*$ + ''' + change_cmd_pat_str = change_cmd_pat_str.format(unit, '{0,1}', clx_port) + change_cmd_buf_pat = re.compile(change_cmd_pat_str, re.M | re.I | re.X) + startup_cfg_buf[block_index], sub_cnt = change_cmd_buf_pat.subn(cmd, startup_cfg_buf[block_index]) + if sub_cnt == 0: + startup_cfg_buf[block_index] += cmd + '\n' + g_sfp_logger.debug('worker {} new cmd {} add in buffer\n'.format(worker_id, cmd)) + else: + g_sfp_logger.debug('worker {} cmd {} updated in buffer\n'.format(worker_id, cmd)) + + +def _update_mdio_cmd_of_startup_cfg(startup_cfg_buf, block_index, change_cmd_buf): + worker_id = threading.current_thread() + + pat_str = r'''^phy\s+set\s+mdio\s+ #phy set mdio + (unit\s*=\s*(?P\d+)\s+){0,1} #unit=0 + portlist\s*=\s*(?P[\d\-]+)\s+ #portlist=0 + devad\s*=\s*(?P\w+)\s+ #devad + addr\s*=\s*(?P\w+)\s+ #addr + .*$ + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + for cmd in change_cmd_buf: + result = pat.search(cmd) + if result is None: + continue + unit = result.group('unit') + if unit is None: + unit = 0 + clx_port = result.group('portlist') + devad = result.group('devad') + addr = result.group('addr') + + change_cmd_pat_str = r'''^phy\s+set\s+mdio\s+ #phy set mdio + (unit\s*=\s*{}\s+){} #unit=0 + portlist\s*=\s*{}\s+ #portlist=0 + devad\s*=\s*{}\s+ #devad + addr\s*=\s*{}\s+ #addr + .*$ + ''' + change_cmd_pat_str = change_cmd_pat_str.format(unit, '{0,1}', clx_port, devad, addr) + change_cmd_buf_pat = re.compile(change_cmd_pat_str, re.M | re.I | re.X) + startup_cfg_buf[block_index], sub_cnt = change_cmd_buf_pat.subn(cmd, startup_cfg_buf[block_index]) + if sub_cnt == 0: + startup_cfg_buf[block_index] += cmd + '\n' + g_sfp_logger.debug('worker {} new cmd {} add in buffer\n'.format(worker_id, cmd)) + else: + g_sfp_logger.debug('worker {} cmd {} updated in buffer\n'.format(worker_id, cmd)) + + +def _update_pre_emphasis_cmd_of_startup_cfg(startup_cfg_buf, block_index, change_cmd_buf): + worker_id = threading.current_thread() + + pat_str = r'''^phy\s+set\s+pre-emphasis\s+ #phy set pre-emphasis + (unit\s*=\s*(?P\d+)\s+){0,1} #unit=0 + portlist\s*=\s*(?P[\d\-]+)\s+ #portlist=0 + lane-cnt\s*=\s*(?P\d+)\s+ #lane-cnt=4 + property\s*=\s*(?P\w+)\s+ #property=cn1 + .*$ + ''' + pat = re.compile(pat_str, re.M | re.I | re.X) + for cmd in change_cmd_buf: + result = pat.search(cmd) + if result is None: + continue + unit = result.group('unit') + if unit is None: + unit = 0 + clx_port = result.group('portlist') + lane_cnt = result.group('lane_cnt') + property_data = result.group('property') + + change_cmd_pat_str = r'''^phy\s+set\s+pre-emphasis\s+ #phy set pre-emphasis + (unit\s*=\s*{}\s+){} #unit=0 + portlist\s*=\s*{}\s+ #portlist=0 + lane-cnt\s*=\s*{}\s+ #lane-cnt=4 + property\s*=\s*{}\s+ #property=cn1 + .*$ + ''' + change_cmd_pat_str = change_cmd_pat_str.format(unit, '{0,1}', clx_port, lane_cnt, property_data) + change_cmd_buf_pat = re.compile(change_cmd_pat_str, re.M | re.I | re.X) + startup_cfg_buf[block_index], sub_cnt = change_cmd_buf_pat.subn(cmd, startup_cfg_buf[block_index]) + if sub_cnt == 0: + startup_cfg_buf[block_index] += cmd + '\n' + g_sfp_logger.debug('worker {} new cmd {} add in buffer\n'.format(worker_id, cmd)) + else: + g_sfp_logger.debug('worker {} cmd {} updated in buffer\n'.format(worker_id, cmd)) + + +@decro_timeit +def _auto_save_startup_config(cmd_queue): + """ + auto save change cmd in port_cfg.clx + :param cmd_queue: + :return: + """ + + worker_id = threading.current_thread() + + # get all change cmds from msg queue + change_cmd = _get_pre_emphasis_change_cmd(cmd_queue) + if len(change_cmd) == 0: + return 0 + + platform_path, hwsku_path = _get_path_to_platform_hwsku() + clx_cfg_full_path = os.path.join(hwsku_path, PORT_CFG_CLX_FILE_NAME) + clx_cfg_exist = os.path.isfile(clx_cfg_full_path) + clx_cfg_backup_full_path = clx_cfg_full_path + '.backup' + backup_exist = os.path.isfile(clx_cfg_backup_full_path) + + # check port_cfg.clx and backup file + if (clx_cfg_exist, backup_exist) == (True, True): + # perfect + g_sfp_logger.debug('worker {} {} and {} are exist.\n'.format( + worker_id, clx_cfg_full_path, clx_cfg_backup_full_path)) + elif (clx_cfg_exist, backup_exist) == (True, False): + # backup port_config.clx + shutil.copy(clx_cfg_full_path, clx_cfg_backup_full_path) + g_sfp_logger.critical('worker {} backup {} to {}\n'.format( + worker_id, clx_cfg_full_path, clx_cfg_backup_full_path)) + elif (clx_cfg_exist, backup_exist) == (False, True): + # restore port_config.clx from backup file + shutil.copy(clx_cfg_backup_full_path, clx_cfg_full_path) + g_sfp_logger.warning('worker {} {} is restored from {}\n'.format( + worker_id, clx_cfg_full_path, clx_cfg_backup_full_path)) + elif (clx_cfg_exist, backup_exist) == (False, False): + # port_config.clx and backup are lost + g_sfp_logger.error('worker {} {} is lost\n'.format(worker_id, clx_cfg_full_path)) + return -1 + + # update cmd in cfg file buf + cfg_file_block_buf, block_index = _partion_start_up_config(clx_cfg_full_path) + if 'media' not in block_index: + media_block_index = len(cfg_file_block_buf) - 1 + else: + media_block_index = block_index['media'] + _update_media_cmd_of_startup_cfg(cfg_file_block_buf, media_block_index, change_cmd) + + if 'mdio' not in block_index: + mdio_block_index = len(cfg_file_block_buf) - 1 + else: + mdio_block_index = block_index['mdio'] + _update_mdio_cmd_of_startup_cfg(cfg_file_block_buf, mdio_block_index, change_cmd) + + if 'emphasis' not in block_index: + pre_emphasis_block_index = len(cfg_file_block_buf) - 1 + else: + pre_emphasis_block_index = block_index['emphasis'] + _update_pre_emphasis_cmd_of_startup_cfg(cfg_file_block_buf, pre_emphasis_block_index, change_cmd) + + # write new config to port_cfg.clx + clx_cfg_tmp_full_path = clx_cfg_full_path + '.tmp' + updated_cfg_content = '' + for buf_block in cfg_file_block_buf: + updated_cfg_content += buf_block + + with open(clx_cfg_tmp_full_path, mode='w') as clx_cfg_tmp_fp: + clx_cfg_tmp_fp.write(updated_cfg_content) + g_sfp_logger.debug('worker {} write cmd to {}\n'.format(worker_id, clx_cfg_tmp_full_path)) + + os.remove(clx_cfg_full_path) + g_sfp_logger.debug('worker {} remove {}\n'.format(worker_id, clx_cfg_full_path)) + + os.rename(clx_cfg_tmp_full_path, clx_cfg_full_path) + g_sfp_logger.debug('worker {} rename {} to {}\n'.format(worker_id, clx_cfg_tmp_full_path, clx_cfg_full_path)) + + g_sfp_logger.critical('worker {} save cmd to {}\n'.format(worker_id, clx_cfg_full_path)) + + +@decro_timeit +def _detect_config_by_port(phy_port_key, phy_port_value): + """ + + :param phy_port_key: + :param phy_port_value: + :return: + """ + if KEY_PHY_PORT_INFO_V_USER_PORT not in phy_port_value: + err_msg = "{} : phy port has no user port {}\n".format(_get_func_meta(), phy_port_key) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + # check sfp info and set media and mdio config for phy port + user_cfg_meida = phy_port_value[KEY_PHY_PORT_INFO_V_USR_CFG_MEDIA] + if user_cfg_meida is None: + # 0 means sfp is not present, we can't auto detect + if 0 == len(phy_port_value[KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO]): + return [] + + # set media and pre-emphasis of port + cmd_change = _update_phy_port_running_config(phy_port_value) + + return cmd_change + + +@decro_timeit +def _detect_config_by_phy_port(port_port_info_dict, msg_queue, debug_verbose): + """ + check sfp type and set pre-emphasis of all ports + :param port_port_info_dict: + :param msg_queue: + :param debug_verbose: + :return: + """ + + all_changed_cmd = [] + for phy_port_key, phy_port_value in port_port_info_dict.items(): + + # show port config detail info before detect and config + if debug_verbose > 0: + print('Running settings before detecting:') + _show_phy_port({phy_port_key: phy_port_value}, debug_verbose) + + port_changed_cmd = _detect_config_by_port(phy_port_key, phy_port_value) + all_changed_cmd += port_changed_cmd + + # show port config detail info after detect and config + if debug_verbose > 0: + print('Running settings after detecting:') + _show_phy_port({phy_port_key: phy_port_value}, debug_verbose) + + # send sfp change cmd to auto save dynamic pre-emphasis config + if (msg_queue is not None) and (len(all_changed_cmd) != 0): + msg_queue.put(all_changed_cmd) + g_sfp_logger.info('{}: change pre-emphasis:\n{}\n'.format(_get_func_meta(), all_changed_cmd)) + + +def _parse_user_port_list(user_port_input=None): + """ + parse user input user port group string like 'Ethernet1-4,Ethernet7' to a + phycial port list [0, 1, 2], + :param user_port_input: + :return: + """ + + phy_port_list = [] + if user_port_input is None: + phy_port_list = sorted(g_phy_port_info.keys(), key=int) + return phy_port_list + + user_port_list = [] + for port_num_seg in [s.strip() for s in user_port_input.split(',')]: + seg_list = port_num_seg.split('-') + if len(seg_list) == 2: + user_port_list.extend(['Ethernet' + str(p) for p in range(int(seg_list[0].strip('Ethernet')), + int(seg_list[1].strip('Ethernet')) + 1)]) + elif len(seg_list) == 1: + user_port_list.append('Ethernet' + seg_list[0].strip('Ethernet')) + else: + err_msg = "{}: invalid user port name {}\n".format( + _get_func_meta(), '-'.join(seg_list)) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + for user_port in user_port_list: + if user_port not in g_user_port_2_phy_port_info: + err_msg = "{}: invalid user port {}\n".format(_get_func_meta(), user_port) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + phy_port = g_user_port_2_phy_port_info[user_port] + if phy_port not in g_phy_port_info: + err_msg = "{}: invalid user port {} has no valid phy port mapping entry {}\n".format( + _get_func_meta(), user_port, phy_port) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + phy_port_list.append(phy_port) + + return phy_port_list + + +def _parse_user_config_media_list(user_config_media): + """ + get user config media list ['dac', 'opt'] from user input string 'dac,opt' + :param user_config_media: + :return: + """ + if user_config_media is None: + target_user_config_media_list = [None] + else: + target_user_config_media_list = [m for m in user_config_media.split(',')] + for media in target_user_config_media_list: + if media != 'opt' and media != 'dac': + err_msg = "{}: invalid user port media type {}, it should be opt or dac\n".format( + _get_func_meta(), media) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + return target_user_config_media_list + + +@decro_timeit +def get_dsh_file_list(): + """ + list all valid dsh file in device dir for user + :return: + """ + dsh_file_list = [] + + platform_path, hwsku_path = _get_path_to_platform_hwsku() + for f in os.listdir(hwsku_path): + if os.path.splitext(f)[1] == '.dsh': + dsh_file_list.append(f) + + return dsh_file_list + + +def _parse_dsh_file_list(dsh_file_input=None): + """ + parse user input dsh file string like oem_a.dsh,oem_b.dsh to a list [oem_a.dsh, oem_b.dsh] + :param dsh_file_input: + :return: + """ + + if dsh_file_input is None: + dsh_file_list = [None] + else: + dsh_file_list = [f.strip() for f in dsh_file_input.split(',')] + all_dsh_file = get_dsh_file_list() + diff_dsh_file = set(dsh_file_list) - set(all_dsh_file) + if len(diff_dsh_file) != 0: + err_msg = "{}: {} does not exist, all valid dsh files are {}\n".format( + _get_func_meta(), diff_dsh_file, all_dsh_file) + g_sfp_logger.error(err_msg) + raise Exception(err_msg) + + return dsh_file_list + + +def _get_dsh_file_path(): + target_dsh_file = [] + + dsh_file_name_list = get_dsh_file_list() + platform_path, hwsku_path = _get_path_to_platform_hwsku() + for dsh_file in dsh_file_name_list: + target_dsh_file.append(os.path.join(hwsku_path, dsh_file)) + + return target_dsh_file + + +@decro_timeit +def _init_phy_port_info(): + # first of all, we need to init logging + _init_logging() + + # _is_sys_running() + # init global phy port info database form config.ini and port_config.clx + _parse_phy_port_info() + + # get dsh file + target_dsh_file_list = _get_dsh_file_path() + _parse_pre_emphasis_info(target_dsh_file_list) + + # set default media and mdio for port + for phy_port, phy_port_value in g_phy_port_info.items(): + first_user_port = phy_port_value[KEY_PHY_PORT_INFO_V_USER_PORT].itervalues().next() + media_hw = first_user_port[KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA] + media = 'opt' if 'sr' in media_hw else 'dac' + _set_phy_port_media_mdio(phy_port_value, media) + + +@decro_timeit +def _init_detect_config_port(phy_port_media_dsh): + """ + get phy port configuration of user port and valid dsh file + :phy_port_media_dsh:{'0': (None, 'clounix_dac.dsh')} + :return: + """ + target_phy_port_info_dict = collections.OrderedDict() + + # get target_phy_port_info_dict from key list + for phy_port, (media, dsh) in phy_port_media_dsh.items(): + target_phy_port_info_dict[phy_port] = g_phy_port_info[phy_port] + target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_USR_CFG_MEDIA] = media + target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_USR_CFG_DSH] = dsh + user_port_name_list = ','.join(target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_USER_PORT].keys()) + if target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_USR_CFG_MEDIA] is None: + if KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO not in target_phy_port_info_dict[phy_port]: + present = _get_port_sfp_present_status(int(phy_port)) + if not present: + target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO] = {} + print('No transceiver is plugged into {}'.format(user_port_name_list)) + else: + target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO] = \ + _get_port_sfp_info(int(phy_port)) + sfp_info = target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_PRESENT_SFP_INFO] + media_type = _get_sfp_type(sfp_info) + if len(sfp_info) != 0: + print('{} transceiver is plugged into port {}'.format( + 'opt(fiber)'.title() if media_type == 'opt' else 'dac(copper)'.title(), + user_port_name_list)) + else: + media_type = target_phy_port_info_dict[phy_port][KEY_PHY_PORT_INFO_V_USR_CFG_MEDIA] + print('{} transceiver is configured by user for port {}'.format( + 'opt(fiber)'.title() if media_type == 'opt' else 'dac(copper)'.title(), + user_port_name_list)) + + _set_phy_port_media_mdio(target_phy_port_info_dict[phy_port], media_type) + + return target_phy_port_info_dict + + +@decro_timeit +@decro_get_docker_exec +def _get_port_raw_allin1_running_config(popen_obj, phy_port_value): + """ + get raw running media, pre-emphasis, mdio config of given user port list, + this func depend on _init_phy_info, so call call _init_phy_info and then call + this func + :param popen_obj: + :param phy_port_value: + :return: + """ + exec_cmd = [] + + phy_port_lane_cnt = len(phy_port_value[KEY_PHY_PORT_INFO_V_LANE_LIST]) + user_port_list = phy_port_value[KEY_PHY_PORT_INFO_V_USER_PORT] + portlist_key_ol = sorted(list(user_port_list)) + for user_port in portlist_key_ol: + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT + unit, clx_port = user_port_list[user_port][k] + + # display media type of port + cmd_str = 'clx_diag port show property unit={0} portlist={1}\n'.format( + unit, clx_port) + popen_obj.stdin.write(cmd_str) + exec_cmd.append(cmd_str) + time.sleep(0.005) + + # display pre-emphasis + if portlist_key_ol.index(user_port) == 0: + prop_list = ['c2', 'cn1', 'c1', 'c0'] + for prop in prop_list: + cmd_str = 'clx_diag phy show pre-emphasis unit={0} portlist={1}' \ + ' lane-cnt={2} property={3}'.format(unit, clx_port, phy_port_lane_cnt, prop) + '\n' + popen_obj.stdin.write(cmd_str) + exec_cmd.append(cmd_str) + time.sleep(0.005) + + # show mdio + k = KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO + mdio_config_ol = sorted(list(user_port_list[user_port][k])) + for dev, add in mdio_config_ol: + cmd_str = 'clx_diag phy show mdio unit={0} portlist={1}' \ + ' devad={2} addr={3}'.format(unit, clx_port, dev, add) + '\n' + popen_obj.stdin.write(cmd_str) + exec_cmd.append(cmd_str) + time.sleep(0.005) + + return exec_cmd + + +def _get_port_allin1_running_config(phy_port_value): + """ + get hw running meida, pre-emphasis and mdio etc. + :param phy_port_value: + :return: + """ + # get runnming settings of phy + # exec_cmd: + # clx_diag port show property unit=0 portlist=0 + # clx_diag phy show pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c2 + # clx_diag phy show pre-emphasis unit=0 portlist=0 lane-cnt=4 property=cn1 + # clx_diag phy show pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c1 + # clx_diag phy show pre-emphasis unit=0 portlist=0 lane-cnt=4 property=c0 + # clx_diag phy show mdio unit=0 portlist=0 devad=0x1e addr=0x2 + # output_line_list = output.split('\n'): + # ['port speed medium admin an eee fec flow-ctrl status loopback cut-through', + # '---- ----- ------ ----- --- --- --- --------- ------ -------- -----------', + # '0 100g sr4 en dis dis dis dis down dis dis ', + # 'port 000: data=0x0002.0002.0002.0002', + # 'port 000: data=0x0001.0001.0001.0001', + # 'port 000: data=0x0007.0007.0007.0007', + # 'port 000: data=0x001a.001a.001a.001a', + # 'port 000: data=0x8001', ''] + exec_cmd, output = _get_port_raw_allin1_running_config(phy_port_value) + output_line_list = [l for l in output.split('\n') if len(l) > 0] + if len(output_line_list) < 8: + print('Get media failed: \nExec_cmd:\n{}\nCmd_output:\n{}\n'.format(exec_cmd, output)) + return + + media = [v for v in output_line_list[2].split(' ') if len(v) > 0][2].strip() + idx = output_line_list[3].find('0x') + pre_emphasis = 'c2:{}\n'.format(output_line_list[3][idx:]) + pre_emphasis += 'cn1:{}\n'.format(output_line_list[4][idx:]) + pre_emphasis += 'c1:{}\n'.format(output_line_list[5][idx:]) + pre_emphasis += 'c0:{}\n'.format(output_line_list[6][idx:]) + mdio = '{}\n'.format(output_line_list[7][idx:]) + + return {KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA: media, + KEY_PHY_PORT_INFO_V_PRE_EMPHASIS: pre_emphasis, + KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO: mdio} + + +@decro_timeit +def _show_phy_port(phy_port_info, debug_verbose): + """ + This func depends on _init_phy_port_info. + Display phy port to user port mapping, and running meida, pre-emphasis + and mdio setting in chip of given ports. + :param phy_port_info: + :param debug_verbose: + :return: + """ + fmt = 'simple' + table = [] + headers = ['Logic port', 'Media'] + if debug_verbose > 0: + headers.extend(['Pre-emphasis', 'MDIO', 'Phy port', 'Lanes', 'CLX Port']) + + for phy_port, phy_port_value in phy_port_info.items(): + for user_port, user_port_info_value in phy_port_value[KEY_PHY_PORT_INFO_V_USER_PORT].items(): + if debug_verbose == 0: + media = user_port_info_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA] + media = 'dac(copper)' if 'cr' in media else 'opt(fiber)' + port_row = [user_port, media] + else: + running_config = _get_port_allin1_running_config(phy_port_value) + media = running_config[KEY_PHY_PORT_INFO_V_USER_PORT_V_MEDIA] + media = 'dac(copper)' if 'cr' in media else 'opt(fiber)' + pre_emphasis = running_config[KEY_PHY_PORT_INFO_V_PRE_EMPHASIS] + mdio = running_config[KEY_PHY_PORT_INFO_V_USER_PORT_V_MDIO] + port_row = [user_port, media, pre_emphasis, mdio, phy_port, + user_port_info_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_LANES], + user_port_info_value[KEY_PHY_PORT_INFO_V_USER_PORT_V_CLX_PORT]] + table.append(port_row) + + print(tabulate(table, headers, tablefmt=fmt)) + + +@decro_timeit +def _convert_user_port_to_phy_port(user_port_str=None, + user_config_media_str=None, + dsh_file_str=None): + """ + get phy port tuple from user input + :param user_port_str: + :param user_config_media_str: + :param dsh_file_str: + :return:{'0': (None, None), '1': ('opt', None)] + """ + + # get phy port dict from user input list string like Ethernet1-4;Ethernet8 + phy_port_list = _parse_user_port_list(user_port_str) + + # broadcast last user config media value to all other ports, and update into g_phy_port_info + media_list = _parse_user_config_media_list(user_config_media_str) + media_list.extend(list(itertools.repeat(media_list[-1], len(phy_port_list) - len(media_list)))) + + # parse user input dsh file list + dsh_list = _parse_dsh_file_list(dsh_file_str) + dsh_list.extend(list(itertools.repeat(dsh_list[-1], len(phy_port_list) - len(dsh_list)))) + + target_phy_port_media_dsh = collections.OrderedDict() + for port in phy_port_list: + idx = phy_port_list.index(port) + target_phy_port_media_dsh.update({port: (media_list[idx], dsh_list[idx])}) + + return target_phy_port_media_dsh + + +@decro_timeit +def show_user_port(user_port_str=None, debug_verbose=0): + """ + This func depends on _init_phy_port_info. + Display phy port to user port mapping, and running meida, pre-emphasis + and mdio setting in chip of given ports. + Phy port num: 0 + Lanes: + User port list: + Ethernet0: + Lanes: + Clx port: + Transceiver info: + Transceiver media type: opt + Running media,pre-emphasis and mdio setting: + ... + :param user_port_str: + :param debug_verbose + :return: + """ + + _init_phy_port_info() + + target_phy_port_info = collections.OrderedDict() + phy_port_media_dsh = _convert_user_port_to_phy_port(user_port_str) + for phy_port in phy_port_media_dsh: + target_phy_port_info[phy_port] = g_phy_port_info[phy_port] + + _show_phy_port(target_phy_port_info, debug_verbose) + + +@decro_timeit +def show_dsh_file(): + """ + display dsh files list + :return: + """ + _init_logging() + + dsh_file_list = get_dsh_file_list() + for f in dsh_file_list: + print(f) + + +@decro_timeit +def detect_config_by_phy_port(config_file=START_UP_CFG_FILE, + debug_verbose=0): + """ + detect and get sfp Transceiver info, then config pre-emphasis, media, mdio value in chip, + this func should be called when system is booting up + :param phy_port_media_dsh:{'0': (None, 'clounix_dac.dsh')} + :param debug_verbose: + :return: + """ + with open(config_file, 'r') as fp: + phy_port_media_dsh = json.load(fp, object_pairs_hook=collections.OrderedDict) + + _init_phy_port_info() + + # get target phy port dict + phy_port_info_dict = _init_detect_config_port(phy_port_media_dsh) + + # detect and config phy ports + msg_queue = que.Queue() + _detect_config_by_phy_port(phy_port_info_dict, msg_queue, debug_verbose) + + # auto save or log port dynamic pre-emphasis config to port_config.clx + _auto_save_startup_config(msg_queue) + + +@decro_timeit +def detect_config_by_user_port(user_port_str=None, + user_config_media_str=None, + dsh_file_str=None, + debug_verbose=0): + """ + detect and get sfp Transceiver info, then config pre-emphasis, media, mdio value in chip + :param user_port_str: + :param user_config_media_str: + :param dsh_file_str: + :param debug_verbose: + :return: + """ + + _init_phy_port_info() + + # get target phy port dict + phy_port_media_dsh = _convert_user_port_to_phy_port(user_port_str, user_config_media_str, dsh_file_str) + + # get target phy port dict + phy_port_info_dict = _init_detect_config_port(phy_port_media_dsh) + + # detect and config phy ports + msg_queue = que.Queue() + _detect_config_by_phy_port(phy_port_info_dict, msg_queue, debug_verbose) + + # auto save or log port dynamic pre-emphasis config to port_config.clx + _auto_save_startup_config(msg_queue) + + # if detect port succeed, update start up config(START_UP_CFG_FILE) + cfg = collections.OrderedDict() + with open(START_UP_CFG_FILE, mode='a+') as fp: + try: + cfg = json.load(fp, object_pairs_hook=collections.OrderedDict) + except ValueError as e: + err_msg = "{}: {} in {}\n".format(_get_func_meta(), e, START_UP_CFG_FILE) + g_sfp_logger.info(err_msg) + pass + cfg.update(phy_port_media_dsh) + with open(START_UP_CFG_FILE, mode='w') as fp: + json.dump(cfg, fp, indent=4) + + +# This is our main entrypoint - the main 'sfputil' command +@click.group() +def cli(): + """sfpdet - Command line utility for configuring port's MEDIA""" + + if os.geteuid() != 0: + print "Root privileges are required for this operation" + sys.exit(1) + # Make sure user has reboot after use port-breakout cli! + if get_state_db(PORT_CFG_STATE_NAME) == STATE_MODIFIED: + click.echo('Please reboot after port breakout!!') + sys.exit(1) + + +# 'show' subgroup +@cli.group() +def show(): + """Display status of SFP transceivers""" + pass + + +# 'media' subcommand +@show.command() +@click.option('-p', '--port', metavar='', help="Port list like Ethernet1;Ethernet3-5") +@click.option('-v', '--verbose', metavar='', count=True, default=0, help="Detail debug info") +def media(port=None, verbose=0): + """Display all port info include physical, logical, clx port, transceiver and running media, + pre-emphasis and mdio phy setting info""" + try: + show_user_port(port, verbose) + except Exception as e: + print(traceback.format_exc(e)) + + + +# 'dshfile' subcommand +@show.command() +def dshfile(): + """Display available dsh files for transceiver.""" + try: + show_dsh_file() + except Exception as e: + print(traceback.format_exc(e)) + + +def get_portcfg_state(self): + return get_state_db(PORT_CFG_STATE_NAME) + +# 'config' subcommand +@cli.command() +@click.option('-p', '--port', metavar='', help="Port list like Ethernet1,Ethernet3-5") +@click.option('-m', '--media', metavar='', help="Transceiver media type `opt` or `dac`") +@click.option('-d', '--dsh', metavar='', help=".dsh file list like vendor_an_opt.dsh,vendor_an_dac.dsh") +@click.option('-v', '--verbose', metavar='', count=True, help="Detail debug info") +def config(port=None, media=None, dsh=None, verbose=0): + """Auto detect and configure pre-emphasis, media and mdio for port.""" + try: + detect_config_by_user_port(port, media, dsh, verbose) + except Exception as e: + print(traceback.format_exc(e)) + +@cli.command('recover-from-json') +@click.pass_context +@click.option('-j', '--json-file', + metavar='', + required=False, + default=START_UP_CFG_FILE) +@click.option('-v', '--verbose', metavar='', count=True, help="detail debug info") +def recover_from_json(ctx, json_file, verbose=0): + """Recover port MEDIA configuration from json.""" + detect_config_by_phy_port(json_file, verbose) + + +if __name__ == '__main__': + cli() diff --git a/platform/clounix/clx-utils/clounix-utils/setup.py b/platform/clounix/clx-utils/clounix-utils/setup.py new file mode 100644 index 000000000000..89923b6934eb --- /dev/null +++ b/platform/clounix/clx-utils/clounix-utils/setup.py @@ -0,0 +1,30 @@ +from setuptools import setup +import glob + +setup( + name='clx-utils', + version='0.1', + description='Clounix Command-line utilities for SONiC', + license='Apache 2.0', + maintainer='Zhiqian.Wu', + maintainer_email='Zhiqian.Wu@clounixinc.com', + author='Clounix Team', + packages=[ + 'port_breakout', + ], + package_data={ + 'port_breakout': ['port_config.clx.j2'] + }, + scripts=[ + 'scripts/sfpdet' + ], + data_files=[ + ('/etc/bash_completion.d', glob.glob('bash_completion.d/*')), + ], + entry_points={ + 'console_scripts': [ + 'port-breakout=port_breakout.main:cli' + ] + }, + keywords='sonic SONiC utilities command line cli CLI clounix' +) diff --git a/platform/clounix/docker-ptf-clounix.mk b/platform/clounix/docker-ptf-clounix.mk new file mode 100644 index 000000000000..7595a2678bd0 --- /dev/null +++ b/platform/clounix/docker-ptf-clounix.mk @@ -0,0 +1,7 @@ +# docker image for docker-ptf-clounix + +DOCKER_PTF_CLOUNIX = docker-ptf-clounix.gz +$(DOCKER_PTF_CLOUNIX)_PATH = $(DOCKERS_PATH)/docker-ptf +$(DOCKER_PTF_CLOUNIX)_DEPENDS += $(LIBTHRIFT) $(PYTHON_THRIFT) $(PTF) $(PYTHON_SAITHRIFT) +$(DOCKER_PTF_CLOUNIX)_LOAD_DOCKERS += $(DOCKER_BASE_BUSTER) +SONIC_DOCKER_IMAGES += $(DOCKER_PTF_CLOUNIX) diff --git a/platform/clounix/docker-saiserver-clounix.mk b/platform/clounix/docker-saiserver-clounix.mk new file mode 100644 index 000000000000..beb4a48a0208 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix.mk @@ -0,0 +1,22 @@ +# docker image for clounix saiserver + +DOCKER_SAISERVER_CLOUNIX_STEM = docker-saiserver-clounix +DOCKER_SAISERVER_CLOUNIX = $(DOCKER_SAISERVER_CLOUNIX_STEM).gz +$(DOCKER_SAISERVER_CLOUNIX)_PATH = $(PLATFORM_PATH)/docker-saiserver-clounix +$(DOCKER_SAISERVER_CLOUNIX)_DEPENDS += $(SAISERVER) $(CLOUNIX_SAI_DEV) +$(DOCKER_SAISERVER_CLOUNIX)_FILES += $(DSSERVE) +$(DOCKER_SAISERVER_CLOUNIX)_LOAD_DOCKERS += $(DOCKER_CONFIG_ENGINE_BUSTER) +$(DOCKER_SAISERVER_CLOUNIX)_DBG_IMAGE_PACKAGES = $($(DOCKER_CONFIG_ENGINE_BUSTER)_DBG_IMAGE_PACKAGES) + + +SONIC_DOCKER_IMAGES += $(DOCKER_SAISERVER_CLOUNIX) +DOCKER_SAISERVER_CLOUNIX_DBG = $(DOCKER_SAISERVER_CLOUNIX_STEM)-$(DBG_IMAGE_MARK).gz +SONIC_DOCKER_DBG_IMAGES += $(DOCKER_SAISERVER_CLOUNIX_DBG) + +$(DOCKER_SAISERVER_CLOUNIX)_CONTAINER_NAME = saiserver +$(DOCKER_SAISERVER_CLOUNIX)_BASE_IMAGE_FILES += clx_ipython:/usr/bin/clx_ipython +$(DOCKER_SAISERVER_CLOUNIX)_RUN_OPT += --net=host --privileged -t +$(DOCKER_SAISERVER_CLOUNIX)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf +$(DOCKER_SAISERVER_CLOUNIX)_RUN_OPT += -v /var/run/docker-saiserver:/var/run/sswsyncd +$(DOCKER_SAISERVER_CLOUNIX)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro +$(DOCKER_SAISERVER_CLOUNIX)_RUN_OPT += -v /host/warmboot:/var/warmboot diff --git a/platform/clounix/docker-saiserver-clounix/Dockerfile.j2 b/platform/clounix/docker-saiserver-clounix/Dockerfile.j2 new file mode 100644 index 000000000000..f9be48490700 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/Dockerfile.j2 @@ -0,0 +1,72 @@ +FROM docker-config-engine-buster + +ARG docker_container_name +COPY ["base_image_files/rsyslog.conf", "/etc/rsyslog.conf"] +RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf + +## Make apt-get non-interactive +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update && apt-get install libboost-atomic1.71.0 + +COPY \ +{% for deb in docker_saiserver_clounix_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } ; \ +{% for deb in docker_saiserver_clounix_debs.split(' ') -%} +dpkg_apt debs/{{ deb }}{{'; '}} +{%- endfor %} + +## TODO: add kmod into Depends +RUN apt-get install -yf kmod \ +# Install IPython, jupyter-console packages + jupyter-console \ + jupyter-client + +COPY ["files/dsserve", "start.sh", "/usr/bin/"] +COPY ["clx_diag", "/usr/bin/"] +COPY ["warm-verifier", "/usr/bin/"] +RUN chmod +x /usr/bin/clx_diag /usr/bin/warm-verifier /usr/bin/dsserve + +COPY ["base_image_files", "/etc/clounix"] +COPY ["base_image_files/port_config.ini", "/etc/sai/portmap.ini"] +COPY ["profile.ini", "/etc/sai/"] + +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] + +# IPython kernel config +COPY ["ipython_config.json", "/etc/ipython/"] + +# Install IPython Cling Kernel +#{%- if INCLUDE_CLING_KERNEL == "yes" %} +#COPY ["install_clingkernel.sh", "/usr/bin/"] +#COPY ["cling-0.9-buster.tar", "/opt/"] +#RUN /usr/bin/install_clingkernel.sh + +RUN apt-get install -y build-essential \ + libc-dev \ + libc6-dev-i386 + +ENV CLING_OPTS "-I/usr/include/sai/ \ + -I/usr/include/clounix/ \ + -I/usr/include/clx_system/clx_sdk/include \ + -I/usr/include/clx_system/clx_sdk/include/cdb \ + -I/usr/include/clx_system/clx_sdk/include/osal \ + -I/usr/include/clx_system/clx_sdk/src/inc \ + -DCLX_EN_HOST_64_BIT_LITTLE_ENDIAN \ + -DCLX_EN_LITTLE_ENDIAN \ + -DCLX_EN_COMPILER_SUPPORT_LONG_LONG \ + -DCLX_LINUX_USER_MODE \ + -DCLX_SDK \ + -DCLX_EN_NETIF \ + -DCLX_EN_64BIT_ADDR " +#{%- endif %} + +## Clean up +RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y +RUN rm -rf /debs + +ENTRYPOINT ["/usr/local/bin/supervisord"] diff --git a/platform/clounix/docker-saiserver-clounix/base_image_files/00README.md b/platform/clounix/docker-saiserver-clounix/base_image_files/00README.md new file mode 100644 index 000000000000..d61c1ad2134d --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/base_image_files/00README.md @@ -0,0 +1,21 @@ +Clounix 12.8T Leo Link Recover +============================= + +### For 400G(8x50g PAM4) DAC cable like between FP1 and FP2 +```shell +lightning_linkup-dac.sh portlist=0,8 400g cr8 8 + +### For 400G(8x50g PAM4) AOC cable like between FP1 and FP2 +```shell +lightning_linkup-aoc.sh portlist=0,8 400g lr8 8 +``` + +### For 100G(4x25g NRZ) DAC cable like between FP1 and FP2 +```shell +lightning_linkup-dac.sh portlist=0,4 100g cr4 4 +``` + +### For 100G(4x25g NRZ) AOC cable like between FP1 and FP2 +```shell +lightning_linkup-aoc.sh portlist=0,4 100g lr4 4 +``` diff --git a/platform/clounix/docker-saiserver-clounix/base_image_files/clx_diag b/platform/clounix/docker-saiserver-clounix/base_image_files/clx_diag new file mode 100755 index 000000000000..8d47ca16c614 Binary files /dev/null and b/platform/clounix/docker-saiserver-clounix/base_image_files/clx_diag differ diff --git a/platform/clounix/docker-saiserver-clounix/base_image_files/clx_ipython b/platform/clounix/docker-saiserver-clounix/base_image_files/clx_ipython new file mode 100755 index 000000000000..818832f3b952 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/base_image_files/clx_ipython @@ -0,0 +1,5 @@ +#!/bin/bash + +docker exec -it syncd clx_diag ipy +docker exec -it syncd jupyter-console --existing clx-ipython-shell.json + diff --git a/platform/clounix/docker-saiserver-clounix/base_image_files/rsyslog.conf b/platform/clounix/docker-saiserver-clounix/base_image_files/rsyslog.conf new file mode 100644 index 000000000000..eb700bd53c2f --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/base_image_files/rsyslog.conf @@ -0,0 +1,76 @@ +# +# /etc/rsyslog.conf Configuration file for rsyslog. +# +# For more information see +# /usr/share/doc/rsyslog-doc/html/rsyslog_conf.html + + +################# +#### MODULES #### +################# + +$ModLoad imuxsock # provides support for local system logging + +# +# Set a rate limit on messages from the container +# +$SystemLogRateLimitInterval 0 +$SystemLogRateLimitBurst 0 + +#$ModLoad imklog # provides kernel logging support +#$ModLoad immark # provides --MARK-- message capability + +# provides UDP syslog reception +#$ModLoad imudp +#$UDPServerRun 514 + +# provides TCP syslog reception +#$ModLoad imtcp +#$InputTCPServerRun 514 + + +########################### +#### GLOBAL DIRECTIVES #### +########################### + +# Set remote syslog server +template (name="ForwardFormatInContainer" type="string" string="<%PRI%>%TIMESTAMP:::date-rfc3339% %HOSTNAME% %syslogtag%%msg:::sp-if-no-1st-sp%%msg%") +*.* action(type="omfwd" target="127.0.0.1" port="514" protocol="udp" Template="ForwardFormatInContainer") + +# +# Use traditional timestamp format. +# To enable high precision timestamps, comment out the following line. +# +#$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat + +# Define a custom template +$template SONiCFileFormat,"%TIMESTAMP%.%timestamp:::date-subseconds% %HOSTNAME% %syslogseverity-text:::uppercase% %syslogtag%%msg:::sp-if-no-1st-sp%%msg:::drop-last-lf%\n" +$ActionFileDefaultTemplate SONiCFileFormat + +# +# Set the default permissions for all log files. +# +$FileOwner root +$FileGroup adm +$FileCreateMode 0640 +$DirCreateMode 0755 +$Umask 0022 + +# +# Where to place spool and state files +# +$WorkDirectory /var/spool/rsyslog + +# +# Include all config files in /etc/rsyslog.d/ +# +$IncludeConfig /etc/rsyslog.d/*.conf + +# +# Suppress duplicate messages and report "message repeated n times" +# +$RepeatedMsgReduction on + +############### +#### RULES #### +############### diff --git a/platform/clounix/docker-saiserver-clounix/base_image_files/sai.profile b/platform/clounix/docker-saiserver-clounix/base_image_files/sai.profile new file mode 100755 index 000000000000..c0ad916b5ca6 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/base_image_files/sai.profile @@ -0,0 +1,2 @@ +SAI_INIT_CONFIG_FILE=/usr/share/sonic/platform/lightning-fn8656_bnf.cfg +SAI_DSH_CONFIG_FILE=/usr/share/sonic/hwsku/lightning-fn8656_bnf.dsh diff --git a/platform/clounix/docker-saiserver-clounix/base_image_files/warm-verifier b/platform/clounix/docker-saiserver-clounix/base_image_files/warm-verifier new file mode 100755 index 000000000000..7c8535811c49 Binary files /dev/null and b/platform/clounix/docker-saiserver-clounix/base_image_files/warm-verifier differ diff --git a/platform/clounix/docker-saiserver-clounix/clx_diag b/platform/clounix/docker-saiserver-clounix/clx_diag new file mode 100755 index 000000000000..8d47ca16c614 Binary files /dev/null and b/platform/clounix/docker-saiserver-clounix/clx_diag differ diff --git a/platform/clounix/docker-saiserver-clounix/install_clingkernel.sh b/platform/clounix/docker-saiserver-clounix/install_clingkernel.sh new file mode 100755 index 000000000000..5596647dcee1 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/install_clingkernel.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +echo "Install IPython ClingKernel ..." +cd /opt/ && tar xvf cling-0.9-buster.tar -C /usr/ && \ +cd /usr/share/cling/tools/Jupyter/kernel/ && \ +pip3 install -e . && \ +jupyter-kernelspec install cling-cpp11 && \ +jupyter-kernelspec install cling-cpp14 && \ +jupyter-kernelspec install cling-cpp1z && \ +jupyter-kernelspec install cling-cpp17 && \ +jupyter-kernelspec list && \ +rm -rf /opt/cling-0.9-buster.tar +echo "Done" diff --git a/platform/clounix/docker-saiserver-clounix/ipython_config.json b/platform/clounix/docker-saiserver-clounix/ipython_config.json new file mode 100644 index 000000000000..ce59391ab3bd --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/ipython_config.json @@ -0,0 +1,6 @@ +{ + "ConnectionFileMixin": { + "connection_file" : "clx-ipython-shell.json" + } +} + diff --git a/platform/clounix/docker-saiserver-clounix/profile.ini b/platform/clounix/docker-saiserver-clounix/profile.ini new file mode 100644 index 000000000000..64497a1759f8 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/profile.ini @@ -0,0 +1,5 @@ +SAI_INIT_CONFIG_FILE=/etc/clounix/lightning-fn8656_bnf.cfg +SAI_DSH_CONFIG_FILE=/etc/clounix/lightning-fn8656_bnf.dsh +SAI_WARM_BOOT_READ_FILE=/var/cache/sai_warmboot.bin +SAI_WARM_BOOT_WRITE_FILE=/var/cache/sai_warmboot.bin +SAI_BOOT_TYPE=0 diff --git a/platform/clounix/docker-saiserver-clounix/start.sh b/platform/clounix/docker-saiserver-clounix/start.sh new file mode 100755 index 000000000000..09cc0ddb5416 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/start.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +rm -f /var/run/rsyslogd.pid + +supervisorctl start rsyslogd + +supervisorctl start saiserver diff --git a/platform/clounix/docker-saiserver-clounix/supervisord.conf b/platform/clounix/docker-saiserver-clounix/supervisord.conf new file mode 100644 index 000000000000..c53ad2e0b187 --- /dev/null +++ b/platform/clounix/docker-saiserver-clounix/supervisord.conf @@ -0,0 +1,32 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[eventlistener:dependent-startup] +command=python3 -m supervisord_dependent_startup +autostart=true +autorestart=unexpected +startretries=0 +exitcodes=0,3 +events=PROCESS_STATE +buffer_size=25 + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n -iNONE +priority=1 +autostart=false +autorestart=unexpected +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true + +[program:saiserver] +command=/usr/bin/saiserver -p /etc/sai/profile.ini -f /etc/sai/portmap.ini +priority=2 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running diff --git a/platform/clounix/docker-saiserver-clounix/warm-verifier b/platform/clounix/docker-saiserver-clounix/warm-verifier new file mode 100755 index 000000000000..7c8535811c49 Binary files /dev/null and b/platform/clounix/docker-saiserver-clounix/warm-verifier differ diff --git a/platform/clounix/docker-syncd-clounix-rpc.dep b/platform/clounix/docker-syncd-clounix-rpc.dep new file mode 100644 index 000000000000..70d3d06ad61c --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc.dep @@ -0,0 +1,9 @@ +#DPKG FRK +DPATH := $($(DOCKER_SYNCD_CLOUNIX_RPC)_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/docker-syncd-clounix-rpc.mk platform/clounix/docker-syncd-clounix-rpc.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(DPATH)) + +$(DOCKER_SYNCD_BASE)_CACHE_MODE := GIT_CONTENT_SHA +$(DOCKER_SYNCD_BASE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(DOCKER_SYNCD_BASE)_DEP_FILES := $(DEP_FILES) diff --git a/platform/clounix/docker-syncd-clounix-rpc.mk b/platform/clounix/docker-syncd-clounix-rpc.mk new file mode 100644 index 000000000000..2e1ef4b2dc1b --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc.mk @@ -0,0 +1,27 @@ +# docker image for clounix syncd with rpc + +DOCKER_SYNCD_CLOUNIX_RPC = docker-syncd-clounix-rpc.gz +$(DOCKER_SYNCD_CLOUNIX_RPC)_PATH = $(PLATFORM_PATH)/docker-syncd-clounix-rpc +$(DOCKER_SYNCD_CLOUNIX_RPC)_DEPENDS += $(SYNCD_RPC) $(LIBTHRIFT) $(PTF) +$(DOCKER_SYNCD_CLOUNIX_RPC)_DBG_DEPENDS += $(SYNCD_RPC_DBG) \ + $(LIBSWSSCOMMON_DBG) \ + $(LIBSAIMETADATA_DBG) \ + $(LIBSAIREDIS_DBG) +$(DOCKER_SYNCD_CLOUNIX_RPC)_FILES += $(DSSERVE) +$(DOCKER_SYNCD_CLOUNIX_RPC)_LOAD_DOCKERS += $(DOCKER_SYNCD_BASE) +SONIC_DOCKER_IMAGES += $(DOCKER_SYNCD_CLOUNIX_RPC) +ifeq ($(ENABLE_SYNCD_RPC),y) +SONIC_INSTALL_DOCKER_IMAGES += $(DOCKER_SYNCD_CLOUNIX_RPC) +endif + +$(DOCKER_SYNCD_CLOUNIX_RPC)_CONTAINER_NAME = syncd + +$(DOCKER_SYNCD_CLOUNIX_RPC)_BASE_IMAGE_FILES += clx_diag:/usr/bin/clx_diag +$(DOCKER_SYNCD_CLOUNIX_RPC)_BASE_IMAGE_FILES += clx_ipython:/usr/bin/clx_ipython +$(DOCKER_SYNCD_CLOUNIX_RPC)_BASE_IMAGE_FILES += clx_icling:/usr/bin/clx_icling + +$(DOCKER_SYNCD_CLOUNIX_RPC)_RUN_OPT += --net=host --privileged -t +$(DOCKER_SYNCD_CLOUNIX_RPC)_RUN_OPT += -v /host/machine.conf:/etc/machine.conf +$(DOCKER_SYNCD_CLOUNIX_RPC)_RUN_OPT += -v /host/warmboot:/var/warmboot +$(DOCKER_SYNCD_CLOUNIX_RPC)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd +$(DOCKER_SYNCD_CLOUNIX_RPC)_RUN_OPT += -v /etc/sonic:/etc/sonic:ro diff --git a/platform/clounix/docker-syncd-clounix-rpc/Dockerfile.j2 b/platform/clounix/docker-syncd-clounix-rpc/Dockerfile.j2 new file mode 100644 index 000000000000..f1ecf58a2aa1 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc/Dockerfile.j2 @@ -0,0 +1,59 @@ +FROM docker-syncd-clounix + +## Make apt-get non-interactive +ENV DEBIAN_FRONTEND=noninteractive + +COPY \ +{% for deb in docker_syncd_clounix_rpc_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +RUN apt-get purge -y syncd + +## Pre-install the fundamental packages +RUN apt-get update \ + && apt-get -y install \ + net-tools \ + python-pip \ + python-setuptools \ + build-essential \ + libssl-dev \ + libffi-dev \ + python-dev \ + wget \ + cmake \ + libqt5core5a \ + libqt5network5 \ + libboost-atomic1.71.0 + +RUN dpkg_apt() { [ -f $1 ] && { dpkg -i $1 || apt-get -y install -f; } || return 1; } ; \ +{% for deb in docker_syncd_clounix_rpc_debs.split(' ') -%} +dpkg_apt debs/{{ deb }}{{'; '}} +{%- endfor %} + +RUN wget https://github.com/nanomsg/nanomsg/archive/1.0.0.tar.gz \ + && tar xvfz 1.0.0.tar.gz \ + && cd nanomsg-1.0.0 \ + && mkdir -p build \ + && cmake . \ + && make install \ + && ldconfig \ + && cd .. \ + && rm -fr nanomsg-1.0.0 \ + && rm -f 1.0.0.tar.gz \ + && pip2 install cffi==1.7.0 \ + && pip2 install --upgrade cffi==1.7.0 \ + && pip2 install wheel \ + && pip2 install nnpy \ + && mkdir -p /opt \ + && cd /opt \ + && git clone https://github.com/p4lang/ptf.git \ + && cp ptf/ptf_nn/ptf_nn_agent.py ./ \ + && apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y \ + && rm -rf /root/deps + +RUN chmod +x /usr/bin/clx_diag /usr/bin/warm-verifier /usr/bin/dsserve +COPY ["ptf_nn_agent.conf", "/etc/supervisor/conf.d/"] + +ENTRYPOINT ["/usr/local/bin/supervisord"] diff --git a/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_diag b/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_diag new file mode 100755 index 000000000000..d6fd648de5c6 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_diag @@ -0,0 +1,3 @@ +#!/bin/bash + +docker exec -i syncd clx_diag "$@" diff --git a/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_icling b/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_icling new file mode 100755 index 000000000000..994343866af0 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_icling @@ -0,0 +1,5 @@ +#!/bin/bash + +docker exec -it syncd clx_diag icling +docker exec -it syncd jupyter-console --existing clx-icling-shell.json + diff --git a/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_ipython b/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_ipython new file mode 100755 index 000000000000..818832f3b952 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc/base_image_files/clx_ipython @@ -0,0 +1,5 @@ +#!/bin/bash + +docker exec -it syncd clx_diag ipy +docker exec -it syncd jupyter-console --existing clx-ipython-shell.json + diff --git a/platform/clounix/docker-syncd-clounix-rpc/ptf_nn_agent.conf b/platform/clounix/docker-syncd-clounix-rpc/ptf_nn_agent.conf new file mode 100644 index 000000000000..fa1ed0eb1622 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix-rpc/ptf_nn_agent.conf @@ -0,0 +1,10 @@ +[program:ptf_nn_agent] +command=/usr/bin/python /opt/ptf_nn_agent.py --device-socket 1@tcp://0.0.0.0:10900 -i 1-3@Ethernet12 --set-iface-rcv-buffer=109430400 +process_name=ptf_nn_agent +stdout_logfile=/tmp/ptf_nn_agent.out.log +stderr_logfile=/tmp/ptf_nn_agent.err.log +redirect_stderr=false +autostart=true +autorestart=true +startsecs=1 +numprocs=1 diff --git a/platform/clounix/docker-syncd-clounix.dep b/platform/clounix/docker-syncd-clounix.dep new file mode 100644 index 000000000000..e26d484e8c89 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix.dep @@ -0,0 +1,11 @@ +#DPKG FRK +DPATH := $($(DOCKER_SYNCD_BASE)_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/docker-syncd-clounix.mk platform/clounix/docker-syncd-clounix.dep platform/clounix/sai.mk +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(DPATH)) + +$(DOCKER_SYNCD_BASE)_CACHE_MODE := GIT_CONTENT_SHA +$(DOCKER_SYNCD_BASE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(DOCKER_SYNCD_BASE)_DEP_FILES := $(DEP_FILES) + +$(eval $(call add_dbg_docker,$(DOCKER_SYNCD_BASE),$(DOCKER_SYNCD_BASE_DBG))) diff --git a/platform/clounix/docker-syncd-clounix.mk b/platform/clounix/docker-syncd-clounix.mk new file mode 100644 index 000000000000..0c2e249567f1 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix.mk @@ -0,0 +1,19 @@ +# docker image for clounix syncd + +DOCKER_SYNCD_PLATFORM_CODE = clounix +include $(PLATFORM_PATH)/../template/docker-syncd-base.mk + +$(DOCKER_SYNCD_BASE)_DEPENDS += $(SYNCD) $(CLOUNIX_SAI_DEV) $(CLOUNIX_WARM_VERIFIER) +$(DOCKER_SYNCD_BASE)_FILES = $(DSSERVE) + +$(DOCKER_SYNCD_BASE)_DBG_DEPENDS += $(SYNCD_DBG) \ + $(LIBSWSSCOMMON_DBG) \ + $(LIBSAIMETADATA_DBG) \ + $(LIBSAIREDIS_DBG) + +$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /host/warmboot:/var/warmboot +$(DOCKER_SYNCD_BASE)_RUN_OPT += -v /var/run/docker-syncd:/var/run/sswsyncd + +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += clx_diag:/usr/bin/clx_diag +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += clx_ipython:/usr/bin/clx_ipython +$(DOCKER_SYNCD_BASE)_BASE_IMAGE_FILES += clx_icling:/usr/bin/clx_icling diff --git a/platform/clounix/docker-syncd-clounix/Dockerfile.j2 b/platform/clounix/docker-syncd-clounix/Dockerfile.j2 new file mode 100755 index 000000000000..5d722ba3a888 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/Dockerfile.j2 @@ -0,0 +1,76 @@ +{% from "dockers/dockerfile-macros.j2" import install_debian_packages %} +FROM docker-config-engine-buster + +ARG docker_container_name +RUN [ -f /etc/rsyslog.conf ] && sed -ri "s/%syslogtag%/$docker_container_name#%syslogtag%/;" /etc/rsyslog.conf + +## Make apt-get non-interactive +ENV DEBIAN_FRONTEND=noninteractive + +RUN apt-get update + +COPY \ +{% for deb in docker_syncd_clounix_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +COPY \ +{% for deb in docker_syncd_clounix_pydebs.split(' ') -%} +python-debs/{{ deb }}{{' '}} +{%- endfor -%} +debs/ + +RUN apt-get install -y libxml2 \ +# Install IPython, jupyter-console packages + jupyter-console \ + jupyter-client + +RUN dpkg -i \ +{% for deb in docker_syncd_clounix_debs.split(' ') -%} +debs/{{ deb }}{{' '}} +{%- endfor %} + +##RUN dpkg -i \ +##{% for deb in docker_syncd_clounix_pydebs.split(' ') -%} +##debs/{{ deb }}{{' '}} +##{%- endfor %} + +COPY ["files/dsserve", "/usr/bin/"] +RUN chmod +x /usr/bin/dsserve + +COPY ["supervisord.conf", "/etc/supervisor/conf.d/"] +COPY ["files/supervisor-proc-exit-listener", "/usr/bin"] +COPY ["critical_processes", "/etc/supervisor/"] + +# IPython kernel config +COPY ["ipython_config.json", "/etc/ipython/"] + +# Install IPython Cling Kernel +#COPY ["install_clingkernel.sh", "/usr/bin/"] +#COPY ["cling-0.9-buster.tar", "/opt/"] +#RUN /usr/bin/install_clingkernel.sh + +RUN apt-get install -y build-essential \ + libc-dev \ + libc6-dev-i386 + +ENV CLING_OPTS "-I/usr/include/sai/ \ + -I/usr/include/clounix/ \ + -I/usr/include/clx_system/clx_sdk/include \ + -I/usr/include/clx_system/clx_sdk/include/cdb \ + -I/usr/include/clx_system/clx_sdk/include/osal \ + -I/usr/include/clx_system/clx_sdk/src/inc \ + -DCLX_EN_HOST_64_BIT_LITTLE_ENDIAN \ + -DCLX_EN_LITTLE_ENDIAN \ + -DCLX_EN_COMPILER_SUPPORT_LONG_LONG \ + -DCLX_LINUX_USER_MODE \ + -DCLX_SDK \ + -DCLX_EN_NETIF \ + -DCLX_EN_64BIT_ADDR " + +## Clean up +RUN apt-get clean -y; apt-get autoclean -y; apt-get autoremove -y +RUN rm -rf /debs + +ENTRYPOINT ["/usr/local/bin/supervisord"] diff --git a/platform/clounix/docker-syncd-clounix/base_image_files/clx_diag b/platform/clounix/docker-syncd-clounix/base_image_files/clx_diag new file mode 100755 index 000000000000..d6fd648de5c6 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/base_image_files/clx_diag @@ -0,0 +1,3 @@ +#!/bin/bash + +docker exec -i syncd clx_diag "$@" diff --git a/platform/clounix/docker-syncd-clounix/base_image_files/clx_icling b/platform/clounix/docker-syncd-clounix/base_image_files/clx_icling new file mode 100755 index 000000000000..994343866af0 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/base_image_files/clx_icling @@ -0,0 +1,5 @@ +#!/bin/bash + +docker exec -it syncd clx_diag icling +docker exec -it syncd jupyter-console --existing clx-icling-shell.json + diff --git a/platform/clounix/docker-syncd-clounix/base_image_files/clx_ipython b/platform/clounix/docker-syncd-clounix/base_image_files/clx_ipython new file mode 100755 index 000000000000..818832f3b952 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/base_image_files/clx_ipython @@ -0,0 +1,5 @@ +#!/bin/bash + +docker exec -it syncd clx_diag ipy +docker exec -it syncd jupyter-console --existing clx-ipython-shell.json + diff --git a/platform/clounix/docker-syncd-clounix/critical_processes b/platform/clounix/docker-syncd-clounix/critical_processes new file mode 100644 index 000000000000..d1163a9c3046 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/critical_processes @@ -0,0 +1,2 @@ +program:dsserve +program:syncd diff --git a/platform/clounix/docker-syncd-clounix/install_clingkernel.sh b/platform/clounix/docker-syncd-clounix/install_clingkernel.sh new file mode 100755 index 000000000000..5596647dcee1 --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/install_clingkernel.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +echo "Install IPython ClingKernel ..." +cd /opt/ && tar xvf cling-0.9-buster.tar -C /usr/ && \ +cd /usr/share/cling/tools/Jupyter/kernel/ && \ +pip3 install -e . && \ +jupyter-kernelspec install cling-cpp11 && \ +jupyter-kernelspec install cling-cpp14 && \ +jupyter-kernelspec install cling-cpp1z && \ +jupyter-kernelspec install cling-cpp17 && \ +jupyter-kernelspec list && \ +rm -rf /opt/cling-0.9-buster.tar +echo "Done" diff --git a/platform/clounix/docker-syncd-clounix/ipython_config.json b/platform/clounix/docker-syncd-clounix/ipython_config.json new file mode 100644 index 000000000000..ce59391ab3bd --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/ipython_config.json @@ -0,0 +1,6 @@ +{ + "ConnectionFileMixin": { + "connection_file" : "clx-ipython-shell.json" + } +} + diff --git a/platform/clounix/docker-syncd-clounix/supervisord.conf b/platform/clounix/docker-syncd-clounix/supervisord.conf new file mode 100644 index 000000000000..3437400338be --- /dev/null +++ b/platform/clounix/docker-syncd-clounix/supervisord.conf @@ -0,0 +1,38 @@ +[supervisord] +logfile_maxbytes=1MB +logfile_backups=2 +nodaemon=true + +[eventlistener:dependent-startup] +command=python3 -m supervisord_dependent_startup +autostart=true +autorestart=unexpected +startretries=0 +exitcodes=0,3 +events=PROCESS_STATE +buffer_size=25 + +[eventlistener:supervisor-proc-exit-listener] +command=python3 /usr/bin/supervisor-proc-exit-listener --container-name syncd +events=PROCESS_STATE_EXITED,PROCESS_STATE_RUNNING +autostart=true +autorestart=unexpected + +[program:rsyslogd] +command=/usr/sbin/rsyslogd -n -iNONE +priority=1 +autostart=false +autorestart=unexpected +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true + +[program:syncd] +command=/usr/bin/syncd_start.sh +priority=2 +autostart=false +autorestart=false +stdout_logfile=syslog +stderr_logfile=syslog +dependent_startup=true +dependent_startup_wait_for=rsyslogd:running diff --git a/platform/clounix/libsaithrift-dev.dep b/platform/clounix/libsaithrift-dev.dep new file mode 100644 index 000000000000..658835665636 --- /dev/null +++ b/platform/clounix/libsaithrift-dev.dep @@ -0,0 +1,13 @@ +#DPKG FRK +SPATH := $($(LIBSAITHRIFT_DEV)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/libsaithrift-dev.mk platform/clounix/libsaithrift-dev.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_PATHS := $(SPATH) +$(foreach path, $(SMDEP_PATHS), $(eval $(path) :=$(filter-out $(SMDEP_PATHS),$(addprefix $(path)/, $(shell cd $(path) && git ls-files | grep -Ev " " ))))) + +$(LIBSAITHRIFT_DEV)_CACHE_MODE := GIT_CONTENT_SHA +$(LIBSAITHRIFT_DEV)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(LIBSAITHRIFT_DEV)_DEP_FILES := $(DEP_FILES) +$(LIBSAITHRIFT_DEV)_SMDEP_FILES := $(foreach path, $(SMDEP_PATHS), $($(path))) +$(LIBSAITHRIFT_DEV)_SMDEP_PATHS := $(SMDEP_PATHS) + diff --git a/platform/clounix/libsaithrift-dev.mk b/platform/clounix/libsaithrift-dev.mk new file mode 100644 index 000000000000..906ce44b4238 --- /dev/null +++ b/platform/clounix/libsaithrift-dev.mk @@ -0,0 +1,20 @@ +# libsaithrift-dev package + +SAI_VER = 1.7.1 + +LIBSAITHRIFT_DEV = libsaithrift-dev_$(SAI_VER)_amd64.deb +$(LIBSAITHRIFT_DEV)_SRC_PATH = $(PLATFORM_PATH)/saithrift/ +$(LIBSAITHRIFT_DEV)_DEPENDS += $(LIBTHRIFT) $(LIBTHRIFT_DEV) $(PYTHON_THRIFT) $(THRIFT_COMPILER) $(CLOUNIX_SAI) $(CLOUNIX_SAI_DEV) +$(LIBSAITHRIFT_DEV)_RDEPENDS += $(LIBTHRIFT) $(CLOUNIX_SAI) +SONIC_DPKG_DEBS += $(LIBSAITHRIFT_DEV) + +PYTHON_SAITHRIFT = python-saithrift_$(SAI_VER)_amd64.deb +$(eval $(call add_extra_package,$(LIBSAITHRIFT_DEV),$(PYTHON_SAITHRIFT))) + +SAISERVER = saiserver_$(SAI_VER)_amd64.deb +$(SAISERVER)_RDEPENDS += $(LIBTHRIFT) $(CLOUNIX_SAI) +$(eval $(call add_extra_package,$(LIBSAITHRIFT_DEV),$(SAISERVER))) + +SAISERVER_DBG = saiserver-dbg_$(SAI_VER)_amd64.deb +$(SAISERVER_DBG)_RDEPENDS += $(SAISERVER) +$(eval $(call add_extra_package,$(LIBSAITHRIFT_DEV),$(SAISERVER_DBG))) diff --git a/platform/clounix/one-image.dep b/platform/clounix/one-image.dep new file mode 100644 index 000000000000..c5399d808172 --- /dev/null +++ b/platform/clounix/one-image.dep @@ -0,0 +1,2 @@ +#DPKG FRK +$(SONIC_ONE_IMAGE)_CACHE_MODE := none diff --git a/platform/clounix/one-image.mk b/platform/clounix/one-image.mk new file mode 100644 index 000000000000..b9f685effc08 --- /dev/null +++ b/platform/clounix/one-image.mk @@ -0,0 +1,16 @@ +# sonic clounix one image installer + +SONIC_ONE_IMAGE = sonic-clounix.bin +$(SONIC_ONE_IMAGE)_MACHINE = clounix +$(SONIC_ONE_IMAGE)_IMAGE_TYPE = onie +$(SONIC_ONE_IMAGE)_INSTALLS += $(CLOUNIX_MODULE) $(CLX_UTILS) +$(SONIC_ONE_IMAGE)_INSTALLS += $(SYSTEMD_SONIC_GENERATOR) +$(SONIC_ONE_IMAGE)_LAZY_INSTALLS += $(PEGATRON_FN8656_BNF_PLATFORM_MODULE) + +ifeq ($(INSTALL_DEBUG_TOOLS),y) +$(SONIC_ONE_IMAGE)_DOCKERS += $(SONIC_INSTALL_DOCKER_DBG_IMAGES) +$(SONIC_ONE_IMAGE)_DOCKERS += $(filter-out $(patsubst %-$(DBG_IMAGE_MARK).gz,%.gz, $(SONIC_INSTALL_DOCKER_DBG_IMAGES)), $(SONIC_INSTALL_DOCKER_IMAGES)) +else +$(SONIC_ONE_IMAGE)_DOCKERS = $(SONIC_INSTALL_DOCKER_IMAGES) +endif +SONIC_INSTALLERS += $(SONIC_ONE_IMAGE) diff --git a/platform/clounix/platform-modules-pegatron.dep b/platform/clounix/platform-modules-pegatron.dep new file mode 100644 index 000000000000..fc8ca5fe2bc6 --- /dev/null +++ b/platform/clounix/platform-modules-pegatron.dep @@ -0,0 +1,10 @@ + +MPATH := $($(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/platform-modules-pegatron.mk platform/clounix/platform-modules-pegatron.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(MPATH)) + +$(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_CACHE_MODE := GIT_CONTENT_SHA +$(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_DEP_FILES := $(DEP_FILES) + diff --git a/platform/clounix/platform-modules-pegatron.mk b/platform/clounix/platform-modules-pegatron.mk new file mode 100644 index 000000000000..0ae02644a4a3 --- /dev/null +++ b/platform/clounix/platform-modules-pegatron.mk @@ -0,0 +1,11 @@ +# Pegatron Platform modules +PEGATRON_PLATFORM_MODULE_VERSION = 1.0.0 +export PEGATRON_PLATFORM_MODULE_VERSION + +PEGATRON_FN8656_BNF_PLATFORM_MODULE = sonic-platform-pegatron-fn8656-bnf_$(PEGATRON_PLATFORM_MODULE_VERSION)_amd64.deb +$(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_SRC_PATH = $(PLATFORM_PATH)/sonic-platform-modules-pegatron +$(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +$(PEGATRON_FN8656_BNF_PLATFORM_MODULE)_PLATFORM = x86_64-pegatron_fn8656_bnf-r0 +SONIC_DPKG_DEBS += $(PEGATRON_FN8656_BNF_PLATFORM_MODULE) + +$(eval $(call add_extra_package,$(PEGATRON_FN8656_BNF_PLATFORM_MODULE))) diff --git a/platform/clounix/platform.conf b/platform/clounix/platform.conf new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/platform/clounix/rules.dep b/platform/clounix/rules.dep new file mode 100644 index 000000000000..e8f9f77a0a0c --- /dev/null +++ b/platform/clounix/rules.dep @@ -0,0 +1,7 @@ +#DPKG FRK +include $(PLATFORM_PATH)/clounix-modules.dep +include $(PLATFORM_PATH)/clx-utils.dep +include $(PLATFORM_PATH)/platform-modules-pegatron.dep +include $(PLATFORM_PATH)/docker-syncd-clounix.dep +include $(PLATFORM_PATH)/docker-syncd-clounix-rpc.dep +include $(PLATFORM_PATH)/one-image.dep diff --git a/platform/clounix/rules.mk b/platform/clounix/rules.mk new file mode 100644 index 000000000000..fecb693b9cbf --- /dev/null +++ b/platform/clounix/rules.mk @@ -0,0 +1,27 @@ +include $(PLATFORM_PATH)/sai.mk +include $(PLATFORM_PATH)/clx-utils.mk +include $(PLATFORM_PATH)/clounix-modules.mk +include $(PLATFORM_PATH)/platform-modules-pegatron.mk +include $(PLATFORM_PATH)/docker-syncd-clounix.mk +include $(PLATFORM_PATH)/docker-syncd-clounix-rpc.mk +include $(PLATFORM_PATH)/one-image.mk +include $(PLATFORM_PATH)/libsaithrift-dev.mk +include $(PLATFORM_PATH)/docker-ptf-clounix.mk +include $(PLATFORM_PATH)/docker-saiserver-clounix.mk + +DSSERVE = dsserve +$(DSSERVE)_URL = "https://sonicstorage.blob.core.windows.net/packages/20190307/dsserve?sv=2015-04-05&sr=b&sig=lk7BH3DtW%2F5ehc0Rkqfga%2BUCABI0UzQmDamBsZH9K6w%3D&se=2038-05-06T22%3A34%3A45Z&sp=r" +SONIC_ONLINE_FILES += $(DSSERVE) + +SONIC_ALL += $(SONIC_ONE_IMAGE) $(DOCKER_FPM) + +# Inject clounix sai into syncd +$(SYNCD)_DEPENDS += $(CLOUNIX_SAI) $(CLOUNIX_SAI_DEV) +$(SYNCD)_UNINSTALLS += $(CLOUNIX_SAI_DEV) + +ifeq ($(ENABLE_SYNCD_RPC),y) +$(SYNCD)_DEPENDS += $(LIBSAITHRIFT_DEV) +endif + +# Runtime dependency on clounix sai is set only for syncd +$(SYNCD)_RDEPENDS += $(CLOUNIX_SAI) diff --git a/platform/clounix/sai.dep b/platform/clounix/sai.dep new file mode 100644 index 000000000000..29b5feefcece --- /dev/null +++ b/platform/clounix/sai.dep @@ -0,0 +1,13 @@ + +SPATH := $($(CLOUNIX_SAI)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) platform/clounix/sai.mk platform/clounix/sai.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_PATHS := $(SPATH) $(SPATH)/clx_system +$(foreach path, $(SMDEP_PATHS), $(eval $(path) :=$(filter-out $(SMDEP_PATHS),$(addprefix $(path)/, $(shell cd $(path) && git ls-files | grep -Ev " " ))))) + +$(CLOUNIX_SAI)_CACHE_MODE := GIT_CONTENT_SHA +$(CLOUNIX_SAI)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(CLOUNIX_SAI)_DEP_FILES := $(DEP_FILES) +$(CLOUNIX_SAI)_SMDEP_FILES := $(foreach path, $(SMDEP_PATHS), $($(path))) +$(CLOUNIX_SAI)_SMDEP_PATHS := $(SMDEP_PATHS) + diff --git a/platform/clounix/sai.mk b/platform/clounix/sai.mk new file mode 100644 index 000000000000..300615d25c03 --- /dev/null +++ b/platform/clounix/sai.mk @@ -0,0 +1,42 @@ +SDK_VERSION = 3.0.0 +SAI_HEADER_VERSION = 1.7.1.0-1.RC1 +#SAI_CHIP_ID = dawn +SAI_CHIP_ID = lightning +export SAI_HEADER_VERSION SAI_CHIP_ID + +# Place here URL where SAI deb exist +# +SAI_DEB_URL = yes +ifeq ($(SAI_DEB_URL),no) +CLOUNIX_SAI = libsaiclx_$(SAI_HEADER_VERSION)_amd64.deb +$(CLOUNIX_SAI)_SRC_PATH = $(PLATFORM_PATH)/clnx-sai +$(CLOUNIX_SAI)_DEPENDS += $(LINUX_HEADERS) $(LINUX_HEADERS_COMMON) +SONIC_DPKG_DEBS += $(CLOUNIX_SAI) + +CLOUNIX_SAI_DEV = libsaiclx-dev_$(SAI_HEADER_VERSION)_amd64.deb +$(CLOUNIX_SAI_DEV)_DEPENDS += $(CLOUNIX_SAI) + +CLOUNIX_WARM_VERIFIER = clx-app_$(SAI_HEADER_VERSION)_amd64.deb +$(CLOUNIX_WARM_VERIFIER)_DEPENDS += $(CLOUNIX_SAI) + +CLOUNIX_SAI_DBG = libsaiclx-dbg_$(SAI_HEADER_VERSION)_amd64.deb +$(CLOUNIX_SAI_DBG)_DEPENDS += $(CLOUNIX_SAI) +$(eval $(call add_derived_package,$(CLOUNIX_SAI),$(CLOUNIX_SAI_DEV))) +$(eval $(call add_derived_package,$(CLOUNIX_SAI),$(CLOUNIX_WARM_VERIFIER))) +$(eval $(call add_derived_package,$(CLOUNIX_SAI),$(CLOUNIX_SAI_DBG))) +else +CLOUNIX_SAI = libsaiclx_$(SAI_HEADER_VERSION)_amd64.deb +$(CLOUNIX_SAI)_PATH = $(PLATFORM_PATH)/clx-sai +$(CLOUNIX_SAI)_URL = "https://github.com/clounix/sai_release/raw/main/sai_available/libsaiclx_$(SAI_HEADER_VERSION)_amd64.deb" + +CLOUNIX_SAI_DEV = libsaiclx-dev_$(SAI_HEADER_VERSION)_amd64.deb +$(CLOUNIX_SAI_DEV)_PATH = $(PLATFORM_PATH)/clx-sai +$(CLOUNIX_SAI_DEV)_URL = "https://github.com/clounix/sai_release/raw/main/sai_available/libsaiclx-dev_$(SAI_HEADER_VERSION)_amd64.deb" + +CLOUNIX_SAI_DBG = libsaiclx-dbg_$(SAI_HEADER_VERSION)_amd64.deb +(CLOUNIX_SAI_DBG)_PATH = $(PLATFORM_PATH)/clx-sai +$(CLOUNIX_SAI_DBG)_URL = "https://github.com/clounix/sai_release/raw/main/sai_available/libsaiclx-dbg_$(SAI_HEADER_VERSION)_amd64.deb" +#SONIC_COPY_DEBS += $(CLOUNIX_SAI) $(CLOUNIX_SAI_DEV) +SONIC_ONLINE_DEBS+= $(CLOUNIX_SAI) $(CLOUNIX_SAI_DEV) +endif + diff --git a/platform/clounix/sonic-platform-modules-pegatron/LICENSE b/platform/clounix/sonic-platform-modules-pegatron/LICENSE new file mode 100644 index 000000000000..a23cc2b232cd --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/LICENSE @@ -0,0 +1,16 @@ +Copyright (C) 2016 Microsoft, Inc +Copyright (C) 2018 Pegatron Corporation. + +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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. diff --git a/platform/clounix/sonic-platform-modules-pegatron/README.md b/platform/clounix/sonic-platform-modules-pegatron/README.md new file mode 100644 index 000000000000..32444b4b8916 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/README.md @@ -0,0 +1 @@ +platform drivers of Pegatron products for the SONiC project diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/Makefile b/platform/clounix/sonic-platform-modules-pegatron/common/modules/Makefile new file mode 100644 index 000000000000..4a685c2650bc --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/Makefile @@ -0,0 +1,3 @@ +obj-m += i2c-mux-pca9641.o +obj-m += pegatron_hwmon_mcu.o +obj-m += clounix_sysfs_main.o diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_common.h b/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_common.h new file mode 100644 index 000000000000..64d878510572 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_common.h @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct clounix_node_info { + struct list_head node; + char name[64]; + char info[256]; + struct kobj_attribute kobj_attr; +}; diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_main.c b/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_main.c new file mode 100644 index 000000000000..84bc19b50cdb --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_main.c @@ -0,0 +1,445 @@ +#include "clounix_sysfs_common.h" +#include "clounix_sysfs_var.h" + +static struct kobject *clounix_switch; +static struct kernfs_node *fail_node = NULL; +atomic_t is_work = ATOMIC_INIT(0); + +LIST_HEAD(clounix_list_head); +DEFINE_SPINLOCK(node_rw_lock); + +static inline int in_work(void) +{ + if (atomic_read(&is_work) < 0) + return 1; + + if (atomic_add_negative(1, &is_work) != 0) { + atomic_dec(&is_work); + return 1; + } + + return 0; +} + +static inline void out_work(void) +{ + atomic_dec(&is_work); +} + +static char *skip_root(char *path) +{ + if (memcmp(path, SYSFS_ROOT, strlen(SYSFS_ROOT)) == 0) { + path += strlen(SYSFS_ROOT); + return path; + } + + return NULL; +} + +static void traverse_sysfs_by_rbtree(struct kernfs_node *parent) +{ + struct rb_node *node; + struct kernfs_node *sd; + + if (parent == NULL) + return; + + node = rb_first(&(parent->dir.children)); + + while (node != NULL) { + sd = container_of(node, struct kernfs_node, rb); + printk(KERN_DEBUG "node name: %s \t type: %x parent dir %s\r\n", sd->name ? sd->name : "null", sd->flags, sd->parent->name); + node = rb_next(node); + } +} + +static struct kernfs_node *search_sysfs_node_by_path(struct kernfs_node *root, char *path) +{ + char *start, *end; + struct kernfs_node *sd = root; + + if (path == NULL || root == NULL) + goto out; + + if ((start = skip_root(path)) == NULL) + start = path; + + while (start != NULL) { + while (*start == '/') + start++; + + if ((end = strchr(start, '/')) != NULL) { + *end = '\0'; + sd = sysfs_get_dirent(sd, start); + sysfs_put(sd); + *end = '/'; + + if (sd == NULL) + goto out; + + if ((sd->flags & KERNFS_LINK) != 0) + sd = sd->symlink.target_kn; + + start = end+1; + } else { + sd = sysfs_get_dirent(sd, start); + sysfs_put(sd); + break; + } + } + + return sd; + +out: + return NULL; +} + +static struct kernfs_node *pass_path(struct kobject **kobj, struct kernfs_node *root, char *path, char **name) +{ + struct kernfs_node *sd = NULL; + char *start, *end; + + if ((start = skip_root(path)) == NULL) { + printk(KERN_DEBUG "path format err\r\n"); + return NULL; + } + + while (start != NULL) { + while (*start == '/') + start++; + + if ((end = strchr(start, '/')) != NULL) { + *end = '\0'; + if ((sd = sysfs_get_dirent(root, start)) == NULL) { + if ((*kobj = kobject_create_and_add(start, root->priv)) == NULL) + goto path_err; + + printk(KERN_DEBUG "create missing dir %s\r\n", (*kobj)->sd->name); + sd = (*kobj)->sd; + sysfs_get(sd); + } + + sysfs_put(sd); + *end = '/'; + root = sd; + start = end+1; + continue; + } + *kobj = root->priv; + *name = start; + break; + } + + return root; + +path_err: + return NULL; +} + +static int create_link_auto(struct kernfs_node *root, struct kernfs_node *target, char *path) +{ + struct kernfs_node *sd; + struct kobject *kobj = NULL; + struct kobject fake_kobj = {0}; + char *start; + int err_no; + + if ((root = pass_path(&kobj, root, path, &start)) == NULL) + return -ENOMEM; + + if ((sd = sysfs_get_dirent(root, start)) != NULL) { + sysfs_put(sd); + printk(KERN_DEBUG "link exist\r\n"); + return -EEXIST; + } + /* + Some sysfs node is create by func 'sysfs_create_group(s)', the node's kernfs_node struct's + member 'priv' is 'attribute' not 'kobject'.Can use fake kobj to create link, because the + 'sysfs_crate_link' only use kobj->sd as link source and never use other member in kobj. + */ + fake_kobj.sd = target; + + if ((err_no = sysfs_create_link(kobj, &fake_kobj, start)) != 0) { + printk(KERN_DEBUG "fail to create link %s in dir %s\r\n", start, kobj->sd->name); + return err_no; + } + + return 0; +} + +static char *format_check(const char *buf) +{ + char *p = (char *)buf; + + if ((p = strchr(p, ' ')) != NULL) { + if (*(p+1) != ' ') + return p; + else + return NULL; + } + + return NULL; +} + +static struct clounix_node_info *find_node_from_list(struct attribute *attr) +{ + struct clounix_node_info *pos = NULL; + struct clounix_node_info *tmp = NULL; + + list_for_each_entry_safe(pos, tmp, &clounix_list_head, node) { + if (attr == &(pos->kobj_attr.attr)) + return pos; + } + + return NULL; +} + +static void rm_all_node(void) +{ + struct clounix_node_info *pos = NULL; + struct clounix_node_info *tmp = NULL; + + spin_lock(&node_rw_lock); + list_for_each_entry_safe(pos, tmp, &clounix_list_head, node) { + list_del_init(&(pos->node)); + kfree(pos); + } + spin_unlock(&node_rw_lock); +} + +static ssize_t node_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + struct clounix_node_info *pos = NULL; + int len = 0; + + spin_lock(&node_rw_lock); + if ((pos = find_node_from_list(&(attr->attr))) != NULL) + len = sprintf(buf, "%s\r\n", pos->info); + spin_unlock(&node_rw_lock); + + return len; +} + +static int add_node(struct kernfs_node *root, char *buf) +{ + int err_no; + char *node_path, *info; + struct kobject *kobj; + struct kernfs_node *tmp; + struct clounix_node_info *attr_node; + + node_path = format_check(buf); + if (node_path == NULL) + return -ENOENT; + + info = node_path + 1; + *node_path = '\0'; + node_path = buf; + + if ((root = pass_path(&kobj, root, node_path, &node_path)) == NULL) + return -ENOENT; + + if (strlen(node_path) > MAX_NODE_NAME_LEN) + return -ENOMEM; + + if (strlen(info) > MAX_NODE_INFO_LEN) + return -ENOMEM; + + if ((tmp = sysfs_get_dirent(root, node_path)) != NULL) { + sysfs_put(tmp); + printk(KERN_DEBUG "node exist\r\n"); + return -EEXIST; + } + + if ((attr_node = kzalloc(sizeof(struct clounix_node_info), GFP_ATOMIC)) == NULL) + return -ENOMEM; + + strcpy(attr_node->name, node_path); + strcpy(attr_node->info, info); + attr_node->kobj_attr.attr.name = attr_node->name; + attr_node->kobj_attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444); + attr_node->kobj_attr.show = node_show; + attr_node->kobj_attr.store = NULL; + + if ((err_no = sysfs_create_file(kobj, &(attr_node->kobj_attr.attr))) != 0) { + kfree(attr_node); + return err_no; + } + + spin_lock(&node_rw_lock); + list_add_tail(&(attr_node->node), &clounix_list_head); + spin_unlock(&node_rw_lock); + + return 0; +} + +static int del_node(struct kernfs_node *root, char *link) +{ + struct kernfs_node *sd; + struct clounix_node_info *node = NULL; + + if ((sd = search_sysfs_node_by_path(root, link)) == NULL) + goto not_find; + + if ((sd->flags & KERNFS_LINK) != 0) + sysfs_remove_link(sd->parent->priv, sd->name); + else if ((sd->flags & KERNFS_DIR) != 0) + kobject_del(sd->priv); + else if ((sd->flags & KERNFS_FILE) != 0) { + spin_lock(&node_rw_lock); + if ((node = find_node_from_list(sd->priv)) == NULL) { + spin_unlock(&node_rw_lock); + goto not_find; + } + list_del_init(&node->node); + spin_unlock(&node_rw_lock); + + sysfs_remove_file(sd->parent->priv, sd->priv); + kfree(node); + } + + return 0; + +not_find: + printk(KERN_DEBUG "del target not found\r\n"); + return -1; +} + +static int cmd_guess(const char *buf) +{ + if (memcmp(buf, DEL_CMD, strlen(DEL_CMD)) == 0) + return DEL_OPS; + else if (memcmp(buf, ADD_CMD, strlen(ADD_CMD)) == 0) + return ADD_OPS; + else + return 0; +} + +static int add_new_link(struct kernfs_node *root, char *src, char *node) +{ + struct kernfs_node *target = NULL; + + if ((target = search_sysfs_node_by_path(root, src)) == NULL) + goto path_err; + + if ((target->flags & KERNFS_LINK) != 0) + target = target->symlink.target_kn; + + create_link_auto(root, target, node); + + return 0; + +path_err: + printk(KERN_DEBUG "not find sysfs node: %s\r\n", src); + return -1; +} + +static ssize_t cmd_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) +{ + traverse_sysfs_by_rbtree(fail_node); + + return 0; +} + +static ssize_t cmd_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t count) +{ + struct kernfs_node *root = clounix_switch->sd->parent; + char *src, *pra; + char *p; + + if (in_work() == 1) + return count; + + if (count <= MIN_PATH_LEN || count > PAGE_SIZE) + goto format_err; + + if ((p = format_check(buf)) == NULL) + goto format_err; + + if ((src = kzalloc(PAGE_SIZE, GFP_ATOMIC)) == NULL) + goto format_err; + + memcpy(src, buf, count-1); + pra = src + (p - buf); + *pra = '\0'; + pra++; + + switch (cmd_guess(buf)) { + case DEL_OPS: + if (del_node(root, pra) != 0) + goto path_err; + break; + case ADD_OPS: + if (add_node(root, pra) != 0) + goto path_err; + break; + default: + if (add_new_link(root, src, pra) != 0) + goto path_err; + break; + } + + kfree(src); + out_work(); + return count; + +path_err: + printk(KERN_DEBUG "not find %s\r\n", buf); +format_err: + printk(KERN_DEBUG KERN_ALERT PATH_FORMAT); + kfree(src); + out_work(); + return count; +} + +static struct kobj_attribute ctrl_attr = __ATTR(clounix_cmd, 0644, cmd_show, cmd_store); + +static struct attribute * ctrl_attrs[] = { + &ctrl_attr.attr, + NULL +}; + +static const struct attribute_group control_attr_group = { + .attrs = ctrl_attrs, +}; + +static int __init main_init(void) +{ + int err_no = 0; + + printk(KERN_DEBUG "clounix kobj node_init!\r\n"); + + clounix_switch = kobject_create_and_add(CLOUNIX_DIR_NAME, NULL); + if (clounix_switch == NULL) + return -ENOMEM; + + if ((err_no = sysfs_create_group(clounix_switch, &control_attr_group)) != 0) + goto err_out; + + return 0; + +err_out: + printk(KERN_DEBUG "has err_no %d\r\n", err_no); + kobject_put(clounix_switch); + return -ENOMEM; +} + +static void __exit main_exit(void) +{ + printk(KERN_DEBUG "clounix kobj node_del!\r\n"); + + if (atomic_sub_return(2, &is_work) != -2) { + while (atomic_read(&is_work) != -2) {}; + } + sysfs_remove_group(clounix_switch, &control_attr_group); + + rm_all_node(); + kobject_del(clounix_switch); +} + +module_init(main_init); +module_exit(main_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("baohx@clounix.com"); +MODULE_DESCRIPTION("clounix sysfs operate interface"); diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_var.h b/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_var.h new file mode 100644 index 000000000000..ab0425e84d96 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/clounix_sysfs_var.h @@ -0,0 +1,15 @@ +#define MIN_PATH_LEN (16) +#define MAX_NAME_LEN (PAGE_SIZE/2) + +#define PATH_FORMAT "Format:\r\nFor create: target_node path link_node_path.\r\nFor del: del link_node_path\r\nThe path format must be full path like \"/sys/bus/...\"\r\n" + +#define SYSFS_ROOT "/sys" +#define CLOUNIX_DIR_NAME "switch" +#define DEL_CMD "del " +#define ADD_CMD "add " + +#define MAX_NODE_NAME_LEN (64-1) +#define MAX_NODE_INFO_LEN (256-1) + +#define DEL_OPS 1 +#define ADD_OPS 2 diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/i2c-mux-pca9641.c b/platform/clounix/sonic-platform-modules-pegatron/common/modules/i2c-mux-pca9641.c new file mode 100644 index 000000000000..1499a9a70256 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/i2c-mux-pca9641.c @@ -0,0 +1,427 @@ +/* + * I2C multiplexer driver for PCA9641 bus master selector + * + * Copyright (c) 2010 Ericsson AB. + * + * Author: Guenter Roeck + * + * Derived from: + * pca954x.c + * + * Copyright (c) 2008-2009 Rodolfo Giometti + * Copyright (c) 2008-2009 Eurotech S.p.A. + * + * 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 +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) +#include +#endif +#include "pegatron_pub.h" + +/* + * The PCA9641 is a bus master selector. It supports two I2C masters connected + * to a single slave bus. + * + * Before each bus transaction, a master has to acquire bus ownership. After the + * transaction is complete, bus ownership has to be released. This fits well + * into the I2C multiplexer framework, which provides select and release + * functions for this purpose. For this reason, this driver is modeled as + * single-channel I2C bus multiplexer. + * + * This driver assumes that the two bus masters are controlled by two different + * hosts. If a single host controls both masters, platform code has to ensure + * that only one of the masters is instantiated at any given time. + */ + +#define PCA9641_ID 0x00 +#define PCA9641_ID_MAGIC 0x38 + +#define PCA9641_CONTROL 0x01 +#define PCA9641_STATUS 0x02 +#define PCA9641_TIME 0x03 + +#define PCA9641_CTL_LOCK_REQ BIT(0) +#define PCA9641_CTL_LOCK_GRANT BIT(1) +#define PCA9641_CTL_BUS_CONNECT BIT(2) +#define PCA9641_CTL_BUS_INIT BIT(3) +#define PCA9641_CTL_SMBUS_SWRST BIT(4) +#define PCA9641_CTL_IDLE_TIMER_DIS BIT(5) +#define PCA9641_CTL_SMBUS_DIS BIT(6) +#define PCA9641_CTL_PRIORITY BIT(7) + +#define PCA9641_STS_OTHER_LOCK BIT(0) +#define PCA9641_STS_BUS_INIT_FAIL BIT(1) +#define PCA9641_STS_BUS_HUNG BIT(2) +#define PCA9641_STS_MBOX_EMPTY BIT(3) +#define PCA9641_STS_MBOX_FULL BIT(4) +#define PCA9641_STS_TEST_INT BIT(5) +#define PCA9641_STS_SCL_IO BIT(6) +#define PCA9641_STS_SDA_IO BIT(7) + +/* arbitration timeouts, in jiffies */ +#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ +#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ + +/* arbitration retry delays, in us */ +#define SELECT_DELAY_SHORT 50 +#define SELECT_DELAY_LONG 1000 + +static void pca9641_release_bus(struct i2c_client *client); +static int pca9641_arbitrate(struct i2c_client *client); +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; + +enum pca_type { + pca_9541, + pca_9641, +}; + +struct pca9641 { + struct i2c_client *client; + unsigned long select_timeout; + unsigned long arb_timeout; +}; + +static const struct i2c_device_id pca9641_id[] = { + { "pca9541", pca_9541 }, + { "pca9641", pca_9641 }, + {} +}; + +MODULE_DEVICE_TABLE(i2c, pca9641_id); + +#ifdef CONFIG_OF +static const struct of_device_id pca9641_of_match[] = { + { .compatible = "nxp,pca9541" }, + { .compatible = "nxp,pca9641" }, + {} +}; +MODULE_DEVICE_TABLE(of, pca9641_of_match); +#endif + +/* + * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() + * as they will try to lock the adapter a second time. + */ +static int pca9641_reg_write(struct i2c_client *client, u8 command, u8 val) +{ + struct i2c_adapter *adap = client->adapter; + int ret; + + if (adap->algo->master_xfer) { + struct i2c_msg msg; + char buf[2]; + + msg.addr = client->addr; + msg.flags = 0; + msg.len = 2; + buf[0] = command; + buf[1] = val; + msg.buf = buf; + ret = adap->algo->master_xfer(adap, &msg, 1); + } else { + union i2c_smbus_data data; + + data.byte = val; + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_WRITE, + command, + I2C_SMBUS_BYTE_DATA, &data); + } + + return ret; +} + +/* + * Read from chip register. Don't use i2c_transfer()/i2c_smbus_xfer() + * as they will try to lock adapter a second time. + */ +static int pca9641_reg_read(struct i2c_client *client, u8 command) +{ + struct i2c_adapter *adap = client->adapter; + int ret; + u8 val; + + if (adap->algo->master_xfer) { + struct i2c_msg msg[2] = { + { + .addr = client->addr, + .flags = 0, + .len = 1, + .buf = &command + }, + { + .addr = client->addr, + .flags = I2C_M_RD, + .len = 1, + .buf = &val + } + }; + ret = adap->algo->master_xfer(adap, msg, 2); + if (ret == 2) { + ret = val; + } + else if (ret >= 0) { + ret = -EIO; + } + } else { + union i2c_smbus_data data; + + ret = adap->algo->smbus_xfer(adap, client->addr, + client->flags, + I2C_SMBUS_READ, + command, + I2C_SMBUS_BYTE_DATA, &data); + if (!ret) { + ret = data.byte; + } + } + return ret; +} + +/* + * Arbitration management functions + */ + +#define pca9641_other_lock(r) ((r) & PCA9641_STS_OTHER_LOCK) +#define pca9641_lock_grant(r) ((r) & PCA9641_CTL_LOCK_GRANT) + +static inline int pca9641_busoff(int ctl, int sts) +{ + return !(ctl & PCA9641_CTL_LOCK_GRANT) && + !(sts & PCA9641_STS_OTHER_LOCK); +} + + +/* Release bus. Also reset NTESTON and BUSINIT if it was set. */ +static void pca9641_release_bus(struct i2c_client *client) +{ + pca9641_reg_write(client, PCA9641_CONTROL, 0); +} + + +/* + * Arbitration is defined as a two-step process. A bus master can only activate + * the slave bus if it owns it; otherwise it has to request ownership first. + * This multi-step process ensures that access contention is resolved + * gracefully. + * + * Bus Ownership Other master Action + * state requested access + * ---------------------------------------------------- + * off - yes wait for arbitration timeout or + * for other master to drop request + * off no no take ownership + * off yes no turn on bus + * on yes - done + * on no - wait for arbitration timeout or + * for other master to release bus + * + * The main contention point occurs if the slave bus is off and both masters + * request ownership at the same time. In this case, one master will turn on + * the slave bus, believing that it owns it. The other master will request + * bus ownership. Result is that the bus is turned on, and master which did + * _not_ own the slave bus before ends up owning it. + */ + +/* + * Channel arbitration + * + * Return values: + * <0: error + * 0 : bus not acquired + * 1 : bus acquired + */ +static int pca9641_arbitrate(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + struct pca9641 *data = i2c_mux_priv(muxc); + int reg_ctl, reg_sts; + + reg_ctl = pca9641_reg_read(client, PCA9641_CONTROL); + if (reg_ctl < 0) { + return reg_ctl; + } + reg_sts = pca9641_reg_read(client, PCA9641_STATUS); + pega_print(DEBUG, "PCA9641_CONTROL:0x%x,PCA9641_STATUS:0x%x\n", reg_ctl,reg_sts); + + if (pca9641_busoff(reg_ctl, reg_sts)) { + /* + * Bus is off. Request ownership or turn it on unless + * other master requested ownership. + */ + //printk(KERN_WARNING "(ar)lock req\n"); + reg_ctl |= PCA9641_CTL_LOCK_REQ | PCA9641_CTL_IDLE_TIMER_DIS | PCA9641_CTL_SMBUS_DIS; + pca9641_reg_write(client, PCA9641_CONTROL, reg_ctl); + reg_ctl = pca9641_reg_read(client, PCA9641_CONTROL); + if (pca9641_lock_grant(reg_ctl)) { + /* + * Other master did not request ownership, + * or arbitration timeout expired. Take the bus. + */ + //printk(KERN_WARNING "(ar)grant\n"); + reg_ctl |= PCA9641_CTL_BUS_CONNECT + | PCA9641_CTL_LOCK_REQ; + pca9641_reg_write(client, PCA9641_CONTROL, reg_ctl); + data->select_timeout = SELECT_DELAY_SHORT; + + return 1; + } else { + /* + * Other master requested ownership. + * Set extra long timeout to give it time to acquire it. + */ + data->select_timeout = SELECT_DELAY_LONG * 2; + } + } else if (pca9641_lock_grant(reg_ctl)) { + /* + * Bus is on, and we own it. We are done with acquisition. + */ + //printk(KERN_WARNING "(ar)grant already\n"); + reg_ctl |= PCA9641_CTL_BUS_CONNECT | PCA9641_CTL_LOCK_REQ; + pca9641_reg_write(client, PCA9641_CONTROL, reg_ctl); + + return 1; + } else if (pca9641_other_lock(reg_sts)) { + /* + * Other master owns the bus. + * If arbitration timeout has expired, force ownership. + * Otherwise request it. + */ + //printk(KERN_WARNING "(ar) other grant already\n"); + data->select_timeout = SELECT_DELAY_LONG; + reg_ctl |= PCA9641_CTL_LOCK_REQ; + pca9641_reg_write(client, PCA9641_CONTROL, reg_ctl); + } + return 0; +} + +static int pca9641_select_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9641 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + int ret; + unsigned long timeout = jiffies + ARB2_TIMEOUT; + /* give up after this time */ + + pega_print(DEBUG, "(ar)select\n"); + data->arb_timeout = jiffies + ARB_TIMEOUT; + /* force bus ownership after this time */ + do { + ret = pca9641_arbitrate(client); + if (ret) { + return ret < 0 ? ret : 0; + } + + if (data->select_timeout == SELECT_DELAY_SHORT) { + udelay(data->select_timeout); + } + else { + msleep(data->select_timeout / 1000); + } + } while (time_is_after_eq_jiffies(timeout)); + pega_print(WARNING,"arbiter acquisition failure (timeout)\n"); + return -ETIMEDOUT; +} + +static int pca9641_release_chan(struct i2c_mux_core *muxc, u32 chan) +{ + struct pca9641 *data = i2c_mux_priv(muxc); + struct i2c_client *client = data->client; + pca9641_release_bus(client); + return 0; +} + +/* + * I2C init/probing/exit functions + */ +static int pca9641_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adap = client->adapter; +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,10,0) + struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev); +#endif + struct i2c_mux_core *muxc; + struct pca9641 *data; + int force; + int ret = -ENODEV; + //int detect_id; + + if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE_DATA)) + return -ENODEV; + + /* + * I2C accesses are unprotected here. + * We have to lock the adapter before releasing the bus. + */ + i2c_lock_bus(adap, I2C_LOCK_SEGMENT); + pca9641_release_bus(client); + i2c_unlock_bus(adap, I2C_LOCK_SEGMENT); + + /* Create mux adapter */ + + force = 0; +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,18,0) + if (pdata) + force = pdata->modes[0].adap_id; +#endif + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), + I2C_MUX_ARBITRATOR, + pca9641_select_chan, pca9641_release_chan); + if (!muxc) + return -ENOMEM; + + data = i2c_mux_priv(muxc); + data->client = client; + + i2c_set_clientdata(client, muxc); + + ret = i2c_mux_add_adapter(muxc, force, 0, 0); + if (ret) { + dev_err(&client->dev, "failed to register master selector\n"); + return ret; + } + + dev_info(&client->dev, "registered master selector for I2C %s\n", + client->name); + + return 0; +} + +static int pca9641_remove(struct i2c_client *client) +{ + struct i2c_mux_core *muxc = i2c_get_clientdata(client); + + i2c_mux_del_adapters(muxc); + return 0; +} + +static struct i2c_driver pca9641_driver = { + .driver = { + .name = "pca9641", + .of_match_table = of_match_ptr(pca9641_of_match), + }, + .probe = pca9641_probe, + .remove = pca9641_remove, + .id_table = pca9641_id, +}; + +module_i2c_driver(pca9641_driver); + +module_param(loglevel,uint,0664); +MODULE_PARM_DESC(loglevel,"0x01-LOG_ERR,0x02-LOG_WARNING,0x04-LOG_INFO,0x08-LOG_DEBUG"); +MODULE_AUTHOR("Guenter Roeck "); +MODULE_DESCRIPTION("PCA9641 I2C master selector driver"); +MODULE_LICENSE("GPL v2"); diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/pegatron_hwmon_mcu.c b/platform/clounix/sonic-platform-modules-pegatron/common/modules/pegatron_hwmon_mcu.c new file mode 100644 index 000000000000..8bab9be95d0b --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/pegatron_hwmon_mcu.c @@ -0,0 +1,1930 @@ +/* + * A MCU driver connect to hwmon + * + * Copyright (C) 2018 Pegatron Corporation. + * Peter5_Lin + * + * 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 "pegatron_pub.h" + +#undef pega_DEBUG +#ifdef pega_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif /* DEBUG */ + +#define FW_UPGRADE_COMMAND 0xA5 +#define FAN_DISABLE_COMMAND 0x20 +#define FAN_ENABLE_COMMAND 0x21 +#define FAN_LED_SETTO_MANUAL_COMMAND 0x30 +#define FAN_LED_SETTO_AUTO_COMMAND 0x31 +#define FAN_LED_GREENOFF_COMMAND 0x40 +#define FAN_LED_GREENON_COMMAND 0x41 +#define FAN_LED_AMBEROFF_COMMAND 0x50 +#define FAN_LED_AMBERON_COMMAND 0x51 +#define SMART_FAN_ENABLE_BIT 0 +#define SMART_FAN_SETTING_ENABLE_BIT 0 +#define SA56004X_REMOTE_TEMP_ALERT_BIT 4 +#define I2C_FANBOARD_TIMEOUT_BIT 0 +#define ALERT_MODE_BIT 0 +#define GET_BIT(data, bit, value) value = (data >> bit) & 0x1 +#define SET_BIT(data, bit) data |= (1 << bit) +#define CLEAR_BIT(data, bit) data &= ~(1 << bit) + +enum fan_alert +{ + FAN_WRONG_AIRFLOW = 0, + FAN_OUTER_RPM_OVER_ALERT_BIT, + FAN_OUTER_RPM_UNDER_ALERT_BIT, + FAN_OUTER_RPM_ZERO_ALERT_BIT, + FAN_INNER_RPM_OVER_ALERT_BIT, + FAN_INNER_RPM_UNDER_ALERT_BIT, + FAN_INNER_RPM_ZERO_ALERT_BIT, + FAN_NOTCONNECT_ALERT_BIT, +}; + +enum fan_status +{ + SYSTEM_AIRFLOW_DIR, + FAN_STATUS_AIRFLOW, + FAN_ALERT_BIT, + FAN_LED_AMBER_BIT, + FAN_LED_GREEN_BIT, + FAN_LED_AUTO_BIT, + FAN_ENABLE_BIT, + FAN_PRESENT_BIT, +}; + +enum hwmon_mcu_register +{ + MB_FW_UG_REG = 0, + FB_FW_UG_REG, + MB_HW_VER_REG, + FB_HW_SKUVER_REG, + MB_FW_VER_REG, + FB_FW_VER_REG, + + FAN_PWM_REG = 16, + + SF_ENABLE_REG, + SF_SETTING_ENABLE_REG, + SF_DEVICE_REG, + SF_UPDATE_REG, + SF_TEMP_MAX_REG, + SF_TEMP_MID_REG, + SF_TEMP_MIN_REG, + SF_PWM_MAX_REG, + SF_PWM_MID_REG, + SF_PWM_MIN_REG, + + FAN1_INNER_RPM_REG = 32, + FAN2_INNER_RPM_REG, + FAN3_INNER_RPM_REG, + FAN4_INNER_RPM_REG, + FAN5_INNER_RPM_REG, + FAN6_INNER_RPM_REG, + + FAN1_OUTER_RPM_REG = 48, + FAN2_OUTER_RPM_REG, + FAN3_OUTER_RPM_REG, + FAN4_OUTER_RPM_REG, + FAN5_OUTER_RPM_REG, + FAN6_OUTER_RPM_REG, + + FAN1_STATUS_REG = 64, + FAN2_STATUS_REG, + FAN3_STATUS_REG, + FAN4_STATUS_REG, + FAN5_STATUS_REG, + FAN6_STATUS_REG, + + ADC_UNDER_VOL_ALERT_REG = 80, + ADC_OVER_VOL_ALERT_REG, + TS_OVER_TEMP_ALERT_REG, + + FAN1_ALERT_REG, + FAN2_ALERT_REG, + FAN3_ALERT_REG, + FAN4_ALERT_REG, + FAN5_ALERT_REG, + FAN6_ALERT_REG, + + I2C_BUS_ALERT_REG, + ALERT_MODE_REG, + + MONITOR_ADC_VOLTAGE_REG = 96, + + LM_0X48_TEMP_REG = 112, + LM_0X49_TEMP_REG, + LM_0X4A_TEMP_REG, + SA56004X_LOCAL_TEMP_REG, + SA56004X_REMOTE_TEMP_REG, + +}; + +#define HWMON_MCU_TEMP_NUM 5 +struct hwmon_mcu_data { + struct i2c_client *client; + int temp_max[HWMON_MCU_TEMP_NUM]; + int temp_crit[HWMON_MCU_TEMP_NUM]; + int temp_min[HWMON_MCU_TEMP_NUM]; +}; +int hwmon_temp_threshold_max[HWMON_MCU_TEMP_NUM] = {56, 65, 60, 65, 65}; +int hwmon_temp_threshold_crit[HWMON_MCU_TEMP_NUM] = {66, 75, 70, 75, 75}; +int hwmon_temp_threshold_min[HWMON_MCU_TEMP_NUM] = {4, 10, 1, 5, 4}; + + +static struct mutex pega_hwmon_mcu_lock; + +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; +static char debug[MAX_DEBUG_INFO_LEN] = "debug info: \n\ +we should set smartFan_enable to 1 instead of setting the fan ratio. \n"; + +#define MAX_FAN_NUM 6 +#define MOTOR_NUM_PER_FAN 1 + +static LIST_HEAD(mcu_client_list); +static struct mutex list_lock; + +struct mcu_client_node { + struct i2c_client *client; + struct list_head list; +}; + +static int pega_hwmon_mcu_read(struct i2c_client *client, u8 reg) +{ + int data = -EPERM; + + mutex_lock(&pega_hwmon_mcu_lock); + + data = i2c_smbus_read_word_data(client, reg); + + mutex_unlock(&pega_hwmon_mcu_lock); + + return data; +} + +static int pega_hwmon_mcu_write(struct i2c_client *client, u8 reg, u8 val) +{ + int ret = -EIO; + + mutex_lock(&pega_hwmon_mcu_lock); + + ret = i2c_smbus_write_byte_data(client, reg, val); + + mutex_unlock(&pega_hwmon_mcu_lock); + + return ret; +} +int pega_mcu_read(unsigned short addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct mcu_client_node *mcu_mode = NULL; + int data = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &mcu_client_list) + { + mcu_mode = list_entry(list_node, struct mcu_client_node, list); + + if (mcu_mode->client->addr == addr) { + //data = i2c_smbus_read_byte_data(mcu_mode->client, reg); + data = pega_hwmon_mcu_read(mcu_mode->client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", addr, reg, data); + break; + } + } + + mutex_unlock(&list_lock); + + return data; +} +EXPORT_SYMBOL(pega_mcu_read); + + +int pega_mcu_write(unsigned short addr, u8 reg, u8 val) +{ + struct list_head *list_node = NULL; + struct mcu_client_node *mcu_mode = NULL; + int ret = -EIO; + + mutex_lock(&list_lock); + + list_for_each(list_node, &mcu_client_list) + { + mcu_mode = list_entry(list_node, struct mcu_client_node, list); + + if (mcu_mode->client->addr == addr) { + //ret = i2c_smbus_write_byte_data(mcu_mode->client, reg, val); + ret = pega_hwmon_mcu_write(mcu_mode->client, reg, val); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", addr, reg, val); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(pega_mcu_write); + +static ssize_t mainBoardUpgrade(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = MB_FW_UG_REG; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + if(val) + pega_hwmon_mcu_write(client, reg, FW_UPGRADE_COMMAND); + else + pega_hwmon_mcu_write(client, reg, 0xff); + + pega_print(DEBUG,"addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, FW_UPGRADE_COMMAND); + + return count; +} + +static ssize_t fanBoardUpgrade(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = FB_FW_UG_REG; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + if(val) + pega_hwmon_mcu_write(client, reg, FW_UPGRADE_COMMAND); + else + pega_hwmon_mcu_write(client, reg, 0xff); + + pega_print(DEBUG,"addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, FW_UPGRADE_COMMAND); + + return count; +} + +static ssize_t get_MB_HW_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = MB_HW_VER_REG; + + data = pega_hwmon_mcu_read(client, reg); + + pega_print(DEBUG,"addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, FW_UPGRADE_COMMAND); + + data &= 0x1f; + + return sprintf(buf, "%02x\n", data); +} + +static ssize_t get_FB_HW_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = FB_HW_SKUVER_REG; + + data = pega_hwmon_mcu_read(client, reg); + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + data = (data >> 5) & 0x7; + + return sprintf(buf, "%02x\n", data); +} + +static ssize_t get_FB_boardId(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = FB_HW_SKUVER_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + data &= 0x1f; + + return sprintf(buf, "%02x\n", data); +} + +static ssize_t get_MB_FW_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, major_ver = 0, minor_ver = 0; + u8 reg = MB_FW_VER_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + major_ver = (data >> 4) & 0xf; + minor_ver = data & 0xf; + + return sprintf(buf, "%d.%d\n", major_ver, minor_ver); +} + +static ssize_t get_FB_FW_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, major_ver = 0, minor_ver = 0; + u8 reg = FB_FW_VER_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + major_ver = (data >> 4) & 0xf; + minor_ver = data & 0xf; + + return sprintf(buf, "%d.%d\n", major_ver, minor_ver); +} + +static ssize_t get_pwr_down(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = 0xb2; + u8 data = 0; + u8 pwr_down = 0; + + pega_hwmon_mcu_write(client, 0xB0, 0x0); + pega_hwmon_mcu_write(client, 0xB1, 0xa0); + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + pwr_down = ((data == 0xff)?0:1); + + return sprintf(buf, "0x%02x\n", pwr_down); +} + +static ssize_t get_fan_PWM(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = FAN_PWM_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_fan_pwm(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = FAN_PWM_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_enable(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = SF_ENABLE_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, SMART_FAN_ENABLE_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t set_smartFan_enable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_ENABLE_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + if(val) + SET_BIT(data, SMART_FAN_ENABLE_BIT); + else + CLEAR_BIT(data, SMART_FAN_ENABLE_BIT); + pega_hwmon_mcu_write(client, reg, data); + + return count; +} + +static ssize_t get_smartFan_setting_enable(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = SF_SETTING_ENABLE_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, SMART_FAN_SETTING_ENABLE_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t set_smartFan_setting_enable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_SETTING_ENABLE_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + if(val) + SET_BIT(data, SMART_FAN_SETTING_ENABLE_BIT); + else + CLEAR_BIT(data, SMART_FAN_SETTING_ENABLE_BIT); + pega_hwmon_mcu_write(client, reg, data); + + return count; +} + +static ssize_t get_smartFan_device(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_DEVICE_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%x\n", data); +} + +static ssize_t set_smartFan_device(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_DEVICE_REG; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_update(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_UPDATE_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_update(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_UPDATE_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_max_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_TEMP_MAX_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_max_temp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_TEMP_MAX_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_mid_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_TEMP_MID_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_mid_temp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_TEMP_MID_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_min_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_TEMP_MIN_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_min_temp(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_TEMP_MIN_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_max_pwm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_PWM_MAX_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_max_pwm(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_PWM_MAX_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_mid_pwm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_PWM_MID_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_mid_pwm(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_PWM_MID_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_smartFan_min_pwm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = SF_PWM_MIN_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_smartFan_min_pwm(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = SF_PWM_MIN_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + pega_hwmon_mcu_write(client, reg, val); + + return count; +} + +static ssize_t get_fan_inner_rpm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 data = 0; + u8 reg = FAN1_INNER_RPM_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t get_fan_outer_rpm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 data = 0; + u8 reg = FAN1_OUTER_RPM_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data); +} + +static ssize_t get_fan_airflow_dir(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, SYSTEM_AIRFLOW_DIR, val); + + return sprintf(buf, "%d\n", val); +} + + +#define FAN_ABSENT 1 +#define FAN_POWER_OK 0 + +#define KWAI_FAN_ABSENT 0 +#define KWAI_FAN_PRESENT_NORMAL 1 +#define KWAI_FAN_PRESENT_ABNORMAL 2 + +static ssize_t get_fan_present(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0,present = 0,alarm = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_PRESENT_BIT, present); + GET_BIT(data, FAN_ALERT_BIT, alarm); + + + if(present == FAN_ABSENT) + { + val = KWAI_FAN_ABSENT; + } + else + { + if(alarm == FAN_POWER_OK) + { + val = KWAI_FAN_PRESENT_NORMAL; + } + else + { + val = KWAI_FAN_PRESENT_ABNORMAL; + } + } + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t get_fan_enable(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_ENABLE_BIT, val); + + return sprintf(buf, "%d\n", val); +} + + +static ssize_t set_fan_enable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = FAN1_STATUS_REG + attr->index; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + if(val) + pega_hwmon_mcu_write(client, reg, FAN_ENABLE_COMMAND); + else + pega_hwmon_mcu_write(client, reg, FAN_DISABLE_COMMAND); + + return count; +} + +static ssize_t get_fan_led_auto(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_LED_AUTO_BIT, val); + + return sprintf(buf, "%d\n", val); +} + + +static ssize_t set_fan_led_auto(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = FAN1_STATUS_REG + attr->index; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + if(val) + pega_hwmon_mcu_write(client, reg, FAN_LED_SETTO_AUTO_COMMAND); + else + pega_hwmon_mcu_write(client, reg, FAN_LED_SETTO_MANUAL_COMMAND); + + return count; +} + +static ssize_t get_fan_led_green(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_LED_GREEN_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_led_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + //Kwai's requirement + if(data & (1 << FAN_LED_GREEN_BIT)) + { + val = 1; + } + else if(data & (1 << FAN_LED_AMBER_BIT)) + { + val = 3; + } + + return sprintf(buf, "%d\n", val); +} + +static ssize_t set_fan_led_green(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = FAN1_STATUS_REG + attr->index; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + if(val) + pega_hwmon_mcu_write(client, reg, FAN_LED_GREENON_COMMAND); + else + pega_hwmon_mcu_write(client, reg, FAN_LED_GREENOFF_COMMAND); + + return count; +} + +static ssize_t get_fan_led_amber(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_LED_AMBER_BIT, val); + + return sprintf(buf, "%d\n", val); +} + + +static ssize_t set_fan_led_amber(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 reg = FAN1_STATUS_REG + attr->index; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + if(val) + pega_hwmon_mcu_write(client, reg, FAN_LED_AMBERON_COMMAND); + else + pega_hwmon_mcu_write(client, reg, FAN_LED_AMBEROFF_COMMAND); + + return count; +} + +static ssize_t get_fan_status_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_STATUS_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_adc_under_vol_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = ADC_UNDER_VOL_ALERT_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, attr->index, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_adc_over_vol_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = ADC_OVER_VOL_ALERT_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, attr->index, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_temp_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = TS_OVER_TEMP_ALERT_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, attr->index, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_wrong_airflow_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_WRONG_AIRFLOW, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_outerRPMOver_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_OUTER_RPM_OVER_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_outerRPMUnder_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_OUTER_RPM_UNDER_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_outerRPMZero_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_OUTER_RPM_ZERO_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_innerRPMOver_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_INNER_RPM_OVER_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_innerRPMUnder_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_INNER_RPM_UNDER_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_innerRPMZero_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_INNER_RPM_ZERO_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_fan_notconnect_alert(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = FAN1_ALERT_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, FAN_NOTCONNECT_ALERT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_i2c_timeout(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = I2C_BUS_ALERT_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, (I2C_FANBOARD_TIMEOUT_BIT + attr->index), val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_alert_mode(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, val = 0; + u8 reg = ALERT_MODE_REG; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, ALERT_MODE_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t set_alert_mode(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = ALERT_MODE_REG; + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %lx\r\n", client->addr, reg, val); + + if(val) + SET_BIT(data, ALERT_MODE_BIT); + else + CLEAR_BIT(data, ALERT_MODE_BIT); + pega_hwmon_mcu_write(client, reg, data); + + return count; +} + +static ssize_t get_adc_vol(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 data = 0, reg = MONITOR_ADC_VOLTAGE_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d.%02d\n", data/1000, data%1000); +} + +static ssize_t get_hwmon_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0; + u8 reg = LM_0X48_TEMP_REG + attr->index; + + data = pega_hwmon_mcu_read(client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%d\n", data*1000); +} +static ssize_t get_label(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + return sprintf(buf, "temp%d\n", attr->index); +} + +static ssize_t get_hwmon_temp_min(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", drv_data->temp_min[attr->index]); +} + +static ssize_t get_hwmon_temp_max(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", drv_data->temp_max[attr->index]); +} +static ssize_t set_hwmon_temp_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + drv_data->temp_max[attr->index] = val; + return count; +} +static ssize_t get_hwmon_temp_crit(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", drv_data->temp_crit[attr->index]); +} +static ssize_t set_hwmon_temp_crit(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct hwmon_mcu_data *drv_data = dev_get_drvdata(dev); + long val = 0; + + if (kstrtol(buf, 10, &val)) + { + return -EINVAL; + } + + drv_data->temp_crit[attr->index] = val; + return count; +} + +static ssize_t get_total_fan_num(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "%d\n", MAX_FAN_NUM); +} +static ssize_t get_motor_num(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "%d\n", MOTOR_NUM_PER_FAN); +} +static ssize_t get_fan_model_name(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "XG40561BX-1Q313-S9H"); +} +static ssize_t get_fan_serial_num(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "N/A"); +} +static ssize_t get_fan_vendor(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "SUNON"); +} +static ssize_t get_fan_part_num(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "N/A"); +} +static ssize_t get_fan_hard_version(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "1.0"); +} +static ssize_t get_fan_motor_speed_target(struct device *dev, + struct device_attribute *da, char *buf) +{ + return sprintf(buf, "27500"); +} +static ssize_t get_fan_motor_speed_tolerance(struct device *dev, + struct device_attribute *da, char *buf) +{ + //10 percentage + return sprintf(buf, "2750"); +} +#define SET_FAN_ATTR(_num) \ + static SENSOR_DEVICE_ATTR(fan##_num##_inner_rpm, S_IRUGO, get_fan_inner_rpm, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_outer_rpm, S_IRUGO, get_fan_outer_rpm, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_present, S_IRUGO, get_fan_present, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_enable, S_IRUGO | S_IWUSR, get_fan_enable, set_fan_enable, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_led_auto, S_IRUGO | S_IWUSR, get_fan_led_auto, set_fan_led_auto, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_led_status, S_IRUGO, get_fan_led_status, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_led_green, S_IRUGO | S_IWUSR, get_fan_led_green, set_fan_led_green, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_led_amber, S_IRUGO | S_IWUSR, get_fan_led_amber, set_fan_led_amber, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_status_alert, S_IRUGO, get_fan_status_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_wrongAirflow_alert, S_IRUGO, get_fan_wrong_airflow_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_outerRPMOver_alert, S_IRUGO, get_fan_outerRPMOver_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_outerRPMUnder_alert, S_IRUGO, get_fan_outerRPMUnder_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_outerRPMZero_alert, S_IRUGO, get_fan_outerRPMZero_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_innerRPMOver_alert, S_IRUGO, get_fan_innerRPMOver_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_innerRPMUnder_alert, S_IRUGO, get_fan_innerRPMUnder_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_innerRPMZero_alert, S_IRUGO, get_fan_innerRPMZero_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_notconnect_alert, S_IRUGO, get_fan_notconnect_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(fan##_num##_airflow_dir, S_IRUGO, get_fan_airflow_dir, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_motor_num, S_IRUGO, get_motor_num, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_model_name, S_IRUGO, get_fan_model_name, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_serial_num, S_IRUGO, get_fan_serial_num, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_vendor, S_IRUGO, get_fan_vendor, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_part_num, S_IRUGO, get_fan_part_num, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_hard_version, S_IRUGO, get_fan_hard_version, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_speed_target, S_IRUGO, get_fan_motor_speed_target, NULL, _num-1);\ + static SENSOR_DEVICE_ATTR(fan##_num##_speed_tolerance, S_IRUGO, get_fan_motor_speed_tolerance, NULL, _num-1); + + + +SET_FAN_ATTR(1);SET_FAN_ATTR(2);SET_FAN_ATTR(3);SET_FAN_ATTR(4);SET_FAN_ATTR(5);SET_FAN_ATTR(6); + +#define SET_ADC_ATTR(_num) \ + static SENSOR_DEVICE_ATTR(ADC##_num##_under_alert, S_IRUGO, get_adc_under_vol_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(ADC##_num##_over_alert, S_IRUGO, get_adc_over_vol_alert, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(ADC##_num##_vol, S_IRUGO, get_adc_vol, NULL, _num-1) + +SET_ADC_ATTR(1);SET_ADC_ATTR(2);SET_ADC_ATTR(3);SET_ADC_ATTR(4);SET_ADC_ATTR(5);SET_ADC_ATTR(6);SET_ADC_ATTR(7);SET_ADC_ATTR(8); + +static SENSOR_DEVICE_ATTR(mb_fw_upgrade, S_IWUSR, NULL, mainBoardUpgrade, 0); +static SENSOR_DEVICE_ATTR(fb_fw_upgrade, S_IWUSR, NULL, fanBoardUpgrade, 0); +static SENSOR_DEVICE_ATTR(mb_hw_version, S_IRUGO, get_MB_HW_version, NULL, 0); +static SENSOR_DEVICE_ATTR(fb_hw_version, S_IRUGO, get_FB_HW_version, NULL, 0); +static SENSOR_DEVICE_ATTR(fb_board_id, S_IRUGO, get_FB_boardId, NULL, 0); +static SENSOR_DEVICE_ATTR(mb_fw_version, S_IRUGO, get_MB_FW_version, NULL, 0); +static SENSOR_DEVICE_ATTR(fb_fw_version, S_IRUGO, get_FB_FW_version, NULL, 0); +static SENSOR_DEVICE_ATTR(fan_pwm, S_IRUGO | S_IWUSR, get_fan_PWM, set_fan_pwm, 0); +static SENSOR_DEVICE_ATTR(pwr_down, S_IRUGO, get_pwr_down, NULL, 0); + +static SENSOR_DEVICE_ATTR(smartFan_enable, S_IRUGO | S_IWUSR, get_smartFan_enable, set_smartFan_enable, 0); +static SENSOR_DEVICE_ATTR(smartFan_setting_enable, S_IRUGO | S_IWUSR, get_smartFan_setting_enable, set_smartFan_setting_enable, 0); +static SENSOR_DEVICE_ATTR(smartFan_device, S_IRUGO | S_IWUSR, get_smartFan_device, set_smartFan_device, 0); +static SENSOR_DEVICE_ATTR(smartFan_update, S_IRUGO | S_IWUSR, get_smartFan_update, set_smartFan_update, 0); +static SENSOR_DEVICE_ATTR(smartFan_max_temp, S_IRUGO | S_IWUSR, get_smartFan_max_temp, set_smartFan_max_temp, 0); +static SENSOR_DEVICE_ATTR(smartFan_mid_temp, S_IRUGO | S_IWUSR, get_smartFan_mid_temp, set_smartFan_mid_temp, 0); +static SENSOR_DEVICE_ATTR(smartFan_min_temp, S_IRUGO | S_IWUSR, get_smartFan_min_temp, set_smartFan_min_temp, 0); +static SENSOR_DEVICE_ATTR(smartFan_max_pwm, S_IRUGO | S_IWUSR, get_smartFan_max_pwm, set_smartFan_max_pwm, 0); +static SENSOR_DEVICE_ATTR(smartFan_mid_pwm, S_IRUGO | S_IWUSR, get_smartFan_mid_pwm, set_smartFan_mid_pwm, 0); +static SENSOR_DEVICE_ATTR(smartFan_min_pwm, S_IRUGO | S_IWUSR, get_smartFan_min_pwm, set_smartFan_min_pwm, 0); + +static SENSOR_DEVICE_ATTR(lm75_48_temp_alert, S_IRUGO, get_temp_alert, NULL, 5); +static SENSOR_DEVICE_ATTR(lm75_49_temp_alert, S_IRUGO, get_temp_alert, NULL, 4); +static SENSOR_DEVICE_ATTR(lm75_4a_temp_alert, S_IRUGO, get_temp_alert, NULL, 3); +static SENSOR_DEVICE_ATTR(sa56004x_Ltemp_alert, S_IRUGO, get_temp_alert, NULL, 2); +static SENSOR_DEVICE_ATTR(sa56004x_Rtemp_alert, S_IRUGO, get_temp_alert, NULL, 1); +static SENSOR_DEVICE_ATTR(fanBoard_alert, S_IRUGO, get_temp_alert, NULL, 0); + +static SENSOR_DEVICE_ATTR(i2c_fb_timeout, S_IRUGO, get_i2c_timeout, NULL, 0); +static SENSOR_DEVICE_ATTR(i2c_remote_timeout, S_IRUGO, get_i2c_timeout, NULL, 1); +static SENSOR_DEVICE_ATTR(i2c_local_timeout, S_IRUGO, get_i2c_timeout, NULL, 2); +static SENSOR_DEVICE_ATTR(i2c_lm75_48_timeout, S_IRUGO, get_i2c_timeout, NULL, 3); +static SENSOR_DEVICE_ATTR(i2c_lm75_49_timeout, S_IRUGO, get_i2c_timeout, NULL, 4); +static SENSOR_DEVICE_ATTR(alert_mode, S_IRUGO | S_IWUSR, get_alert_mode, set_alert_mode, 0); + +static SENSOR_DEVICE_ATTR(fan_num, S_IRUGO, get_total_fan_num, NULL, 0); + +#define SET_TEMP_ATTR(_num) \ + static SENSOR_DEVICE_ATTR(temp##_num##_input, S_IRUGO, get_hwmon_temp, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_label, S_IRUGO, get_label, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_min, S_IRUGO, get_hwmon_temp_min, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_max, S_IRUGO, get_hwmon_temp_max, set_hwmon_temp_max, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_crit, S_IRUGO, get_hwmon_temp_crit, set_hwmon_temp_crit, _num-1); + +SET_TEMP_ATTR(1);SET_TEMP_ATTR(2);SET_TEMP_ATTR(3);SET_TEMP_ATTR(4);SET_TEMP_ATTR(5); + +static struct attribute *pega_hwmon_mcu_attrs[] = { + &sensor_dev_attr_mb_fw_upgrade.dev_attr.attr, + &sensor_dev_attr_fb_fw_upgrade.dev_attr.attr, + &sensor_dev_attr_mb_hw_version.dev_attr.attr, + &sensor_dev_attr_fb_hw_version.dev_attr.attr, + &sensor_dev_attr_fb_board_id.dev_attr.attr, + &sensor_dev_attr_mb_fw_version.dev_attr.attr, + &sensor_dev_attr_fb_fw_version.dev_attr.attr, + &sensor_dev_attr_fan_pwm.dev_attr.attr, + &sensor_dev_attr_pwr_down.dev_attr.attr, + + &sensor_dev_attr_smartFan_enable.dev_attr.attr, + &sensor_dev_attr_smartFan_setting_enable.dev_attr.attr, + &sensor_dev_attr_smartFan_device.dev_attr.attr, + &sensor_dev_attr_smartFan_update.dev_attr.attr, + &sensor_dev_attr_smartFan_max_temp.dev_attr.attr, + &sensor_dev_attr_smartFan_mid_temp.dev_attr.attr, + &sensor_dev_attr_smartFan_min_temp.dev_attr.attr, + &sensor_dev_attr_smartFan_max_pwm.dev_attr.attr, + &sensor_dev_attr_smartFan_mid_pwm.dev_attr.attr, + &sensor_dev_attr_smartFan_min_pwm.dev_attr.attr, + + &sensor_dev_attr_fan1_inner_rpm.dev_attr.attr, + &sensor_dev_attr_fan2_inner_rpm.dev_attr.attr, + &sensor_dev_attr_fan3_inner_rpm.dev_attr.attr, + &sensor_dev_attr_fan4_inner_rpm.dev_attr.attr, + &sensor_dev_attr_fan5_inner_rpm.dev_attr.attr, + &sensor_dev_attr_fan6_inner_rpm.dev_attr.attr, + + &sensor_dev_attr_fan1_outer_rpm.dev_attr.attr, + &sensor_dev_attr_fan2_outer_rpm.dev_attr.attr, + &sensor_dev_attr_fan3_outer_rpm.dev_attr.attr, + &sensor_dev_attr_fan4_outer_rpm.dev_attr.attr, + &sensor_dev_attr_fan5_outer_rpm.dev_attr.attr, + &sensor_dev_attr_fan6_outer_rpm.dev_attr.attr, + + &sensor_dev_attr_fan1_present.dev_attr.attr, + &sensor_dev_attr_fan2_present.dev_attr.attr, + &sensor_dev_attr_fan3_present.dev_attr.attr, + &sensor_dev_attr_fan4_present.dev_attr.attr, + &sensor_dev_attr_fan5_present.dev_attr.attr, + &sensor_dev_attr_fan6_present.dev_attr.attr, + + &sensor_dev_attr_fan1_enable.dev_attr.attr, + &sensor_dev_attr_fan2_enable.dev_attr.attr, + &sensor_dev_attr_fan3_enable.dev_attr.attr, + &sensor_dev_attr_fan4_enable.dev_attr.attr, + &sensor_dev_attr_fan5_enable.dev_attr.attr, + &sensor_dev_attr_fan6_enable.dev_attr.attr, + + &sensor_dev_attr_fan1_led_auto.dev_attr.attr, + &sensor_dev_attr_fan2_led_auto.dev_attr.attr, + &sensor_dev_attr_fan3_led_auto.dev_attr.attr, + &sensor_dev_attr_fan4_led_auto.dev_attr.attr, + &sensor_dev_attr_fan5_led_auto.dev_attr.attr, + &sensor_dev_attr_fan6_led_auto.dev_attr.attr, + + &sensor_dev_attr_fan1_led_status.dev_attr.attr, + &sensor_dev_attr_fan2_led_status.dev_attr.attr, + &sensor_dev_attr_fan3_led_status.dev_attr.attr, + &sensor_dev_attr_fan4_led_status.dev_attr.attr, + &sensor_dev_attr_fan5_led_status.dev_attr.attr, + &sensor_dev_attr_fan6_led_status.dev_attr.attr, + + &sensor_dev_attr_fan1_led_green.dev_attr.attr, + &sensor_dev_attr_fan2_led_green.dev_attr.attr, + &sensor_dev_attr_fan3_led_green.dev_attr.attr, + &sensor_dev_attr_fan4_led_green.dev_attr.attr, + &sensor_dev_attr_fan5_led_green.dev_attr.attr, + &sensor_dev_attr_fan6_led_green.dev_attr.attr, + + &sensor_dev_attr_fan1_led_amber.dev_attr.attr, + &sensor_dev_attr_fan2_led_amber.dev_attr.attr, + &sensor_dev_attr_fan3_led_amber.dev_attr.attr, + &sensor_dev_attr_fan4_led_amber.dev_attr.attr, + &sensor_dev_attr_fan5_led_amber.dev_attr.attr, + &sensor_dev_attr_fan6_led_amber.dev_attr.attr, + + &sensor_dev_attr_fan1_status_alert.dev_attr.attr, + &sensor_dev_attr_fan2_status_alert.dev_attr.attr, + &sensor_dev_attr_fan3_status_alert.dev_attr.attr, + &sensor_dev_attr_fan4_status_alert.dev_attr.attr, + &sensor_dev_attr_fan5_status_alert.dev_attr.attr, + &sensor_dev_attr_fan6_status_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_airflow_dir.dev_attr.attr, + &sensor_dev_attr_fan2_airflow_dir.dev_attr.attr, + &sensor_dev_attr_fan3_airflow_dir.dev_attr.attr, + &sensor_dev_attr_fan4_airflow_dir.dev_attr.attr, + &sensor_dev_attr_fan5_airflow_dir.dev_attr.attr, + &sensor_dev_attr_fan6_airflow_dir.dev_attr.attr, + + &sensor_dev_attr_fan1_motor_num.dev_attr.attr, + &sensor_dev_attr_fan2_motor_num.dev_attr.attr, + &sensor_dev_attr_fan3_motor_num.dev_attr.attr, + &sensor_dev_attr_fan4_motor_num.dev_attr.attr, + &sensor_dev_attr_fan5_motor_num.dev_attr.attr, + &sensor_dev_attr_fan6_motor_num.dev_attr.attr, + + &sensor_dev_attr_fan1_model_name.dev_attr.attr, + &sensor_dev_attr_fan2_model_name.dev_attr.attr, + &sensor_dev_attr_fan3_model_name.dev_attr.attr, + &sensor_dev_attr_fan4_model_name.dev_attr.attr, + &sensor_dev_attr_fan5_model_name.dev_attr.attr, + &sensor_dev_attr_fan6_model_name.dev_attr.attr, + + &sensor_dev_attr_fan1_serial_num.dev_attr.attr, + &sensor_dev_attr_fan2_serial_num.dev_attr.attr, + &sensor_dev_attr_fan3_serial_num.dev_attr.attr, + &sensor_dev_attr_fan4_serial_num.dev_attr.attr, + &sensor_dev_attr_fan5_serial_num.dev_attr.attr, + &sensor_dev_attr_fan6_serial_num.dev_attr.attr, + + &sensor_dev_attr_fan1_vendor.dev_attr.attr, + &sensor_dev_attr_fan2_vendor.dev_attr.attr, + &sensor_dev_attr_fan3_vendor.dev_attr.attr, + &sensor_dev_attr_fan4_vendor.dev_attr.attr, + &sensor_dev_attr_fan5_vendor.dev_attr.attr, + &sensor_dev_attr_fan6_vendor.dev_attr.attr, + + &sensor_dev_attr_fan1_part_num.dev_attr.attr, + &sensor_dev_attr_fan2_part_num.dev_attr.attr, + &sensor_dev_attr_fan3_part_num.dev_attr.attr, + &sensor_dev_attr_fan4_part_num.dev_attr.attr, + &sensor_dev_attr_fan5_part_num.dev_attr.attr, + &sensor_dev_attr_fan6_part_num.dev_attr.attr, + + &sensor_dev_attr_fan1_hard_version.dev_attr.attr, + &sensor_dev_attr_fan2_hard_version.dev_attr.attr, + &sensor_dev_attr_fan3_hard_version.dev_attr.attr, + &sensor_dev_attr_fan4_hard_version.dev_attr.attr, + &sensor_dev_attr_fan5_hard_version.dev_attr.attr, + &sensor_dev_attr_fan6_hard_version.dev_attr.attr, + + &sensor_dev_attr_fan1_speed_target.dev_attr.attr, + &sensor_dev_attr_fan2_speed_target.dev_attr.attr, + &sensor_dev_attr_fan3_speed_target.dev_attr.attr, + &sensor_dev_attr_fan4_speed_target.dev_attr.attr, + &sensor_dev_attr_fan5_speed_target.dev_attr.attr, + &sensor_dev_attr_fan6_speed_target.dev_attr.attr, + + &sensor_dev_attr_fan1_speed_tolerance.dev_attr.attr, + &sensor_dev_attr_fan2_speed_tolerance.dev_attr.attr, + &sensor_dev_attr_fan3_speed_tolerance.dev_attr.attr, + &sensor_dev_attr_fan4_speed_tolerance.dev_attr.attr, + &sensor_dev_attr_fan5_speed_tolerance.dev_attr.attr, + &sensor_dev_attr_fan6_speed_tolerance.dev_attr.attr, + + &sensor_dev_attr_fan_num.dev_attr.attr, + &sensor_dev_attr_ADC1_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC2_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC3_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC4_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC5_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC6_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC7_under_alert.dev_attr.attr, + &sensor_dev_attr_ADC8_under_alert.dev_attr.attr, + + &sensor_dev_attr_ADC1_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC2_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC3_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC4_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC5_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC6_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC7_over_alert.dev_attr.attr, + &sensor_dev_attr_ADC8_over_alert.dev_attr.attr, + + &sensor_dev_attr_lm75_48_temp_alert.dev_attr.attr, + &sensor_dev_attr_lm75_49_temp_alert.dev_attr.attr, + &sensor_dev_attr_lm75_4a_temp_alert.dev_attr.attr, + &sensor_dev_attr_sa56004x_Ltemp_alert.dev_attr.attr, + &sensor_dev_attr_sa56004x_Rtemp_alert.dev_attr.attr, + &sensor_dev_attr_fanBoard_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_wrongAirflow_alert.dev_attr.attr, + &sensor_dev_attr_fan2_wrongAirflow_alert.dev_attr.attr, + &sensor_dev_attr_fan3_wrongAirflow_alert.dev_attr.attr, + &sensor_dev_attr_fan4_wrongAirflow_alert.dev_attr.attr, + &sensor_dev_attr_fan5_wrongAirflow_alert.dev_attr.attr, + &sensor_dev_attr_fan6_wrongAirflow_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_outerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan2_outerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan3_outerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan4_outerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan5_outerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan6_outerRPMOver_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_outerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan2_outerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan3_outerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan4_outerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan5_outerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan6_outerRPMUnder_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_outerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan2_outerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan3_outerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan4_outerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan5_outerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan6_outerRPMZero_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_innerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan2_innerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan3_innerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan4_innerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan5_innerRPMOver_alert.dev_attr.attr, + &sensor_dev_attr_fan6_innerRPMOver_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_innerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan2_innerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan3_innerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan4_innerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan5_innerRPMUnder_alert.dev_attr.attr, + &sensor_dev_attr_fan6_innerRPMUnder_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_innerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan2_innerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan3_innerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan4_innerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan5_innerRPMZero_alert.dev_attr.attr, + &sensor_dev_attr_fan6_innerRPMZero_alert.dev_attr.attr, + + &sensor_dev_attr_fan1_notconnect_alert.dev_attr.attr, + &sensor_dev_attr_fan2_notconnect_alert.dev_attr.attr, + &sensor_dev_attr_fan3_notconnect_alert.dev_attr.attr, + &sensor_dev_attr_fan4_notconnect_alert.dev_attr.attr, + &sensor_dev_attr_fan5_notconnect_alert.dev_attr.attr, + &sensor_dev_attr_fan6_notconnect_alert.dev_attr.attr, + + &sensor_dev_attr_i2c_fb_timeout.dev_attr.attr, + &sensor_dev_attr_i2c_remote_timeout.dev_attr.attr, + &sensor_dev_attr_i2c_local_timeout.dev_attr.attr, + &sensor_dev_attr_i2c_lm75_48_timeout.dev_attr.attr, + &sensor_dev_attr_i2c_lm75_49_timeout.dev_attr.attr, + &sensor_dev_attr_alert_mode.dev_attr.attr, + + &sensor_dev_attr_ADC1_vol.dev_attr.attr, + &sensor_dev_attr_ADC2_vol.dev_attr.attr, + &sensor_dev_attr_ADC3_vol.dev_attr.attr, + &sensor_dev_attr_ADC4_vol.dev_attr.attr, + &sensor_dev_attr_ADC5_vol.dev_attr.attr, + &sensor_dev_attr_ADC6_vol.dev_attr.attr, + &sensor_dev_attr_ADC7_vol.dev_attr.attr, + &sensor_dev_attr_ADC8_vol.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp4_input.dev_attr.attr, + &sensor_dev_attr_temp5_input.dev_attr.attr, + + &sensor_dev_attr_temp1_label.dev_attr.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, + &sensor_dev_attr_temp3_label.dev_attr.attr, + &sensor_dev_attr_temp4_label.dev_attr.attr, + &sensor_dev_attr_temp5_label.dev_attr.attr, + + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp4_max.dev_attr.attr, + &sensor_dev_attr_temp5_max.dev_attr.attr, + + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + &sensor_dev_attr_temp4_crit.dev_attr.attr, + &sensor_dev_attr_temp5_crit.dev_attr.attr, + + NULL +}; + +//static const struct attribute_group pega_hwmon_mcu_group = { .attrs = pega_hwmon_mcu_attributes}; +ATTRIBUTE_GROUPS(pega_hwmon_mcu); + +static void pega_hwmon_mcu_add_client(struct i2c_client *client) +{ + struct mcu_client_node *node = kzalloc(sizeof(struct mcu_client_node), GFP_KERNEL); + + if (!node) { + pega_print(ERR, "Can't allocate mcu_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &mcu_client_list); + mutex_unlock(&list_lock); + pega_print(INFO, "mcu client list added.\n"); +} + +static void pega_hwmon_mcu_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct mcu_client_node *mcu_mode = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &mcu_client_list) + { + mcu_mode = list_entry(list_node, struct mcu_client_node, list); + + if (mcu_mode->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(mcu_mode); + } + + mutex_unlock(&list_lock); + pega_print(INFO, "mcu client list removed.\n"); +} + + + +static int pega_hwmon_mcu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int i; + struct device *dev = &client->dev; + struct hwmon_mcu_data *data; + struct device *hwmon_dev; + + data = devm_kzalloc(dev, sizeof(struct hwmon_mcu_data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + data->client = client; + + for (i = 0; i < HWMON_MCU_TEMP_NUM; i++) { + data->temp_max[i] = hwmon_temp_threshold_max[i] * 1000; + data->temp_crit[i] = hwmon_temp_threshold_crit[i] * 1000; + data->temp_min[i] = hwmon_temp_threshold_min[i] * 1000; + } + + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, pega_hwmon_mcu_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + //pega_hwmon_mcu_add_client(client); + pega_print(INFO, "chip found\n"); + + return 0; +} + +static int pega_hwmon_mcu_remove(struct i2c_client *client) +{ + //pega_hwmon_mcu_remove_client(client); + return 0; +} + +static const struct i2c_device_id pega_hwmon_mcu_id[] = { + { "pega_hwmon_mcu", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pega_hwmon_mcu_id); + +static struct i2c_driver pega_hwmon_mcu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "pegatron_hwmon_mcu", + }, + .probe = pega_hwmon_mcu_probe, + .remove = pega_hwmon_mcu_remove, + .id_table = pega_hwmon_mcu_id, +}; + +static int __init pega_hwmon_mcu_init(void) +{ + mutex_init(&pega_hwmon_mcu_lock); + mutex_init(&list_lock); + + return i2c_add_driver(&pega_hwmon_mcu_driver); +} + +static void __exit pega_hwmon_mcu_exit(void) +{ + i2c_del_driver(&pega_hwmon_mcu_driver); +} + +module_param(loglevel, uint, 0644); +module_param_string(debug, debug, MAX_DEBUG_INFO_LEN, 0644); +MODULE_PARM_DESC(loglevel,"0x01-LOG_ERR,0x02-LOG_WARNING,0x04-LOG_INFO,0x08-LOG_DEBUG"); +MODULE_PARM_DESC(debug,"help info"); + +MODULE_AUTHOR("Peter5 Lin "); +MODULE_DESCRIPTION("pega_hwmon_mcu driver"); +MODULE_LICENSE("GPL"); + +module_init(pega_hwmon_mcu_init); +module_exit(pega_hwmon_mcu_exit); diff --git a/platform/clounix/sonic-platform-modules-pegatron/common/modules/pub/pegatron_pub.h b/platform/clounix/sonic-platform-modules-pegatron/common/modules/pub/pegatron_pub.h new file mode 100644 index 000000000000..29784aa83dc9 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/common/modules/pub/pegatron_pub.h @@ -0,0 +1,42 @@ + +#ifndef __PEGATRON_PUB_H__ +#define __PEGATRON_PUB_H__ + +#include + +#ifndef KBUILD_MODNAME +#define KBUILD_MODNAME __FILE__ +#endif + +#ifdef pr_fmt +#undef pr_fmt +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ +enum log_level +{ + LOG_ERR = 0x01, + LOG_WARNING = 0x02, + LOG_INFO = 0x04, + LOG_DEBUG = 0x08, +}; + +#define pega_print(level, fmt, ...) \ + do \ + { \ + if (LOG_##level & loglevel) \ + printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ + } while (0) + + +#define MAX_DEBUG_INFO_LEN 1024 + +#endif diff --git a/platform/clounix/sonic-platform-modules-pegatron/debian/changelog b/platform/clounix/sonic-platform-modules-pegatron/debian/changelog new file mode 100644 index 000000000000..1c60b2d58336 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/debian/changelog @@ -0,0 +1,5 @@ +sonic-pegatron-platform-modules (1.0.0) unstable; urgency=low + + * Add fn8656-bnf + + -- Pegatron Wed, 13 May 2020 17:41:32 +0800 diff --git a/platform/clounix/sonic-platform-modules-pegatron/debian/compat b/platform/clounix/sonic-platform-modules-pegatron/debian/compat new file mode 100644 index 000000000000..ec635144f600 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/debian/compat @@ -0,0 +1 @@ +9 diff --git a/platform/clounix/sonic-platform-modules-pegatron/debian/control b/platform/clounix/sonic-platform-modules-pegatron/debian/control new file mode 100755 index 000000000000..6481c8de0f08 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/debian/control @@ -0,0 +1,11 @@ +Source: sonic-pegatron-platform-modules +Section: main +Priority: extra +Maintainer: Pegatron +Build-Depends: debhelper (>= 8.0.0), bzip2 +Standards-Version: 3.9.3 + +Package: sonic-platform-pegatron-fn8656-bnf +Architecture: amd64 +Description: kernel modules for platform devices such as fan, led, sfp + diff --git a/platform/clounix/sonic-platform-modules-pegatron/debian/rules b/platform/clounix/sonic-platform-modules-pegatron/debian/rules new file mode 100755 index 000000000000..e3a8a7ea07a7 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/debian/rules @@ -0,0 +1,162 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. + +include /usr/share/dpkg/pkg-info.mk + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +export INSTALL_MOD_DIR:=extra + +PYTHON ?= python2 + +PACKAGE_PRE_NAME := sonic-platform-pegatron +KVERSION ?= $(shell uname -r) +KERNEL_SRC := /lib/modules/$(KVERSION) +MOD_SRC_DIR:= $(shell pwd) +MODULE_DIRS:= fn8656-bnf +MODULE_DIR := modules +UTILS_DIR := utils +SERVICE_DIR := service +SCRIPTS_DIR := scripts +BIOS_DIR := bios_bin +CONF_DIR := conf +PROCESS_DIR := pegaProcess +IXGBE_VERSION := 5.9.4 + +MODULE_CFLAGS:=-I$(MOD_SRC_DIR)/common/modules/pub +# For fn8032-bnf/fn8032-bnf ixgbe driver, maurice + +%: + dh $@ --with systemd,python2,python3 --buildsystem=pybuild + +clean: + dh_testdir + dh_testroot + dh_clean + +build: + # For fn8032-bnf ixgbe driver, maurice + make clean -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/common/modules; \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/common/modules EXTRA_CFLAGS+=${MODULE_CFLAGS}; \ + (for mod in $(MODULE_DIRS); do \ + if [ $$mod = "fn8656-bnf" ]; then \ + make clean -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules EXTRA_CFLAGS+=${MODULE_CFLAGS}; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2 setup.py build; \ + python2 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ + python3 setup.py build; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ + cd $(MOD_SRC_DIR); \ + cd $(MOD_SRC_DIR); \ + fi; \ + if [ $$mod = "fn8032-bnf" ]; then \ + make clean -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules EXTRA_CFLAGS+=${MODULE_CFLAGS}; \ + cd $(MOD_SRC_DIR)/$${mod}; \ + python2 setup.py build; \ + python2 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ + python3 setup.py build; \ + python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/utils; \ + cd $(MOD_SRC_DIR); \ + cd $(MOD_SRC_DIR); \ + fi; \ + if [ $$mod = "fn6254-dnf" ]; then \ + # For fn6254-dnf ixgbe driver \ + rm -rf ./ixgbe-$(IXGBE_VERSION); \ + wget -O ixgbe.tar.gz "https://downloadmirror.intel.com/30240/eng/ixgbe-5.9.4.tar.gz"; \ + tar xzf ixgbe.tar.gz; \ + rm ixgbe-$(IXGBE_VERSION)/src/Makefile ixgbe-$(IXGBE_VERSION)/src/common.mk ixgbe-$(IXGBE_VERSION)/src/Module.supported; \ + git init ixgbe-$(IXGBE_VERSION)/src; \ + git --git-dir=./ixgbe-$(IXGBE_VERSION)/src/.git --work-tree=ixgbe-$(IXGBE_VERSION)/src add --all; \ + git --git-dir=./ixgbe-$(IXGBE_VERSION)/src/.git --work-tree=ixgbe-$(IXGBE_VERSION)/src commit -m "unmodified ixgbe source"; \ + cp ./fn6254-dnf/modules/pegatron_fn6254_dnf_ixgbe/*.patch ./ixgbe-$(IXGBE_VERSION)/src/; \ + git --git-dir=./ixgbe-$(IXGBE_VERSION)/src/.git --work-tree=ixgbe-$(IXGBE_VERSION)/src am 0001-Add-clounix-porting-driver.patch; \ + cp ./ixgbe-$(IXGBE_VERSION)/src/* $(MOD_SRC_DIR)/fn6254-dnf/$(MODULE_DIR)/pegatron_fn6254_dnf_ixgbe/; \ + make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \ + fi; \ + done) + + # Build afulnx_64 for SONiC + (for mod in $(MODULE_DIRS); do \ + cd $(MOD_SRC_DIR)/$${mod}/$(BIOS_DIR); \ + ./afulnx_64 /GENDRV KERNEL=$(KERNEL_SRC)/build .;\ + ./afulnx_64 /MAKEDRV KERNEL=$(KERNEL_SRC)/build .;\ + make KERNEL=$(KERNEL_SRC)/build;\ + cd $(MOD_SRC_DIR); \ + done) + + +binary: binary-arch binary-indep + # Nothing to do + +binary-arch: + # Nothing to do + +#install: build + #dh_testdir + #dh_testroot + #dh_clean -k + #dh_installdirs + +binary-indep: + dh_testdir + dh_installdirs + + # Custom package commands + (for mod in $(MODULE_DIRS); do \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/local/bin; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/local/bin/${PROCESS_DIR}; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/bin; \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /lib/systemd/system; \ + cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + cp $(MOD_SRC_DIR)/common/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SCRIPTS_DIR)/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/${PROCESS_DIR}/* debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/${PROCESS_DIR}; \ + if [ $$mod = "fn8656-bnf" ]; then \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/share/sonic/device/x86_64-pegatron_fn8656_bnf-r0; \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/*.whl debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/share/sonic/device/x86_64-pegatron_fn8656_bnf-r0; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SCRIPTS_DIR)/platform_update_reboot_cause debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/share/sonic/device/x86_64-pegatron_fn8656_bnf-r0; \ + # Add bios upgrade tool to device(usr/local/bin), maurice 20201125 \ + cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/platform_api_mgnt.sh debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + fi; \ + if [ $$mod = "fn8032-bnf" ]; then \ + dh_installdirs -p$(PACKAGE_PRE_NAME)-$${mod} /usr/share/sonic/device/x86_64-pegatron_fn8032_bnf-r0; \ + cp $(MOD_SRC_DIR)/$${mod}/$(UTILS_DIR)/*.whl debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/share/sonic/device/x86_64-pegatron_fn8032_bnf-r0; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SCRIPTS_DIR)/platform_update_reboot_cause debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/share/sonic/device/x86_64-pegatron_fn8032_bnf-r0; \ + # Add bios upgrade tool to device(usr/local/bin), maurice 20201125 \ + cp -r $(MOD_SRC_DIR)/$${mod}/bios_bin debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/platform_api_mgnt.sh debian/$(PACKAGE_PRE_NAME)-$${mod}/usr/local/bin/; \ + fi; \ + if [ $$mod = "fn6254-dnf" ]; then \ + # For fn6254-dnf ixgbe driver \ + cp $(MOD_SRC_DIR)/fn6254-dnf/$(MODULE_DIR)/pegatron_fn6254_dnf_ixgbe/pegatron_fn6254_dnf_ixgbe.ko debian/$(PACKAGE_PRE_NAME)-fn6254-dnf/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \ + fi; \ + done) + + # Resuming debhelper scripts + dh_testroot + dh_install + dh_installchangelogs + dh_installdocs + dh_systemd_enable + dh_installinit + dh_systemd_start + dh_link + dh_fixperms + dh_compress + dh_strip + dh_installdeb + dh_gencontrol + dh_md5sums + dh_builddeb +.PHONY: build binary binary-arch binary-indep clean diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/bios_bin/afulnx_64 b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/bios_bin/afulnx_64 new file mode 100755 index 000000000000..ac0b87e7eb10 Binary files /dev/null and b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/bios_bin/afulnx_64 differ diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/Makefile b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/Makefile new file mode 100644 index 000000000000..ba082e51804c --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/Makefile @@ -0,0 +1,5 @@ +obj-m += pegatron_fn8656_bnf_cpld.o +obj-m += pegatron_fn8656_bnf_sfp.o +obj-m += pegatron_fn8656_bnf_psu.o +obj-m += pegatron_fn8656_bnf_watchdog.o +obj-m += clounix_watchdog.o diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/clounix_watchdog.c b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/clounix_watchdog.c new file mode 100644 index 000000000000..40508c6d8558 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/clounix_watchdog.c @@ -0,0 +1,790 @@ +/* + * intel TCO Watchdog Driver + * + * (c) Copyright 2006-2011 Wim Van Sebroeck . + * + * 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. + * + * Neither Wim Van Sebroeck nor Iguana vzw. admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + * The TCO watchdog is implemented in the following I/O controller hubs: + * (See the intel documentation on http://developer.intel.com.) + * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO) + * document number 290687-002, 298242-027: 82801BA (ICH2) + * document number 290733-003, 290739-013: 82801CA (ICH3-S) + * document number 290716-001, 290718-007: 82801CAM (ICH3-M) + * document number 290744-001, 290745-025: 82801DB (ICH4) + * document number 252337-001, 252663-008: 82801DBM (ICH4-M) + * document number 273599-001, 273645-002: 82801E (C-ICH) + * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R) + * document number 300641-004, 300884-013: 6300ESB + * document number 301473-002, 301474-026: 82801F (ICH6) + * document number 313082-001, 313075-006: 631xESB, 632xESB + * document number 307013-003, 307014-024: 82801G (ICH7) + * document number 322896-001, 322897-001: NM10 + * document number 313056-003, 313057-017: 82801H (ICH8) + * document number 316972-004, 316973-012: 82801I (ICH9) + * document number 319973-002, 319974-002: 82801J (ICH10) + * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH) + * document number 320066-003, 320257-008: EP80597 (IICH) + * document number 324645-001, 324646-001: Cougar Point (CPT) + * document number TBD : Patsburg (PBG) + * document number TBD : DH89xxCC + * document number TBD : Panther Point + * document number TBD : Lynx Point + * document number TBD : Lynx Point-LP + */ + +/* + * Includes, defines, variables, module parameters, ... + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +/* Module and version information */ +#define DRV_NAME "iTCO_wdt" +#define DRV_VERSION "1.11" + +/* Includes */ +#include /* For ACPI support */ +#include /* For module specific items */ +#include /* For new moduleparam's */ +#include /* For standard types (like size_t) */ +#include /* For the -ENODEV/... values */ +#include /* For printk/panic/... */ +#include /* For the watchdog specific items */ +#include /* For __init/__exit/... */ +#include /* For file operations */ +#include /* For platform_driver framework */ +#include /* For pci functions */ +#include /* For io-port access */ +#include /* For spin_lock/spin_unlock/... */ +#include /* For copy_to_user/put_user/... */ +#include /* For inb/outb/... */ +#include +#include +#include +#include +#include +#include +#include + +#include "iTCO_vendor.h" +#include "pegatron_pub.h" + +/* Address definitions for the TCO */ +/* TCO base address */ +#define TCOBASE(p) ((p)->tco_res->start) +/* SMI Control and Enable Register */ +#define SMI_EN(p) ((p)->smi_res->start) + +#define TCO_RLD(p) (TCOBASE(p) + 0x00) /* TCO Timer Reload/Curr. Value */ +#define TCOv1_TMR(p) (TCOBASE(p) + 0x01) /* TCOv1 Timer Initial Value*/ +#define TCO_DAT_IN(p) (TCOBASE(p) + 0x02) /* TCO Data In Register */ +#define TCO_DAT_OUT(p) (TCOBASE(p) + 0x03) /* TCO Data Out Register */ +#define TCO1_STS(p) (TCOBASE(p) + 0x04) /* TCO1 Status Register */ +#define TCO2_STS(p) (TCOBASE(p) + 0x06) /* TCO2 Status Register */ +#define TCO1_CNT(p) (TCOBASE(p) + 0x08) /* TCO1 Control Register */ +#define TCO2_CNT(p) (TCOBASE(p) + 0x0a) /* TCO2 Control Register */ +#define TCOv2_TMR(p) (TCOBASE(p) + 0x12) /* TCOv2 Timer Initial Value*/ + +/* internal variables */ +struct iTCO_wdt_private { + struct watchdog_device wddev; + + /* TCO version/generation */ + unsigned int iTCO_version; + struct resource *tco_res; + struct resource *smi_res; + /* + * NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2), + * or memory-mapped PMC register bit 4 (TCO version 3). + */ + struct resource *gcs_pmc_res; + unsigned long __iomem *gcs_pmc; + /* the lock for io operations */ + spinlock_t io_lock; + /* the PCI-device */ + struct pci_dev *pci_dev; + /* whether or not the watchdog has been suspended */ + bool suspended; + /* no reboot API private data */ + void *no_reboot_priv; + /* no reboot update function pointer */ + int (*update_no_reboot_bit)(void *p, bool set); +}; + +/* module parameters */ +#define WATCHDOG_TIMEOUT 30 /* 30 sec default heartbeat */ +static int heartbeat = WATCHDOG_TIMEOUT; /* in seconds */ +module_param(heartbeat, int, 0644); +MODULE_PARM_DESC(heartbeat, "Watchdog timeout in seconds. " + "5..76 (TCO v1) or 3..614 (TCO v2), default=" + __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); + +static bool nowayout = WATCHDOG_NOWAYOUT; +module_param(nowayout, bool, 0); +MODULE_PARM_DESC(nowayout, + "Watchdog cannot be stopped once started (default=" + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); + +static int turn_SMI_watchdog_clear_off = 1; +module_param(turn_SMI_watchdog_clear_off, int, 0); +MODULE_PARM_DESC(turn_SMI_watchdog_clear_off, + "Turn off SMI clearing watchdog (depends on TCO-version)(default=1)"); + +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; +static char watchdog_debug[MAX_DEBUG_INFO_LEN] = "This watchdog iTCO is in Intel SoC, more details please refer to Intel datasheet\n"; + +/* + * Some TCO specific functions + */ + +/* + * The iTCO v1 and v2's internal timer is stored as ticks which decrement + * every 0.6 seconds. v3's internal timer is stored as seconds (some + * datasheets incorrectly state 0.6 seconds). + */ +static inline unsigned int seconds_to_ticks(struct iTCO_wdt_private *p, + int secs) +{ + return p->iTCO_version == 3 ? secs : (secs * 10) / 6; +} + +static inline unsigned int ticks_to_seconds(struct iTCO_wdt_private *p, + int ticks) +{ + return p->iTCO_version == 3 ? ticks : (ticks * 6) / 10; +} + +static inline u32 no_reboot_bit(struct iTCO_wdt_private *p) +{ + u32 enable_bit; + + switch (p->iTCO_version) { + case 5: + case 3: + enable_bit = 0x00000010; + break; + case 2: + enable_bit = 0x00000020; + break; + case 4: + case 1: + default: + enable_bit = 0x00000002; + break; + } + + return enable_bit; +} + +static int update_no_reboot_bit_def(void *priv, bool set) +{ + return 0; +} + +static int update_no_reboot_bit_pci(void *priv, bool set) +{ + struct iTCO_wdt_private *p = priv; + u32 val32 = 0, newval32 = 0; + + pci_read_config_dword(p->pci_dev, 0xd4, &val32); + if (set) + val32 |= no_reboot_bit(p); + else + val32 &= ~no_reboot_bit(p); + pci_write_config_dword(p->pci_dev, 0xd4, val32); + pci_read_config_dword(p->pci_dev, 0xd4, &newval32); + + /* make sure the update is successful */ + if (val32 != newval32) + return -EIO; + + return 0; +} + +static int update_no_reboot_bit_mem(void *priv, bool set) +{ + struct iTCO_wdt_private *p = priv; + u32 val32 = 0, newval32 = 0; + + val32 = readl(p->gcs_pmc); + if (set) + val32 |= no_reboot_bit(p); + else + val32 &= ~no_reboot_bit(p); + writel(val32, p->gcs_pmc); + newval32 = readl(p->gcs_pmc); + + /* make sure the update is successful */ + if (val32 != newval32) + return -EIO; + + return 0; +} + +static void iTCO_wdt_no_reboot_bit_setup(struct iTCO_wdt_private *p, + struct itco_wdt_platform_data *pdata) +{ + if (pdata->update_no_reboot_bit) { + p->update_no_reboot_bit = pdata->update_no_reboot_bit; + p->no_reboot_priv = pdata->no_reboot_priv; + return; + } + + if (p->iTCO_version >= 2) + p->update_no_reboot_bit = update_no_reboot_bit_mem; + else if (p->iTCO_version == 1) + p->update_no_reboot_bit = update_no_reboot_bit_pci; + else + p->update_no_reboot_bit = update_no_reboot_bit_def; + + p->no_reboot_priv = p; +} + +static int iTCO_wdt_start(struct watchdog_device *wd_dev) +{ + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); + unsigned int val; + + spin_lock(&p->io_lock); + + iTCO_vendor_pre_start(p->smi_res, wd_dev->timeout); + + /* disable chipset's NO_REBOOT bit */ + if (p->update_no_reboot_bit(p->no_reboot_priv, false)) { + spin_unlock(&p->io_lock); + pega_print(ERR, "failed to reset NO_REBOOT flag, reboot disabled by hardware/BIOS\n"); + return -EIO; + } + + /* Force the timer to its reload value by writing to the TCO_RLD + register */ + if (p->iTCO_version >= 2) + outw(0x01, TCO_RLD(p)); + else if (p->iTCO_version == 1) + outb(0x01, TCO_RLD(p)); + + /* Bit 11: TCO Timer Halt -> 0 = The TCO timer is enabled to count */ + val = inw(TCO1_CNT(p)); + val &= 0xf7ff; + outw(val, TCO1_CNT(p)); + val = inw(TCO1_CNT(p)); + spin_unlock(&p->io_lock); + + if (val & 0x0800) + return -1; + return 0; +} + +static int iTCO_wdt_stop(struct watchdog_device *wd_dev) +{ + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); + unsigned int val; + + spin_lock(&p->io_lock); + + iTCO_vendor_pre_stop(p->smi_res); + + /* Bit 11: TCO Timer Halt -> 1 = The TCO timer is disabled */ + val = inw(TCO1_CNT(p)); + val |= 0x0800; + outw(val, TCO1_CNT(p)); + val = inw(TCO1_CNT(p)); + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + p->update_no_reboot_bit(p->no_reboot_priv, true); + + spin_unlock(&p->io_lock); + + if ((val & 0x0800) == 0) + return -1; + return 0; +} + +static int iTCO_wdt_ping(struct watchdog_device *wd_dev) +{ + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); + + spin_lock(&p->io_lock); + + iTCO_vendor_pre_keepalive(p->smi_res, wd_dev->timeout); + + /* Reload the timer by writing to the TCO Timer Counter register */ + if (p->iTCO_version >= 2) { + outw(0x01, TCO_RLD(p)); + } else if (p->iTCO_version == 1) { + /* Reset the timeout status bit so that the timer + * needs to count down twice again before rebooting */ + outw(0x0008, TCO1_STS(p)); /* write 1 to clear bit */ + + outb(0x01, TCO_RLD(p)); + } + + spin_unlock(&p->io_lock); + return 0; +} + +static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t) +{ + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); + unsigned int val16; + unsigned char val8; + unsigned int tmrval; + + tmrval = seconds_to_ticks(p, t); + + /* For TCO v1 the timer counts down twice before rebooting */ + if (p->iTCO_version == 1) + tmrval /= 2; + + /* from the specs: */ + /* "Values of 0h-3h are ignored and should not be attempted" */ + if (tmrval < 0x04) + return -EINVAL; + if ((p->iTCO_version >= 2 && tmrval > 0x3ff) || + (p->iTCO_version == 1 && tmrval > 0x03f)) + return -EINVAL; + + iTCO_vendor_pre_set_heartbeat(tmrval); + + /* Write new heartbeat to watchdog */ + if (p->iTCO_version >= 2) { + spin_lock(&p->io_lock); + val16 = inw(TCOv2_TMR(p)); + val16 &= 0xfc00; + val16 |= tmrval; + outw(val16, TCOv2_TMR(p)); + val16 = inw(TCOv2_TMR(p)); + spin_unlock(&p->io_lock); + + if ((val16 & 0x3ff) != tmrval) + return -EINVAL; + } else if (p->iTCO_version == 1) { + spin_lock(&p->io_lock); + val8 = inb(TCOv1_TMR(p)); + val8 &= 0xc0; + val8 |= (tmrval & 0xff); + outb(val8, TCOv1_TMR(p)); + val8 = inb(TCOv1_TMR(p)); + spin_unlock(&p->io_lock); + + if ((val8 & 0x3f) != tmrval) + return -EINVAL; + } + + wd_dev->timeout = t; + return 0; +} + +static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev) +{ + struct iTCO_wdt_private *p = watchdog_get_drvdata(wd_dev); + unsigned int val16; + unsigned char val8; + unsigned int time_left = 0; + + /* read the TCO Timer */ + if (p->iTCO_version >= 2) { + spin_lock(&p->io_lock); + val16 = inw(TCO_RLD(p)); + val16 &= 0x3ff; + spin_unlock(&p->io_lock); + + time_left = ticks_to_seconds(p, val16); + } else if (p->iTCO_version == 1) { + spin_lock(&p->io_lock); + val8 = inb(TCO_RLD(p)); + val8 &= 0x3f; + if (!(inw(TCO1_STS(p)) & 0x0008)) + val8 += (inb(TCOv1_TMR(p)) & 0x3f); + spin_unlock(&p->io_lock); + + time_left = ticks_to_seconds(p, val8); + } + return time_left; +} + +/* + * Kernel Interfaces + */ + +static const struct watchdog_info ident = { + .options = WDIOF_SETTIMEOUT | + WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, + .firmware_version = 0, + .identity = DRV_NAME, +}; + +static const struct watchdog_ops iTCO_wdt_ops = { + .owner = THIS_MODULE, + .start = iTCO_wdt_start, + .stop = iTCO_wdt_stop, + .ping = iTCO_wdt_ping, + .set_timeout = iTCO_wdt_set_timeout, + .get_timeleft = iTCO_wdt_get_timeleft, +}; + +#if 1 //add by clounix +static struct kobject *parent_kobj = NULL; +static unsigned int work_status = 0; +static struct iTCO_wdt_private *priv_data = NULL; +static struct hrtimer work_timer = {0}; +static struct work_struct work_task = {0}; + +void ping_work(struct work_struct *work) +{ + priv_data->wddev.ops->ping(&(priv_data->wddev)); +} + +static enum hrtimer_restart timer_work_expired(struct hrtimer *timer) +{ + if (work_status == 0) + return HRTIMER_NORESTART; + + if (work_status == 1) { + schedule_work(&work_task); + hrtimer_start(&work_timer, ms_to_ktime((heartbeat*1000)/2), HRTIMER_MODE_REL); + } + + return HRTIMER_NORESTART; +} + +ssize_t clounix_ping_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + if (*buf != '1') + return -EPERM; + + priv_data->wddev.ops->ping(&(priv_data->wddev)); + + return count; +} + +ssize_t clounix_timeout_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\r\n", heartbeat); +} + +ssize_t clounix_timeout_ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + if (count > 10) + return -EPERM; + + if (kstrtoint(buf, 0, &heartbeat) != 0) + return -EPERM; + + hrtimer_cancel(&work_timer); + priv_data->wddev.ops->stop(&(priv_data->wddev)); + + if (priv_data->wddev.ops->set_timeout(&(priv_data->wddev), heartbeat) != 0) { + priv_data->wddev.ops->set_timeout(&(priv_data->wddev), WATCHDOG_TIMEOUT); + pega_print(INFO, "timeout value out of range, using %d\n", + WATCHDOG_TIMEOUT); + heartbeat = WATCHDOG_TIMEOUT; + } + + priv_data->wddev.ops->start(&(priv_data->wddev)); + hrtimer_start(&work_timer, 0, HRTIMER_MODE_REL); + set_bit(WDOG_ACTIVE, &priv_data->wddev.status); + + return count; +} +ssize_t clounix_ctrl_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\r\n", work_status); +} + +ssize_t clounix_ctrl_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) +{ + if (*buf == '1') { + if (work_status == 0) { + work_status = 1; + priv_data->wddev.ops->start(&(priv_data->wddev)); + hrtimer_start(&work_timer, 0, HRTIMER_MODE_REL); + set_bit(WDOG_ACTIVE, &priv_data->wddev.status); + } + } else if (*buf == '0') { + if (work_status == 1) { + work_status = 0; + priv_data->wddev.ops->ping(&(priv_data->wddev)); + priv_data->wddev.ops->stop(&(priv_data->wddev)); + hrtimer_cancel(&work_timer); + flush_work(&work_task); + clear_bit(WDOG_ACTIVE, &priv_data->wddev.status); + } + } else { + return -EINVAL; + } + + return count; +} + +DEVICE_ATTR_WO(clounix_ping); +DEVICE_ATTR_RW(clounix_timeout_ctrl); +DEVICE_ATTR_RW(clounix_ctrl); +static struct attribute *wdt_attrs[] = { + &dev_attr_clounix_ping.attr, + &dev_attr_clounix_timeout_ctrl.attr, + &dev_attr_clounix_ctrl.attr, + NULL +}; +const struct attribute_group ops_group = { + .attrs = wdt_attrs +}; +#endif + +/* + * Init & exit routines + */ + +static int iTCO_wdt_probe(struct platform_device *pdev) +{ + + struct device *dev = &pdev->dev; + struct itco_wdt_platform_data *pdata = dev_get_platdata(dev); + struct iTCO_wdt_private *p; + unsigned long val32; + int ret; + + if (!pdata) + return -ENODEV; + + p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL); + if (!p) + return -ENOMEM; + + spin_lock_init(&p->io_lock); + + p->tco_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_TCO); + if (!p->tco_res) + return -ENODEV; + + p->smi_res = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_IO_SMI); + if (!p->smi_res) + return -ENODEV; + + p->iTCO_version = pdata->version; + p->pci_dev = to_pci_dev(dev->parent); + + iTCO_wdt_no_reboot_bit_setup(p, pdata); + + /* + * Get the Memory-Mapped GCS or PMC register, we need it for the + * NO_REBOOT flag (TCO v2 and v3). + */ + if (p->iTCO_version >= 2 && !pdata->update_no_reboot_bit) { + p->gcs_pmc_res = platform_get_resource(pdev, + IORESOURCE_MEM, + ICH_RES_MEM_GCS_PMC); + p->gcs_pmc = devm_ioremap_resource(dev, p->gcs_pmc_res); + if (IS_ERR(p->gcs_pmc)) + return PTR_ERR(p->gcs_pmc); + } + + /* Check chipset's NO_REBOOT bit */ + if (p->update_no_reboot_bit(p->no_reboot_priv, false) && + iTCO_vendor_check_noreboot_on()) { + pega_print(INFO, "unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n"); + return -ENODEV; /* Cannot reset NO_REBOOT bit */ + } + + /* Set the NO_REBOOT bit to prevent later reboots, just for sure */ + p->update_no_reboot_bit(p->no_reboot_priv, true); + + /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ + if (!devm_request_region(dev, p->smi_res->start, + resource_size(p->smi_res), + pdev->name)) { + pega_print(ERR, "I/O address 0x%04llx already in use, device disabled\n", + (u64)SMI_EN(p)); + return -EBUSY; + } + if (turn_SMI_watchdog_clear_off >= p->iTCO_version) { + /* + * Bit 13: TCO_EN -> 0 + * Disables TCO logic generating an SMI# + */ + val32 = inl(SMI_EN(p)); + val32 &= 0xffffdfff; /* Turn off SMI clearing watchdog */ + outl(val32, SMI_EN(p)); + } + + if (!devm_request_region(dev, p->tco_res->start, + resource_size(p->tco_res), + pdev->name)) { + pega_print(ERR, "I/O address 0x%04llx already in use, device disabled\n", + (u64)TCOBASE(p)); + return -EBUSY; + } + + pega_print(INFO, "Found a %s TCO device (Version=%d, TCOBASE=0x%04llx)\n", + pdata->name, pdata->version, (u64)TCOBASE(p)); + + /* Clear out the (probably old) status */ + switch (p->iTCO_version) { + case 5: + case 4: + outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */ + outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ + break; + case 3: + outl(0x20008, TCO1_STS(p)); + break; + case 2: + case 1: + default: + outw(0x0008, TCO1_STS(p)); /* Clear the Time Out Status bit */ + outw(0x0002, TCO2_STS(p)); /* Clear SECOND_TO_STS bit */ + outw(0x0004, TCO2_STS(p)); /* Clear BOOT_STS bit */ + break; + } + + p->wddev.info = &ident, + p->wddev.ops = &iTCO_wdt_ops, + p->wddev.bootstatus = 0; + p->wddev.timeout = WATCHDOG_TIMEOUT; + watchdog_set_nowayout(&p->wddev, nowayout); + p->wddev.parent = dev; + + + watchdog_set_drvdata(&p->wddev, p); + platform_set_drvdata(pdev, p); + + if (priv_data == NULL) + priv_data = p; + + /* Make sure the watchdog is not running */ + iTCO_wdt_stop(&p->wddev); + + /* Check that the heartbeat value is within it's range; + if not reset to the default */ + if (iTCO_wdt_set_timeout(&p->wddev, heartbeat)) { + iTCO_wdt_set_timeout(&p->wddev, WATCHDOG_TIMEOUT); + pega_print(INFO, "timeout value out of range, using %d\n", + WATCHDOG_TIMEOUT); + } + + watchdog_stop_on_reboot(&p->wddev); + ret = devm_watchdog_register_device(dev, &p->wddev); + if (ret != 0) { + pega_print(ERR, "cannot register watchdog device (err=%d)\n", ret); + return ret; + } + + pega_print(INFO, "initialized. heartbeat=%d sec (nowayout=%d)\n", + heartbeat, nowayout); + + INIT_WORK(&work_task, ping_work); + hrtimer_init(&work_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + work_timer.function = timer_work_expired; + parent_kobj = pdev->dev.kobj.parent; + + return sysfs_create_group(parent_kobj, &ops_group); +} + +static int iTCO_wdt_remove(struct platform_device *pdev) +{ + struct iTCO_wdt_private *p = platform_get_drvdata(pdev); + + hrtimer_cancel(&work_timer); + flush_work(&work_task); + sysfs_remove_group(parent_kobj, &ops_group); + priv_data->wddev.ops->ping(&(priv_data->wddev)); + + /* Stop the timer before we leave */ + if (!nowayout) + iTCO_wdt_stop(&p->wddev); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +/* + * Suspend-to-idle requires this, because it stops the ticks and timekeeping, so + * the watchdog cannot be pinged while in that state. In ACPI sleep states the + * watchdog is stopped by the platform firmware. + */ + +#ifdef CONFIG_ACPI +static inline bool need_suspend(void) +{ + return acpi_target_system_state() == ACPI_STATE_S0; +} +#else +static inline bool need_suspend(void) { return true; } +#endif + +static int iTCO_wdt_suspend_noirq(struct device *dev) +{ + struct iTCO_wdt_private *p = dev_get_drvdata(dev); + int ret = 0; + + p->suspended = false; + if (watchdog_active(&p->wddev) && need_suspend()) { + ret = iTCO_wdt_stop(&p->wddev); + if (!ret) + p->suspended = true; + } + return ret; +} + +static int iTCO_wdt_resume_noirq(struct device *dev) +{ + struct iTCO_wdt_private *p = dev_get_drvdata(dev); + + if (p->suspended) + iTCO_wdt_start(&p->wddev); + + return 0; +} + +static const struct dev_pm_ops iTCO_wdt_pm = { + .suspend_noirq = iTCO_wdt_suspend_noirq, + .resume_noirq = iTCO_wdt_resume_noirq, +}; + +#define ITCO_WDT_PM_OPS (&iTCO_wdt_pm) +#else +#define ITCO_WDT_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + +static struct platform_driver iTCO_wdt_driver = { + .probe = iTCO_wdt_probe, + .remove = iTCO_wdt_remove, + .driver = { + .name = DRV_NAME, + .pm = ITCO_WDT_PM_OPS, + }, +}; + +static int __init iTCO_wdt_init_module(void) +{ + pega_print(INFO, "Intel TCO WatchDog Timer Driver v%s\n", DRV_VERSION); + + return platform_driver_register(&iTCO_wdt_driver); +} + +static void __exit iTCO_wdt_cleanup_module(void) +{ + platform_driver_unregister(&iTCO_wdt_driver); + pega_print(INFO, "Watchdog Module Unloaded\n"); +} + +module_init(iTCO_wdt_init_module); +module_exit(iTCO_wdt_cleanup_module); + +module_param(loglevel, uint, 0644); +module_param_string(watchdog_debug, watchdog_debug, MAX_DEBUG_INFO_LEN, 0644); + +MODULE_AUTHOR("Wim Van Sebroeck "); +MODULE_DESCRIPTION("Intel TCO WatchDog Timer Driver"); +MODULE_VERSION(DRV_VERSION); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/iTCO_vendor.h b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/iTCO_vendor.h new file mode 100644 index 000000000000..7b82a7c6e7c3 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/iTCO_vendor.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* iTCO Vendor Specific Support hooks */ +#ifdef CONFIG_ITCO_VENDOR_SUPPORT +extern void iTCO_vendor_pre_start(struct resource *, unsigned int); +extern void iTCO_vendor_pre_stop(struct resource *); +extern void iTCO_vendor_pre_keepalive(struct resource *, unsigned int); +extern void iTCO_vendor_pre_set_heartbeat(unsigned int); +extern int iTCO_vendor_check_noreboot_on(void); +#else +#define iTCO_vendor_pre_start(acpibase, heartbeat) {} +#define iTCO_vendor_pre_stop(acpibase) {} +#define iTCO_vendor_pre_keepalive(acpibase, heartbeat) {} +#define iTCO_vendor_pre_set_heartbeat(heartbeat) {} +#define iTCO_vendor_check_noreboot_on() 1 + /* 1=check noreboot; 0=don't check */ +#endif diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_cpld.c b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_cpld.c new file mode 100644 index 000000000000..c9604154dc32 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_cpld.c @@ -0,0 +1,1692 @@ +/* + * A CPLD driver for the fn8656_bnf + * + * Copyright (C) 2018 Pegatron Corporation. + * Peter5_Lin + * + * 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 "pegatron_pub.h" + + +#define PEGA_RD(x) 1 + +#define CPLD_MAX_NUM 4 +#define CPLD_SFP_MAX_GROUP 3 +#define SFP_PORT_MAX_NUM 56 +#define SFP_EEPROM_SIZE 256 +#define QSFP_FIRST_PORT 48 +#define CPLDA_SFP_NUM 0 +#define CPLDB_SFP_NUM 28 +#define CPLDC_SFP_NUM 28 +#define CPLDA_ADDRESS 0x74 +#define CPLDB_ADDRESS 0x75 +#define CPLDC_ADDRESS 0x76 +#define CPLDD_ADDRESS 0x18 +#define LM75B_ADDRESS 0x4a +#define LM75B_TEMP_REG 0x0 + + +#define GET_BIT(data, bit, value) value = (data >> bit) & 0x1 +#define SET_BIT(data, bit) data |= (1 << bit) +#define CLEAR_BIT(data, bit) data &= ~(1 << bit) + +static LIST_HEAD(cpld_client_list); +static struct mutex list_lock; +/* Addresses scanned for pegatron_fn8656_bnf_cpld + */ +static const unsigned short normal_i2c[] = { CPLDA_ADDRESS, CPLDB_ADDRESS, CPLDC_ADDRESS, CPLDD_ADDRESS, LM75B_ADDRESS, I2C_CLIENT_END }; + +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; +static char sfp_debug[MAX_DEBUG_INFO_LEN] = "debug info: \n\ +init_mode --- 0: High power mode, 1: Low power mode \n\ +power_on --- 0: Not finished, 1: Finished \n\ +reset --- 0: Reset Keep low, 1: Reset Keep high \n\ +present --- 0: Module insert, 1: Module absent \n\ +interrupt --- 0: Interrupt active 1: Normal operation\n"; + +static char cpld_debug[MAX_DEBUG_INFO_LEN] = "cpld debug info: \n"; +static char sysled_debug[MAX_DEBUG_INFO_LEN] = "sysled debug info: \n"; + +enum{ + DEFAULT_REQUIREMENT = 0x0, + KS_REQUIREMENT = 0x01 +}; + +static uint requirement_flag = DEFAULT_REQUIREMENT; + +struct cpld_client_node { + struct i2c_client *client; + struct list_head list; +}; + +int pegatron_fn8656_bnf_cpld_read(unsigned short addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct cpld_client_node *cpld_node = NULL; + int data = -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 == addr) { + data = i2c_smbus_read_byte_data(cpld_node->client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", addr, reg, data); + break; + } + } + + mutex_unlock(&list_lock); + + return data; +} +EXPORT_SYMBOL(pegatron_fn8656_bnf_cpld_read); + + +int pegatron_fn8656_bnf_cpld_write(unsigned short addr, u8 reg, u8 val) +{ + 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 == addr) { + ret = i2c_smbus_write_byte_data(cpld_node->client, reg, val); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", addr, reg, val); + break; + } + } + + mutex_unlock(&list_lock); + + return ret; +} +EXPORT_SYMBOL(pegatron_fn8656_bnf_cpld_write); + +#if PEGA_RD(CPLD_VERSION) + +#define CPLD_VERSION_REG 0x0 + #define CPLD_HW_VERSION_BIT_OFFSET 5 + #define CPLD_HW_VERSION_BIT_MSK (0x3 << CPLD_HW_VERSION_BIT_OFFSET) + #define CPLD_SW_VERSION_BIT_OFFSET 0 + #define CPLD_SW_VERSION_BIT_MSK (0x1F << CPLD_SW_VERSION_BIT_OFFSET) + +static ssize_t read_cpld_HWversion(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, reg = CPLD_VERSION_REG; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "0x%02x\n", (data & CPLD_HW_VERSION_BIT_MSK) >> CPLD_HW_VERSION_BIT_OFFSET); +} + +static ssize_t read_cpld_SWversion(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, reg = CPLD_VERSION_REG; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "%02d\n", (data & CPLD_SW_VERSION_BIT_MSK) >> CPLD_SW_VERSION_BIT_OFFSET); +} +#endif //CPLD_VERSION + +#if PEGA_RD(LED) + +#define CPLD_A_LED_CONTROL_REG_1 0x5 +#define CPLD_A_SYS_LED_CTL_BIT_OFFSET 5 +#define CPLD_A_SYS_LED_CTL_BIT_MSK (0x7 << CPLD_A_SYS_LED_CTL_BIT_OFFSET) +#define CPLD_A_PWR_LED_CTL_BIT_OFFSET 2 +#define CPLD_A_PWR_LED_CTL_BIT_MSK (0x7 << CPLD_A_PWR_LED_CTL_BIT_OFFSET) + +#define CPLD_A_LED_CONTROL_REG_2 0x6 +#define CPLD_A_FAN_LED_CTL_BIT_OFFSET 0 +#define CPLD_A_FAN_LED_CTL_BIT_MSK (0x7 << CPLD_A_FAN_LED_CTL_BIT_OFFSET) +#define CPLD_A_SERIAL_LED_BIT_OFFSET 3 +#define CPLD_A_SERIAL_LED_BIT_MASK (0x1 << CPLD_A_SERIAL_LED_BIT_OFFSET) +#define CPLD_A_LED_CONTROL_REG_3 0x7 +#define CPLD_A_ALL_LED_CTL_BIT_OFFSET 0 +#define CPLD_A_ALL_LED_CTL_BIT_MSK (0xFF << CPLD_A_ALL_LED_CTL_BIT_OFFSET) +#define CPLD_BC_LED_CONTROL_REG_1 0x01 +#define CPLD_BC_SERIAL_LED_BIT_OFFSET 2 +#define CPLD_BC_SERIAL_LED_BIT_MASK (0x1 << CPLD_BC_SERIAL_LED_BIT_OFFSET) + +#define CPLD_D_LED_CONTROL_REG 0x6 +#define CPLD_D_LOC_LED_CTL_BIT_OFFSET 0 +#define CPLD_D_LOC_LED_CTL_BIT_MSK (0x3 << CPLD_D_LOC_LED_CTL_BIT_OFFSET) + +enum _sysfs_led_attr { + ALL_LED_CTRL = 0, + SERIAL_LED_CTRL, + SYS_LED_CTRL, + PWR_LED_CTRL, + LOC_LED_CTRL, + FAN_LED_CTRL, + LED_ATTR_END +}; +enum _cpld_led_bit_attr{ + CPLD_LED_STATUS_GREEN_ON = 0, + CPLD_LED_STATUS_RED_ON, + CPLD_LED_STATUS_OFF, + CPLD_LED_STATUS_MIX_ON, + CPLD_LED_STATUS_GREEN_BLINK, + CPLD_LED_STATUS_RED_BLINK, + CPLD_LED_STATUS_MIX_BLINK, + CPLD_LED_STATUS_NOT_SUPPORT +}; +enum _kwai_led_bit_attr{ + KWAI_LED_STATUS_OFF = 0, + KWAI_LED_STATUS_GREEN_ON, + KWAI_LED_STATUS_YELLOW_ON, + KWAI_LED_STATUS_RED_ON, + KWAI_LED_STATUS_GREEN_BLINK, + KWAI_LED_STATUS_YELLOW_BLINK, + KWAI_LED_STATUS_RED_BLINK, + KWAI_LED_STATUS_BLLUE_ON, + KWAI_LED_STATUS_BLLUE_BLINK, + KWAI_LED_STATUS_NOT_EXIST +}; + + +static u8 map_ledstatus_cpldconfig_2_userconfig[] = {KWAI_LED_STATUS_GREEN_ON,KWAI_LED_STATUS_RED_ON,KWAI_LED_STATUS_OFF,KWAI_LED_STATUS_NOT_EXIST, + KWAI_LED_STATUS_GREEN_BLINK,KWAI_LED_STATUS_RED_BLINK,KWAI_LED_STATUS_NOT_EXIST}; + + +static u8 map_ledstatus_userconfig_2_cpldconfig[] = {CPLD_LED_STATUS_OFF,CPLD_LED_STATUS_GREEN_ON,CPLD_LED_STATUS_NOT_SUPPORT,CPLD_LED_STATUS_RED_ON,CPLD_LED_STATUS_GREEN_BLINK, + CPLD_LED_STATUS_NOT_SUPPORT,CPLD_LED_STATUS_RED_BLINK,CPLD_LED_STATUS_NOT_SUPPORT,CPLD_LED_STATUS_NOT_SUPPORT}; + +static ssize_t show_led_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); + u8 data = 0, reg = 0,bit_offset = 0,bit_msk = 0; + bool attr_cpld_2_user = FALSE; + + switch(attr->index) { + case ALL_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_3; + bit_offset = CPLD_A_ALL_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_ALL_LED_CTL_BIT_MSK; + break; + case SERIAL_LED_CTRL: + if(client->addr == CPLDA_ADDRESS) + { + reg = CPLD_A_LED_CONTROL_REG_2; + bit_offset = CPLD_A_SERIAL_LED_BIT_OFFSET; + bit_msk = CPLD_A_SERIAL_LED_BIT_MASK; + } + else if((client->addr == CPLDB_ADDRESS) || (client->addr == CPLDC_ADDRESS)) + { + reg = CPLD_BC_LED_CONTROL_REG_1; + bit_offset = CPLD_BC_SERIAL_LED_BIT_OFFSET; + bit_msk = CPLD_BC_SERIAL_LED_BIT_MASK; + } + break; + case SYS_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_1; + bit_offset = CPLD_A_SYS_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_SYS_LED_CTL_BIT_MSK; + attr_cpld_2_user = TRUE; + break; + case PWR_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_1; + bit_offset = CPLD_A_PWR_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_PWR_LED_CTL_BIT_MSK; + attr_cpld_2_user = TRUE; + break; + case FAN_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_2; + bit_offset = CPLD_A_FAN_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_FAN_LED_CTL_BIT_MSK; + attr_cpld_2_user = TRUE; + break; + case LOC_LED_CTRL: + reg = CPLD_D_LED_CONTROL_REG; + bit_offset = CPLD_D_LOC_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_D_LOC_LED_CTL_BIT_MSK; + break; + default: + pega_print(ERR,"incorrect led type\n"); + return sprintf(buf, "ERR"); + } + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + data = (data & bit_msk) >> bit_offset; + + if(data >= CPLD_LED_STATUS_NOT_SUPPORT) + return -EINVAL; + if(attr_cpld_2_user == TRUE) + data = map_ledstatus_cpldconfig_2_userconfig[data]; + + return sprintf(buf, "%d\n", data); +} + +static ssize_t set_led_status(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); + u8 data = 0, reg = 0,bit_offset = 0,bit_msk = 0; + long val = 0; + bool attr_user_2_cpld = FALSE; + + switch(attr->index) { + case ALL_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_3; + bit_offset = CPLD_A_ALL_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_ALL_LED_CTL_BIT_MSK; + break; + case SERIAL_LED_CTRL: + if(client->addr == CPLDA_ADDRESS) + { + reg = CPLD_A_LED_CONTROL_REG_2; + bit_offset = CPLD_A_SERIAL_LED_BIT_OFFSET; + bit_msk = CPLD_A_SERIAL_LED_BIT_MASK; + } + else if((client->addr == CPLDB_ADDRESS) || (client->addr == CPLDC_ADDRESS)) + { + reg = CPLD_BC_LED_CONTROL_REG_1; + bit_offset = CPLD_BC_SERIAL_LED_BIT_OFFSET; + bit_msk = CPLD_BC_SERIAL_LED_BIT_MASK; + } + break; + case SYS_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_1; + bit_offset = CPLD_A_SYS_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_SYS_LED_CTL_BIT_MSK; + attr_user_2_cpld = TRUE; + break; + case PWR_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_1; + bit_offset = CPLD_A_PWR_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_PWR_LED_CTL_BIT_MSK; + attr_user_2_cpld = TRUE; + break; + case FAN_LED_CTRL: + reg = CPLD_A_LED_CONTROL_REG_2; + bit_offset = CPLD_A_FAN_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_A_FAN_LED_CTL_BIT_MSK; + attr_user_2_cpld = TRUE; + break; + case LOC_LED_CTRL: + reg = CPLD_D_LED_CONTROL_REG; + bit_offset = CPLD_D_LOC_LED_CTL_BIT_OFFSET; + bit_msk = CPLD_D_LOC_LED_CTL_BIT_MSK; + break; + default: + pega_print(ERR,"incorrect led type\n"); + return -EINVAL; + } + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + if(val >= KWAI_LED_STATUS_NOT_EXIST) + { + return -EINVAL; + } + if(attr_user_2_cpld == TRUE) + val = map_ledstatus_userconfig_2_cpldconfig[val]; + if(val >= CPLD_LED_STATUS_NOT_SUPPORT) + { + return -EINVAL; + } + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + data = (val << bit_offset) | (data & (~bit_msk)); + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} +#endif //LED + +#if PEGA_RD(EEPROM_WRITE_ENABLE) +#define CPLD_A_EEPROM_WRITE_REG 0x1 +#define CPLD_A_EEPROM_WRITE_BIT 1 +static ssize_t show_eeprom_write_enable(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, val = 0, reg = CPLD_A_EEPROM_WRITE_REG; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, reg, val); + + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_eeprom_write_enable(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, reg = CPLD_A_EEPROM_WRITE_REG; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + if(val) + SET_BIT(data, CPLD_A_EEPROM_WRITE_BIT); + else + CLEAR_BIT(data, CPLD_A_EEPROM_WRITE_BIT); + + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} +#endif //EEPROM_WRITE_ENABLE + +#if PEGA_RD(PSU) +#define CPLD_A_PSU_REG 0x2 + #define CPLD_A_PSU_PWOK_BASE 0 + #define CPLD_A_PSU_PRESENT_BASE 2 + #define CPLD_A_PSU_AC_OK_BASE 4 + +#define PSU_ABSENT 1 +#define PSU_POWER_OK 1 + +#define KWAI_PSU_ABSENT 0 +#define KWAI_PSU_PRESENT_POWER_OK 1 +#define KWAI_PSU_PRESENT_POWER_NOT_OK 2 + +static ssize_t read_psu_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); + u8 data = 0, val=0, reg = CPLD_A_PSU_REG; + u8 power_good = 0, ac_good = 0, present = 0; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + + GET_BIT(data, (CPLD_A_PSU_PWOK_BASE + attr->index), power_good); + GET_BIT(data, (CPLD_A_PSU_AC_OK_BASE + attr->index), ac_good); + GET_BIT(data, (CPLD_A_PSU_PRESENT_BASE + attr->index), present); + + if(present == PSU_ABSENT) + { + val = KWAI_PSU_ABSENT; + } + else + { + if((ac_good == PSU_POWER_OK)&&(power_good == PSU_POWER_OK)) + { + val = KWAI_PSU_PRESENT_POWER_OK; + } + else + { + val = KWAI_PSU_PRESENT_POWER_NOT_OK; + } + } + + return sprintf(buf, "0x%02x\n", val); +} +#endif //PSU + +#define CPLD_A_INT_REG 0x0B +static ssize_t read_int_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, val=0, reg = CPLD_A_INT_REG,fan_fault = 0, psu_fault = 0; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + GET_BIT(data, 5, fan_fault); + //3V3 system power alert + GET_BIT(data, 0, psu_fault); + + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x,Fan board MCU:%d,3V3 system power alert:%d\r\n", client->addr, reg, data, fan_fault, psu_fault); + val = fan_fault | (psu_fault << 1); + + return sprintf(buf, "0x%02x\n", val); +} + +#define CPLD_D_RST_REG 0x09 +#define CPLD_D_SYS_RST_BIT 3 //systemp RST bit 0: reset low active, write and clear 1:Normal operation +#define CPLD_D_COLD_RST_FLAG_BIT 4 +#define CPLD_D_WARM_RST_FLAG_BIT 5 +static ssize_t set_sys_rst(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 reg, data = 0; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + reg = CPLD_D_RST_REG; + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + if(val) + CLEAR_BIT(data, CPLD_D_SYS_RST_BIT); + else + SET_BIT(data, CPLD_D_SYS_RST_BIT); + + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} + +static ssize_t show_sys_rst(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, val = 0, reg = CPLD_D_RST_REG; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, CPLD_D_SYS_RST_BIT, val); + + return sprintf(buf, "0x%02x\n", val); +} + +#define CPLD_D_WDT_REG 0x12 +#define CPLD_D_WATCHDOG_TMO_BIT 6 +extern int pega_mcu_read(unsigned short addr, u8 reg); +extern int pega_mcu_write(unsigned short addr, u8 reg, u8 val); +#define MCU_MB_ADDRESS 0x70 +static ssize_t show_reboot_cause(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, watchdog = 0, reg = CPLD_D_WDT_REG; + u8 reboot_cause = 0; + u8 cold_rst = 0, warm_rst = 0, pwr_down = 0; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, CPLD_D_WATCHDOG_TMO_BIT, watchdog); + reg = CPLD_D_RST_REG; + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, CPLD_D_COLD_RST_FLAG_BIT, cold_rst); + GET_BIT(data, CPLD_D_WARM_RST_FLAG_BIT, warm_rst); +#if 0//power down reason is from mcu + pega_mcu_write(MCU_MB_ADDRESS, 0xB0, 0x0); + pega_mcu_write(MCU_MB_ADDRESS, 0xB1, 0xa0); + pwr_down = ((pega_mcu_read(MCU_MB_ADDRESS, 0xB2) == 0xff)?0:1); +#endif + + reboot_cause = pwr_down | (watchdog << 1) | (cold_rst << 2) | (warm_rst << 3); + return sprintf(buf, "0x%02x\n", reboot_cause); +} + +#if PEGA_RD(DSFP) + +#define DSFP_PRESENT_ADDRESS 0x21 +#define DSFP_RESET_ADDRESS_BASE 0X25 +#define DSFP_IRQ_STATUS_ADDRESS 0x2C +#define DSFP_LOW_POWER_ADDRESS 0x30 + +#define GET_DSFP_STATUS_ADDRESS(idx, reg) \ + do{\ + if(idx >=0 && idx < 24)\ + {\ + reg = DSFP_PRESENT_ADDRESS + ((idx % 24) / 8);\ + }\ + else if(idx >=24 && idx < 28)\ + {\ + reg = 0x24;\ + }\ + else if(idx >=28 && idx < 36)\ + {\ + reg = 0x21;\ + }\ + else if (idx >= 36 && idx < 44)\ + {\ + reg = 0x22;\ + }\ + else if(idx >=44 && idx <48)\ + {\ + reg = 0x23;\ + }\ + } while(0) + +#define GET_DSFP_RST_ADDRESS(idx, reg) \ + reg = (DSFP_RESET_ADDRESS_BASE + ((idx % 28) / 4)); + +#define GET_DSFP_LOWPOWER_ADDRESS(idx, reg) \ + reg = DSFP_LOW_POWER_ADDRESS + ((idx % 28) / 8) + +#define GET_DSFP_IRQ_STATUS_ADDRESS(idx, reg) \ + reg = DSFP_IRQ_STATUS_ADDRESS + ((idx % 28) / 8) + + +static ssize_t get_dsfp_present(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); + u8 data = 0, val = 0, reg; + + GET_DSFP_STATUS_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "attr->index:%d,addr: 0x%x, reg: %x, data: %x\r\n",attr->index, client->addr, reg, data); + + if(requirement_flag & KS_REQUIREMENT) + { + data = ~data; + } + if(attr->index >= 28) + GET_BIT(data, (attr->index - 4) % 8, val); + else + GET_BIT(data, attr->index % 8, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t get_dsfp_irq_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); + u8 data = 0, val = 0, reg; + + GET_DSFP_IRQ_STATUS_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, attr->index % 8, val); + + if(requirement_flag & KS_REQUIREMENT) + { + GET_BIT(~data, attr->index % 8, val); + } + return sprintf(buf, "%d\n", val); +} + +static ssize_t set_dsfp_power_on(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + return count; +} + +static ssize_t get_dsfp_power_on(struct device *dev, struct device_attribute *da, + char *buf) +{ + u8 val = 1; + return sprintf(buf, "%d\n", val); +} + +/*DSFP CPLD 0:reset 1:not reset. KWAI 0:not reset 1:reset*/ +static ssize_t get_dsfp_reset(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); + u8 reg, data =0; + + GET_DSFP_RST_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + data = (data >> ((attr->index % 4)*2)) & 0x3; + + return sprintf(buf, "%d\n", !data); +} + +static ssize_t set_dsfp_reset(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); + u8 reg, data = 0; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + GET_DSFP_RST_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + CLEAR_BIT(data, (attr->index % 4)*2); + CLEAR_BIT(data, ((attr->index % 4)*2+1)); + data |= ((!val) & 0x3) << ((attr->index % 4)*2); + + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} + +/*DSFP CPLD 0:Low 1:High. KWAI 0:High 1:Low*/ +static ssize_t get_dsfp_lowpower(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); + u8 data = 0, val = 0, reg; + u32 port_bit = 0; + if((attr->index >= 44 && attr->index < 48) || (attr->index >= 24 && attr->index < 28)) + port_bit = attr->index % 4; + else + port_bit = attr->index % 8; + + GET_DSFP_LOWPOWER_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, port_bit, val); + return sprintf(buf, "0x%02x\n", !val);//convert val for Kwai requirement +} + +static ssize_t set_dsfp_lowpower(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); + u8 data = 0, reg; + long val = 0; + u32 port_bit = 0; + if((attr->index >= 44 && attr->index < 48) || (attr->index >= 24 && attr->index < 28)) + port_bit = attr->index % 4; + else + port_bit = attr->index % 8; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + GET_DSFP_LOWPOWER_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + if(val)//convert val for Kwai requirement + CLEAR_BIT(data, port_bit); + else + SET_BIT(data, port_bit); + + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} +#endif //DSFP + + +#if PEGA_RD(QSFP) + +#define QSFP_PRESENT_ADDRESS 0x24 +#define QSFP_RESET_ADDRESS_BASE 0X2A +#define QSFP_IRQ_STATUS_ADDRESS 0x2F +#define QSFP_LOW_POWER_ADDRESS 0x33 + + +#define GET_QSFP_STATUS_ADDRESS(idx, reg) \ + reg = QSFP_PRESENT_ADDRESS + +#define GET_QSFP_RST_ADDRESS(idx, reg) \ + reg = QSFP_RESET_ADDRESS_BASE + ((idx % QSFP_FIRST_PORT) / 4) + +#define GET_QSFP_LOWPOWER_ADDRESS(idx, reg) \ + reg = QSFP_LOW_POWER_ADDRESS + +#define GET_QSFP_IRQ_STATUS_ADDRESS(idx, reg) \ + reg = QSFP_IRQ_STATUS_ADDRESS + +static ssize_t get_qsfp_present(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); + u8 data = 0, val = 0, reg; + + GET_QSFP_STATUS_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, attr->index % 8, val); + + if(requirement_flag & KS_REQUIREMENT) + { + GET_BIT(~data, attr->index % 8, val); + } + return sprintf(buf, "%d\n", val); +} +static ssize_t get_qsfp_irq_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); + u8 data = 0, val = 0, reg; + + GET_QSFP_IRQ_STATUS_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, attr->index % 8, val); + + if(requirement_flag & KS_REQUIREMENT) + { + GET_BIT(~data, attr->index % 8, val); + } + return sprintf(buf, "%d\n", val); +} +static ssize_t get_qsfp_power_on(struct device *dev, struct device_attribute *da, + char *buf) +{ + u8 val = 1; + return sprintf(buf, "%d\n", val); +} + +/*QSFP CPLD 0:reset 1:not reset. KWAI 0:not reset 1:reset*/ +static ssize_t get_qsfp_reset(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); + u8 reg, data =0; + + GET_QSFP_RST_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + data = (data >> ((attr->index % 4)*2)) & 0x3; + + return sprintf(buf, "%d\n", !data); +} + +static ssize_t set_qsfp_reset(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); + u8 reg, data = 0; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + + GET_QSFP_RST_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + CLEAR_BIT(data, (attr->index % 4)*2); + CLEAR_BIT(data, ((attr->index % 4)*2+1)); + data |= ((!val) & 0x3) << ((attr->index % 4)*2); + + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} + +/*QSFP-DD CPLD 0:High 1:Low. KWAI 0:High 1:Low*/ +static ssize_t get_qsfp_lowpower(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); + u8 data = 0, val = 0, reg; + + GET_QSFP_LOWPOWER_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, (attr->index % 8), val); + return sprintf(buf, "0x%02x\n", val); +} + +static ssize_t set_qsfp_lowpower(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); + u8 data = 0, reg; + long val = 0; + + if (kstrtol(buf, 16, &val)) + { + return -EINVAL; + } + GET_QSFP_LOWPOWER_ADDRESS(attr->index, reg); + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + if(val) + SET_BIT(data, (attr->index % 8)); + else + CLEAR_BIT(data, (attr->index % 8)); + + pegatron_fn8656_bnf_cpld_write(client->addr, reg, data); + + return count; +} +#endif //QSFP + +#define MAX_SFP_NUM_BIT_MASK 0xffffffffffffffUL //56 sfp + +static ssize_t get_all_port_sfp_present(struct device *dev, struct device_attribute *da, + char *buf) +{ + u8 data1 = 0, data2 = 0,i = 0; + ssize_t present_bit_map = 0 , tmp = 0; + for (i = 0 ; i < 4;i++) + { + data1 = pegatron_fn8656_bnf_cpld_read(CPLDB_ADDRESS, DSFP_PRESENT_ADDRESS + i); + data2 = pegatron_fn8656_bnf_cpld_read(CPLDC_ADDRESS, DSFP_PRESENT_ADDRESS + i); + present_bit_map |= (data1 & 0xffUL) << i*8 | (data2 & 0xffUL) << (32 + i*8); + } + + /*8 registers,only 56bits in use, bit29-32 & bit53-56 reserved */ + tmp = (present_bit_map & 0xfffffffUL) | ((present_bit_map >> 4) & ~0xfffffffUL); + present_bit_map = (tmp & 0xffffffffffffUL) | ((tmp >> 4) & ~0xffffffffffffUL); + if(requirement_flag & KS_REQUIREMENT) + { + present_bit_map = (~present_bit_map) & MAX_SFP_NUM_BIT_MASK; + } + + pega_print(DEBUG, "present_bit_map:0x%lx\r\n", present_bit_map); + + return sprintf(buf, "0x%lx\n", present_bit_map); +} + +static ssize_t get_all_port_sfp_power_on(struct device *dev, struct device_attribute *da, + char *buf) +{ + size_t poweron_bit_map = MAX_SFP_NUM_BIT_MASK; + pega_print(DEBUG, "poweron_bit_map:%lx\r\n", poweron_bit_map); + return sprintf(buf, "0x%lx\n", poweron_bit_map); +} + +static ssize_t get_cpld_alias(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + ssize_t ret_len = 0; + + switch(client->addr) + { + case CPLDA_ADDRESS: + ret_len = sprintf(buf, "CPLD-A"); + break; + case CPLDB_ADDRESS: + ret_len = sprintf(buf, "CPLD-B"); + break; + case CPLDC_ADDRESS: + ret_len = sprintf(buf, "CPLD-C"); + break; + case CPLDD_ADDRESS: + ret_len = sprintf(buf, "CPLD-D"); + break; + default: + pega_print(WARNING, "Error address %x\n", client->addr); + break; + } + + return ret_len; +} + +static ssize_t get_cpld_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "LCMXO2-1200HC\n"); +} +static ssize_t get_cpld_board_version(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 data = 0, reg = CPLD_VERSION_REG; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + + return sprintf(buf, "0x%02x\n", (data & CPLD_HW_VERSION_BIT_MSK) >> CPLD_HW_VERSION_BIT_OFFSET); +} +static ssize_t get_cpld_num(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "%d\n",CPLD_MAX_NUM); +} +static ssize_t get_sfp_num(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "%d\n",SFP_PORT_MAX_NUM); +} +static ssize_t get_cpld_debug(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int count = 0; + + switch (attr->index) { + case 0: + count = sprintf(buf, "%s\n", sysled_debug); + break; + case 1: + count = sprintf(buf, "%s\n", sfp_debug); + break; + case 2: + count = sprintf(buf, "%s\n", cpld_debug); + break; + default: + pega_print(WARNING,"no debug info\n"); + } + return count; +} + +static ssize_t set_cpld_debug(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + int debug_len = (count < MAX_DEBUG_INFO_LEN) ? count : MAX_DEBUG_INFO_LEN; + + switch (attr->index) { + case 0: + memset(sysled_debug,0,strlen(sysled_debug)); + strncpy(sysled_debug, buf, debug_len); + break; + case 1: + memset(sfp_debug,0,strlen(sysled_debug)); + strncpy(sfp_debug, buf, debug_len); + break; + case 2: + memset(cpld_debug,0,strlen(sysled_debug)); + strncpy(cpld_debug, buf, debug_len); + break; + default: + pega_print(WARNING,"no debug info\n"); + } + return debug_len; +} + +/* +static ssize_t set_sfp_debug(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + strncpy(sysled_debug,buf, (count < MAX_DEBUG_INFO_LEN) ? count : MAX_DEBUG_INFO_LEN); + + return (count < MAX_DEBUG_INFO_LEN) ? count : MAX_DEBUG_INFO_LEN; +} + +static ssize_t set_sysled_debug(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + strncpy(sysled_debug,buf, (count < MAX_DEBUG_INFO_LEN) ? count : MAX_DEBUG_INFO_LEN); + + return (count < MAX_DEBUG_INFO_LEN) ? count : MAX_DEBUG_INFO_LEN; +} +*/ + +static SENSOR_DEVICE_ATTR(cpld_hw_version, S_IRUGO, read_cpld_HWversion, NULL, 0); +static SENSOR_DEVICE_ATTR(cpld_sw_version, S_IRUGO, read_cpld_SWversion, NULL, 0); +static SENSOR_DEVICE_ATTR(cpld_alias, S_IRUGO, get_cpld_alias, NULL, 0); +static SENSOR_DEVICE_ATTR(cpld_type, S_IRUGO, get_cpld_type, NULL, 0); +static SENSOR_DEVICE_ATTR(cpld_board_version, S_IRUGO, get_cpld_board_version, NULL, 0); +static SENSOR_DEVICE_ATTR(cpld_num, S_IRUGO, get_cpld_num, NULL, 0); +static SENSOR_DEVICE_ATTR(sfp_port_num, S_IRUGO, get_sfp_num, NULL, 0); +static SENSOR_DEVICE_ATTR(debug_cpld, S_IRUGO | S_IWUSR, get_cpld_debug, set_cpld_debug, 2); +static SENSOR_DEVICE_ATTR(debug_sfp, S_IRUGO | S_IWUSR, get_cpld_debug, set_cpld_debug, 1); +static SENSOR_DEVICE_ATTR(debug_sysled, S_IRUGO | S_IWUSR, get_cpld_debug, set_cpld_debug, 0); + +static SENSOR_DEVICE_ATTR(cpld_allled_ctrl, S_IRUGO | S_IWUSR, show_led_status, set_led_status, ALL_LED_CTRL); +static SENSOR_DEVICE_ATTR(serial_led_enable, S_IRUGO | S_IWUSR, show_led_status, set_led_status, SERIAL_LED_CTRL); +static SENSOR_DEVICE_ATTR(sys_led, S_IRUGO | S_IWUSR, show_led_status, set_led_status, SYS_LED_CTRL); +static SENSOR_DEVICE_ATTR(pwr_led, S_IRUGO , show_led_status, set_led_status, PWR_LED_CTRL); +static SENSOR_DEVICE_ATTR(fan_led, S_IRUGO , show_led_status, set_led_status, FAN_LED_CTRL); +static SENSOR_DEVICE_ATTR(loc_led, S_IRUGO | S_IWUSR, show_led_status, set_led_status, LOC_LED_CTRL); +static SENSOR_DEVICE_ATTR(sys_rst, S_IRUGO | S_IWUSR, show_sys_rst, set_sys_rst, 0); +static SENSOR_DEVICE_ATTR(reboot_cause, S_IRUGO , show_reboot_cause, NULL, 0); + +static SENSOR_DEVICE_ATTR(eeprom_write_enable, S_IRUGO | S_IWUSR, show_eeprom_write_enable, set_eeprom_write_enable, 0); +static SENSOR_DEVICE_ATTR(psu_1_status, S_IRUGO, read_psu_status, NULL, 0); +static SENSOR_DEVICE_ATTR(psu_2_status, S_IRUGO, read_psu_status, NULL, 1); +static SENSOR_DEVICE_ATTR(int_status, S_IRUGO, read_int_status, NULL, 0); + +static SENSOR_DEVICE_ATTR(sfp_all_present, S_IRUGO, get_all_port_sfp_present, NULL, 0); +static SENSOR_DEVICE_ATTR(sfp_all_power_on, S_IRUGO, get_all_port_sfp_power_on, NULL, 0); + +#define SET_DSFP_ATTR(_num) \ + static SENSOR_DEVICE_ATTR(sfp##_num##_present, S_IRUGO, get_dsfp_present, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_reset, S_IRUGO | S_IWUSR, get_dsfp_reset, set_dsfp_reset, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_lowpower, S_IRUGO | S_IWUSR, get_dsfp_lowpower, set_dsfp_lowpower, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_irq_status, S_IRUGO, get_dsfp_irq_status, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_power_on, S_IRUGO | S_IWUSR, get_dsfp_power_on, set_dsfp_power_on,_num-1) + +#define SET_QSFP_ATTR(_num) \ + static SENSOR_DEVICE_ATTR(sfp##_num##_present, S_IRUGO, get_qsfp_present, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_reset, S_IRUGO | S_IWUSR, get_qsfp_reset, set_qsfp_reset, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_lowpower, S_IRUGO | S_IWUSR, get_qsfp_lowpower, set_qsfp_lowpower, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_irq_status, S_IRUGO, get_qsfp_irq_status, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(sfp##_num##_power_on, S_IRUGO | S_IWUSR, get_qsfp_power_on, NULL,_num-1) + +SET_DSFP_ATTR(1);SET_DSFP_ATTR(2);SET_DSFP_ATTR(3);SET_DSFP_ATTR(4);SET_DSFP_ATTR(5);SET_DSFP_ATTR(6);SET_DSFP_ATTR(7);SET_DSFP_ATTR(8);SET_DSFP_ATTR(9); +SET_DSFP_ATTR(10);SET_DSFP_ATTR(11);SET_DSFP_ATTR(12);SET_DSFP_ATTR(13);SET_DSFP_ATTR(14);SET_DSFP_ATTR(15);SET_DSFP_ATTR(16);SET_DSFP_ATTR(17);SET_DSFP_ATTR(18); +SET_DSFP_ATTR(19);SET_DSFP_ATTR(20);SET_DSFP_ATTR(21);SET_DSFP_ATTR(22);SET_DSFP_ATTR(23);SET_DSFP_ATTR(24);SET_DSFP_ATTR(25);SET_DSFP_ATTR(26);SET_DSFP_ATTR(27); +SET_DSFP_ATTR(28);SET_DSFP_ATTR(29);SET_DSFP_ATTR(30);SET_DSFP_ATTR(31);SET_DSFP_ATTR(32);SET_DSFP_ATTR(33);SET_DSFP_ATTR(34);SET_DSFP_ATTR(35);SET_DSFP_ATTR(36); +SET_DSFP_ATTR(37);SET_DSFP_ATTR(38);SET_DSFP_ATTR(39);SET_DSFP_ATTR(40);SET_DSFP_ATTR(41);SET_DSFP_ATTR(42);SET_DSFP_ATTR(43);SET_DSFP_ATTR(44);SET_DSFP_ATTR(45); +SET_DSFP_ATTR(46);SET_DSFP_ATTR(47);SET_DSFP_ATTR(48); +SET_QSFP_ATTR(49);SET_QSFP_ATTR(50);SET_QSFP_ATTR(51);SET_QSFP_ATTR(52);SET_QSFP_ATTR(53);SET_QSFP_ATTR(54);SET_QSFP_ATTR(55);SET_QSFP_ATTR(56); + +static struct attribute *pegatron_fn8656_bnf_cpldA_attributes[] = { + &sensor_dev_attr_cpld_hw_version.dev_attr.attr, + &sensor_dev_attr_cpld_sw_version.dev_attr.attr, + &sensor_dev_attr_cpld_alias.dev_attr.attr, + &sensor_dev_attr_cpld_type.dev_attr.attr, + &sensor_dev_attr_cpld_board_version.dev_attr.attr, + &sensor_dev_attr_cpld_num.dev_attr.attr, + &sensor_dev_attr_debug_cpld.dev_attr.attr, + &sensor_dev_attr_debug_sfp.dev_attr.attr, + &sensor_dev_attr_debug_sysled.dev_attr.attr, + + &sensor_dev_attr_cpld_allled_ctrl.dev_attr.attr, + &sensor_dev_attr_serial_led_enable.dev_attr.attr, + &sensor_dev_attr_sys_led.dev_attr.attr, + &sensor_dev_attr_pwr_led.dev_attr.attr, + &sensor_dev_attr_fan_led.dev_attr.attr, + &sensor_dev_attr_eeprom_write_enable.dev_attr.attr, + + &sensor_dev_attr_psu_1_status.dev_attr.attr, + &sensor_dev_attr_psu_2_status.dev_attr.attr, + &sensor_dev_attr_int_status.dev_attr.attr, + NULL +}; + +static struct attribute *pegatron_fn8656_bnf_cpldB_attributes[] = { + &sensor_dev_attr_cpld_hw_version.dev_attr.attr, + &sensor_dev_attr_cpld_sw_version.dev_attr.attr, + &sensor_dev_attr_cpld_alias.dev_attr.attr, + &sensor_dev_attr_cpld_type.dev_attr.attr, + &sensor_dev_attr_cpld_board_version.dev_attr.attr, + &sensor_dev_attr_sfp_port_num.dev_attr.attr, + + &sensor_dev_attr_serial_led_enable.dev_attr.attr, + + &sensor_dev_attr_sfp_all_present.dev_attr.attr, + &sensor_dev_attr_sfp_all_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp1_present.dev_attr.attr, + &sensor_dev_attr_sfp1_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp1_reset.dev_attr.attr, + &sensor_dev_attr_sfp1_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp1_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp2_present.dev_attr.attr, + &sensor_dev_attr_sfp2_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp2_reset.dev_attr.attr, + &sensor_dev_attr_sfp2_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp2_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp3_present.dev_attr.attr, + &sensor_dev_attr_sfp3_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp3_reset.dev_attr.attr, + &sensor_dev_attr_sfp3_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp3_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp4_present.dev_attr.attr, + &sensor_dev_attr_sfp4_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp4_reset.dev_attr.attr, + &sensor_dev_attr_sfp4_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp4_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp5_present.dev_attr.attr, + &sensor_dev_attr_sfp5_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp5_reset.dev_attr.attr, + &sensor_dev_attr_sfp5_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp5_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp6_present.dev_attr.attr, + &sensor_dev_attr_sfp6_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp6_reset.dev_attr.attr, + &sensor_dev_attr_sfp6_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp6_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp7_present.dev_attr.attr, + &sensor_dev_attr_sfp7_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp7_reset.dev_attr.attr, + &sensor_dev_attr_sfp7_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp7_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp8_present.dev_attr.attr, + &sensor_dev_attr_sfp8_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp8_reset.dev_attr.attr, + &sensor_dev_attr_sfp8_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp8_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp9_present.dev_attr.attr, + &sensor_dev_attr_sfp9_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp9_reset.dev_attr.attr, + &sensor_dev_attr_sfp9_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp9_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp10_present.dev_attr.attr, + &sensor_dev_attr_sfp10_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp10_reset.dev_attr.attr, + &sensor_dev_attr_sfp10_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp10_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp11_present.dev_attr.attr, + &sensor_dev_attr_sfp11_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp11_reset.dev_attr.attr, + &sensor_dev_attr_sfp11_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp11_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp12_present.dev_attr.attr, + &sensor_dev_attr_sfp12_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp12_reset.dev_attr.attr, + &sensor_dev_attr_sfp12_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp12_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp13_present.dev_attr.attr, + &sensor_dev_attr_sfp13_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp13_reset.dev_attr.attr, + &sensor_dev_attr_sfp13_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp13_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp14_present.dev_attr.attr, + &sensor_dev_attr_sfp14_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp14_reset.dev_attr.attr, + &sensor_dev_attr_sfp14_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp14_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp15_present.dev_attr.attr, + &sensor_dev_attr_sfp15_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp15_reset.dev_attr.attr, + &sensor_dev_attr_sfp15_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp15_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp16_present.dev_attr.attr, + &sensor_dev_attr_sfp16_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp16_reset.dev_attr.attr, + &sensor_dev_attr_sfp16_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp16_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp17_present.dev_attr.attr, + &sensor_dev_attr_sfp17_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp17_reset.dev_attr.attr, + &sensor_dev_attr_sfp17_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp17_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp18_present.dev_attr.attr, + &sensor_dev_attr_sfp18_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp18_reset.dev_attr.attr, + &sensor_dev_attr_sfp18_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp18_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp19_present.dev_attr.attr, + &sensor_dev_attr_sfp19_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp19_reset.dev_attr.attr, + &sensor_dev_attr_sfp19_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp19_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp20_present.dev_attr.attr, + &sensor_dev_attr_sfp20_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp20_reset.dev_attr.attr, + &sensor_dev_attr_sfp20_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp20_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp21_present.dev_attr.attr, + &sensor_dev_attr_sfp21_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp21_reset.dev_attr.attr, + &sensor_dev_attr_sfp21_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp21_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp22_present.dev_attr.attr, + &sensor_dev_attr_sfp22_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp22_reset.dev_attr.attr, + &sensor_dev_attr_sfp22_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp22_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp23_present.dev_attr.attr, + &sensor_dev_attr_sfp23_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp23_reset.dev_attr.attr, + &sensor_dev_attr_sfp23_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp23_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp24_present.dev_attr.attr, + &sensor_dev_attr_sfp24_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp24_reset.dev_attr.attr, + &sensor_dev_attr_sfp24_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp24_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp25_present.dev_attr.attr, + &sensor_dev_attr_sfp25_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp25_reset.dev_attr.attr, + &sensor_dev_attr_sfp25_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp25_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp26_present.dev_attr.attr, + &sensor_dev_attr_sfp26_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp26_reset.dev_attr.attr, + &sensor_dev_attr_sfp26_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp26_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp27_present.dev_attr.attr, + &sensor_dev_attr_sfp27_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp27_reset.dev_attr.attr, + &sensor_dev_attr_sfp27_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp27_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp28_present.dev_attr.attr, + &sensor_dev_attr_sfp28_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp28_reset.dev_attr.attr, + &sensor_dev_attr_sfp28_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp28_power_on.dev_attr.attr, + + NULL +}; + +static struct attribute* pegatron_fn8656_bnf_cpldC_attributes[] = { + &sensor_dev_attr_cpld_hw_version.dev_attr.attr, + &sensor_dev_attr_cpld_sw_version.dev_attr.attr, + &sensor_dev_attr_cpld_alias.dev_attr.attr, + &sensor_dev_attr_cpld_type.dev_attr.attr, + &sensor_dev_attr_cpld_board_version.dev_attr.attr, + + &sensor_dev_attr_serial_led_enable.dev_attr.attr, + + &sensor_dev_attr_sfp_all_present.dev_attr.attr, + &sensor_dev_attr_sfp_all_power_on.dev_attr.attr, + + /*dsfp 29-48*/ + &sensor_dev_attr_sfp29_present.dev_attr.attr, + &sensor_dev_attr_sfp29_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp29_reset.dev_attr.attr, + &sensor_dev_attr_sfp29_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp29_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp30_present.dev_attr.attr, + &sensor_dev_attr_sfp30_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp30_reset.dev_attr.attr, + &sensor_dev_attr_sfp30_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp30_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp31_present.dev_attr.attr, + &sensor_dev_attr_sfp31_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp31_reset.dev_attr.attr, + &sensor_dev_attr_sfp31_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp31_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp32_present.dev_attr.attr, + &sensor_dev_attr_sfp32_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp32_reset.dev_attr.attr, + &sensor_dev_attr_sfp32_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp32_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp33_present.dev_attr.attr, + &sensor_dev_attr_sfp33_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp33_reset.dev_attr.attr, + &sensor_dev_attr_sfp33_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp33_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp34_present.dev_attr.attr, + &sensor_dev_attr_sfp34_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp34_reset.dev_attr.attr, + &sensor_dev_attr_sfp34_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp34_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp35_present.dev_attr.attr, + &sensor_dev_attr_sfp35_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp35_reset.dev_attr.attr, + &sensor_dev_attr_sfp35_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp35_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp36_present.dev_attr.attr, + &sensor_dev_attr_sfp36_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp36_reset.dev_attr.attr, + &sensor_dev_attr_sfp36_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp36_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp37_present.dev_attr.attr, + &sensor_dev_attr_sfp37_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp37_reset.dev_attr.attr, + &sensor_dev_attr_sfp37_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp37_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp38_present.dev_attr.attr, + &sensor_dev_attr_sfp38_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp38_reset.dev_attr.attr, + &sensor_dev_attr_sfp38_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp38_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp39_present.dev_attr.attr, + &sensor_dev_attr_sfp39_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp39_reset.dev_attr.attr, + &sensor_dev_attr_sfp39_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp39_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp40_present.dev_attr.attr, + &sensor_dev_attr_sfp40_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp40_reset.dev_attr.attr, + &sensor_dev_attr_sfp40_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp40_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp41_present.dev_attr.attr, + &sensor_dev_attr_sfp41_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp41_reset.dev_attr.attr, + &sensor_dev_attr_sfp41_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp41_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp42_present.dev_attr.attr, + &sensor_dev_attr_sfp42_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp42_reset.dev_attr.attr, + &sensor_dev_attr_sfp42_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp42_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp43_present.dev_attr.attr, + &sensor_dev_attr_sfp43_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp43_reset.dev_attr.attr, + &sensor_dev_attr_sfp43_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp43_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp44_present.dev_attr.attr, + &sensor_dev_attr_sfp44_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp44_reset.dev_attr.attr, + &sensor_dev_attr_sfp44_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp44_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp45_present.dev_attr.attr, + &sensor_dev_attr_sfp45_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp45_reset.dev_attr.attr, + &sensor_dev_attr_sfp45_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp45_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp46_present.dev_attr.attr, + &sensor_dev_attr_sfp46_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp46_reset.dev_attr.attr, + &sensor_dev_attr_sfp46_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp46_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp47_present.dev_attr.attr, + &sensor_dev_attr_sfp47_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp47_reset.dev_attr.attr, + &sensor_dev_attr_sfp47_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp47_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp48_present.dev_attr.attr, + &sensor_dev_attr_sfp48_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp48_reset.dev_attr.attr, + &sensor_dev_attr_sfp48_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp48_power_on.dev_attr.attr, + + /*qsfp 49-56*/ + &sensor_dev_attr_sfp49_present.dev_attr.attr, + &sensor_dev_attr_sfp49_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp49_reset.dev_attr.attr, + &sensor_dev_attr_sfp49_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp49_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp50_present.dev_attr.attr, + &sensor_dev_attr_sfp50_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp50_reset.dev_attr.attr, + &sensor_dev_attr_sfp50_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp50_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp51_present.dev_attr.attr, + &sensor_dev_attr_sfp51_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp51_reset.dev_attr.attr, + &sensor_dev_attr_sfp51_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp51_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp52_present.dev_attr.attr, + &sensor_dev_attr_sfp52_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp52_reset.dev_attr.attr, + &sensor_dev_attr_sfp52_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp52_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp53_present.dev_attr.attr, + &sensor_dev_attr_sfp53_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp53_reset.dev_attr.attr, + &sensor_dev_attr_sfp53_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp53_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp54_present.dev_attr.attr, + &sensor_dev_attr_sfp54_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp54_reset.dev_attr.attr, + &sensor_dev_attr_sfp54_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp54_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp55_present.dev_attr.attr, + &sensor_dev_attr_sfp55_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp55_reset.dev_attr.attr, + &sensor_dev_attr_sfp55_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp55_power_on.dev_attr.attr, + + &sensor_dev_attr_sfp56_present.dev_attr.attr, + &sensor_dev_attr_sfp56_lowpower.dev_attr.attr, + &sensor_dev_attr_sfp56_reset.dev_attr.attr, + &sensor_dev_attr_sfp56_irq_status.dev_attr.attr, + &sensor_dev_attr_sfp56_power_on.dev_attr.attr, + NULL +}; + +static struct attribute *pegatron_fn8656_bnf_cpldD_attributes[] = { + &sensor_dev_attr_cpld_hw_version.dev_attr.attr, + &sensor_dev_attr_cpld_sw_version.dev_attr.attr, + &sensor_dev_attr_loc_led.dev_attr.attr, + &sensor_dev_attr_cpld_alias.dev_attr.attr, + &sensor_dev_attr_cpld_type.dev_attr.attr, + &sensor_dev_attr_cpld_board_version.dev_attr.attr, + &sensor_dev_attr_sys_rst.dev_attr.attr, + &sensor_dev_attr_reboot_cause.dev_attr.attr, + + NULL +}; + +static ssize_t get_lm75b_temp(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u16 data = 0; + u8 reg = LM75B_TEMP_REG; + + data = pegatron_fn8656_bnf_cpld_read(client->addr, reg); + pega_print(DEBUG,"%s - addr: 0x%x, reg: %x, data: %x\r\n", __func__, client->addr, reg, data); + sprintf(buf, "%d\n", data); + return strlen(buf); + +} + +static SENSOR_DEVICE_ATTR(lm75b_temp, S_IRUGO, get_lm75b_temp, NULL, 0); + +static struct attribute *pegatron_fn8656_bnf_lm75b_attributes[] = { + &sensor_dev_attr_lm75b_temp.dev_attr.attr, + NULL +}; + +static const struct attribute_group pegatron_fn8656_bnf_cpldA_group = { .attrs = pegatron_fn8656_bnf_cpldA_attributes}; +static const struct attribute_group pegatron_fn8656_bnf_cpldB_group = { .attrs = pegatron_fn8656_bnf_cpldB_attributes}; +static const struct attribute_group pegatron_fn8656_bnf_cpldC_group = { .attrs = pegatron_fn8656_bnf_cpldC_attributes}; +static const struct attribute_group pegatron_fn8656_bnf_cpldD_group = { .attrs = pegatron_fn8656_bnf_cpldD_attributes}; +static const struct attribute_group pegatron_fn8656_bnf_lm75b_group = { .attrs = pegatron_fn8656_bnf_lm75b_attributes}; + +static void pegatron_fn8656_bnf_cpld_add_client(struct i2c_client *client) +{ + struct cpld_client_node *node = kzalloc(sizeof(struct cpld_client_node), GFP_KERNEL); + + if (!node) { + pega_print(ERR, "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 pegatron_fn8656_bnf_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 int pegatron_fn8656_bnf_cpld_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + pega_print(ERR, "i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + /* Register sysfs hooks */ + switch(client->addr) + { + case CPLDA_ADDRESS: + status = sysfs_create_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldA_group); + break; + case CPLDB_ADDRESS: + status = sysfs_create_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldB_group); + break; + case CPLDC_ADDRESS: + status = sysfs_create_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldC_group); + break; + case CPLDD_ADDRESS: + status = sysfs_create_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldD_group); + break; + case LM75B_ADDRESS: + status = sysfs_create_group(&client->dev.kobj, &pegatron_fn8656_bnf_lm75b_group); + break; + default: + pega_print(WARNING, "i2c_check_CPLD failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + break; + } + + if (status) { + goto exit; + } + + pega_print(INFO, "chip found\n"); + pegatron_fn8656_bnf_cpld_add_client(client); + + return 0; + +exit: + return status; +} + +static int pegatron_fn8656_bnf_cpld_remove(struct i2c_client *client) +{ + switch(client->addr) + { + case CPLDA_ADDRESS: + sysfs_remove_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldA_group); + break; + case CPLDB_ADDRESS: + sysfs_remove_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldB_group); + break; + case CPLDC_ADDRESS: + sysfs_remove_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldC_group); + break; + case CPLDD_ADDRESS: + sysfs_remove_group(&client->dev.kobj, &pegatron_fn8656_bnf_cpldD_group); + break; + case LM75B_ADDRESS: + sysfs_remove_group(&client->dev.kobj, &pegatron_fn8656_bnf_lm75b_group); + break; + default: + pega_print(WARNING, "i2c_remove_CPLD failed (0x%x)\n", client->addr); + break; + } + + + pegatron_fn8656_bnf_cpld_remove_client(client); + return 0; +} + +static const struct i2c_device_id pegatron_fn8656_bnf_cpld_id[] = { + { "fn8656_bnf_cpld", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pegatron_fn8656_bnf_cpld_id); + +static struct i2c_driver pegatron_fn8656_bnf_cpld_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "pegatron_fn8656_bnf_cpld", + }, + .probe = pegatron_fn8656_bnf_cpld_probe, + .remove = pegatron_fn8656_bnf_cpld_remove, + .id_table = pegatron_fn8656_bnf_cpld_id, + .address_list = normal_i2c, +}; + +static int __init pegatron_fn8656_bnf_cpld_init(void) +{ + mutex_init(&list_lock); + + return i2c_add_driver(&pegatron_fn8656_bnf_cpld_driver); +} + +static void __exit pegatron_fn8656_bnf_cpld_exit(void) +{ + i2c_del_driver(&pegatron_fn8656_bnf_cpld_driver); +} + +module_param(loglevel,uint,0644); +module_param(requirement_flag,uint,0664); + +MODULE_PARM_DESC(loglevel,"0x01-LOG_ERR,0x02-LOG_WARNING,0x04-LOG_INFO,0x08-LOG_DEBUG"); +MODULE_PARM_DESC(requirement_flag,"custom requirement.eg:requirement_flag=1 for KS"); + +MODULE_AUTHOR("Peter5 Lin "); +MODULE_DESCRIPTION("pegatron_fn8656_bnf_cpld driver"); +MODULE_LICENSE("GPL"); + +module_init(pegatron_fn8656_bnf_cpld_init); +module_exit(pegatron_fn8656_bnf_cpld_exit); diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_psu.c b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_psu.c new file mode 100644 index 000000000000..b15ce5e8e98f --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_psu.c @@ -0,0 +1,919 @@ +/* + * 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 "pegatron_pub.h" + +#undef PEGA_DEBUG +/*#define pega_DEBUG*/ +#ifdef PEGA_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif /* DEBUG */ + +#define PSU_EEPROM_FRU_50_ADDRESS 0x50 +#define PSU_EEPROM_FRU_51_ADDRESS 0x51 +#define PSU_58_ADDRESS 0x58 +#define PSU_59_ADDRESS 0x59 +#define PSU_VOUT_MODE_REG 0x20 +#define PSU_VOUT_STATUS_REG 0x7A +#define PSU_IOUT_STATUS_REG 0x7B +#define PSU_INPUT_STATUS_REG 0x7C +#define PSU_TEMP_STATUS_REG 0x7D +#define PSU_FANS_1_2_STATUS 0x81 + + +#define PSU_VOUT_OVER_VOLTAGE_BIT 7 +#define PSU_IOUT_OVER_CURRENT_FAULT_BIT 7 +#define PSU_IOUT_OVER_CURRENT_WARNING_BIT 5 +#define PSU_IPUT_OVER_CURRENT_WARNING_BIT 1 +#define PSU_IPUT_INSUFFICIENT_BIT 3 +#define PSU_TEMP_OVER_TEMP_FAULT_BIT 7 +#define PSU_TEMP_OVER_TEMP_WARNING_BIT 6 + + +#define PM_BUS_BLOCK_MAX_LEN 32 + +enum _sysfs_attributes { + PSU_V_IN = 0, + PSU_I_IN, + PSU_V_OUT, + PSU_I_OUT, + PSU_TEMP1_INPUT, + PSU_TEMP2_INPUT, + PSU_TEMP3_INPUT, + PSU_FAN1_SPEED, + + PSU_P_OUT, + PSU_P_IN, + PSU_PMBUS_REVISION, + PSU_MFR_ID, + PSU_MFR_MODEL, + PSU_MFR_REVISION, + PSU_MFR_LOCATION, + PSU_MFR_DATE, + PSU_MFR_SERIAL, + + PSU_VIN_MIN, + PSU_VIN_MAX, + PSU_IIN_MAX, + PSU_PIN_MAX, + PSU_VOUT_MIN, + PSU_VOUT_MAX, + PSU_IOUT_MAX, + PSU_POUT_MAX, + + //PSU_FAN1_FAULT, + //PSU_FAN1_DUTY_CYCLE, + PSU_MFR_TEMP1_MAX, + PSU_MFR_TEMP2_MAX, + PSU_MFR_TEMP3_MAX, + + PSU_ATTR_END +}; +enum _psu_pmbus_reg{ + PSU_VIN_REG = 0x88, + PSU_IIN_REG, + + PSU_VOUT_REG = 0x8B, + PSU_IOUT_REG, + PSU_TEMP1_REG, + PSU_TEMP2_REG, + PSU_TEMP3_REG, + PSU_FAN_SPEED_1_REG, + + PSU_POUT_REG = 0x96, + PSU_PIN_REG, + PSU_PMBUS_REVISION_REG, + PSU_MFR_ID_REG, + PSU_MFR_MODEL_REG, + PSU_MFR_REVISION_REG, + PSU_MFR_LOCATION_REG, + PSU_MFR_DATE_REG, + PSU_MFR_SERIAL_REG, + + PSU_VIN_MIN_REG = 0xA0, + PSU_VIN_MAX_REG, + PSU_IIN_MAX_REG, + PSU_PIN_MAX_REG, + PSU_VOUT_MIN_REG, + PSU_VOUT_MAX_REG, + PSU_IOUT_MAX_REG, + PSU_POUT_MAX_REG, + + PSU_MFR_TEMP1_MAX_REG = 0xC0, + PSU_MFR_TEMP2_MAX_REG, + PSU_MFR_TEMP3_MAX_REG, + +}; +u8 psu_pmbus_reg_map[PSU_ATTR_END] = { + PSU_VIN_REG,PSU_IIN_REG,PSU_VOUT_REG,PSU_IOUT_REG,PSU_TEMP1_REG,PSU_TEMP2_REG,PSU_TEMP3_REG,PSU_FAN_SPEED_1_REG, + PSU_POUT_REG,PSU_PIN_REG,PSU_PMBUS_REVISION_REG,PSU_MFR_ID_REG, PSU_MFR_MODEL_REG,PSU_MFR_REVISION_REG , PSU_MFR_LOCATION_REG,PSU_MFR_DATE_REG ,PSU_MFR_SERIAL_REG, + PSU_VIN_MIN_REG,PSU_VIN_MAX_REG,PSU_IIN_MAX_REG,PSU_PIN_MAX_REG,PSU_VOUT_MIN_REG,PSU_VOUT_MAX_REG,PSU_IOUT_MAX_REG,PSU_POUT_MAX_REG, + PSU_MFR_TEMP1_MAX_REG,PSU_MFR_TEMP2_MAX_REG,PSU_MFR_TEMP3_MAX_REG +}; + +enum power_type { + POWER_AC = 0, + POWER_DC = 1 +}; + +#define GET_BIT(data, bit, value) value = (data >> bit) & 0x1 +#define SET_BIT(data, bit) data |= (1 << bit) +#define CLEAR_BIT(data, bit) data &= ~(1 << bit) + +struct psu_client_node { + struct i2c_client *client; + struct list_head list; +}; + +#define MAX_PSU_NUMS 2 +#define MAX_PSU_TEMP_SENSORS 3 +struct fn8656_bnf_psu_data { + struct i2c_client *client; + uint total_psu_num; + uint temp_sensor_num; + enum power_type type; + + int temp_max[MAX_PSU_TEMP_SENSORS]; + int temp_min[MAX_PSU_TEMP_SENSORS]; + int temp_crit[MAX_PSU_TEMP_SENSORS]; +}; +int psu_temp_max[MAX_PSU_TEMP_SENSORS] = {80, 90, 105}; +int psu_temp_min[MAX_PSU_TEMP_SENSORS] = {-2, 7, 14}; +int psu_temp_crit[MAX_PSU_TEMP_SENSORS] = {85, 95, 110}; +static const unsigned short normal_i2c[] = { PSU_EEPROM_FRU_50_ADDRESS,PSU_EEPROM_FRU_51_ADDRESS,PSU_58_ADDRESS, PSU_59_ADDRESS, I2C_CLIENT_END }; +static LIST_HEAD(psu_client_list); +static struct mutex list_lock; + +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; +static char debug[MAX_DEBUG_INFO_LEN] = "debug info: \n\ +echo 8 > */loglevel --- log driver's debug details \n"; + +static int pega_fn8656_bnf_psu_read(unsigned short addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct psu_client_node *psu_node = NULL; + int data = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &psu_client_list) + { + psu_node = list_entry(list_node, struct psu_client_node, list); + + if (psu_node->client->addr == addr) { + data = i2c_smbus_read_byte_data(psu_node->client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: 0x%x, data: 0x%x\r\n", addr, reg, data); + break; + } + } + + mutex_unlock(&list_lock); + + return data; +} + +static int pega_fn8656_bnf_psu_read_word(unsigned short addr, u8 reg) +{ + struct list_head *list_node = NULL; + struct psu_client_node *psu_node = NULL; + int data = -EPERM; + + mutex_lock(&list_lock); + + list_for_each(list_node, &psu_client_list) + { + psu_node = list_entry(list_node, struct psu_client_node, list); + + if (psu_node->client->addr == addr) { + data = i2c_smbus_read_word_data(psu_node->client, reg); + pega_print(DEBUG, "addr: 0x%x, reg: 0x%x, data: 0x%x\r\n", addr, reg, data); + break; + } + } + + mutex_unlock(&list_lock); + + return data; +} + +static int pega_fn8656_bnf_psu_read_block(unsigned short addr, u8 reg,u8* buf) +{ + struct list_head *list_node = NULL; + struct psu_client_node *psu_node = NULL; + int ret_val = -EPERM,i = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &psu_client_list) + { + psu_node = list_entry(list_node, struct psu_client_node, list); + + if (psu_node->client->addr == addr) { + ret_val = i2c_smbus_read_block_data(psu_node->client, reg, buf); + pega_print(DEBUG, "addr: 0x%x, reg: 0x%x, length:%d buf: ", addr, reg,ret_val); + for(i = 0;i < ret_val; i++){ + pega_print(DEBUG,"0x%x ",buf[i]); + } + break; + } + } + + mutex_unlock(&list_lock); + + return ret_val; +} + +static ssize_t read_psu_alarm(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 vout_data = 0, temp_data = 0,fan_data = 0,val = 0; + + vout_data = pega_fn8656_bnf_psu_read(client->addr, PSU_VOUT_STATUS_REG); + temp_data = pega_fn8656_bnf_psu_read(client->addr, PSU_TEMP_STATUS_REG); + fan_data = pega_fn8656_bnf_psu_read(client->addr, PSU_FANS_1_2_STATUS); + pega_print(DEBUG, "vout_data:0x%x,temp_data:0x%x,fan_data:0x%x\r\n", vout_data,temp_data,fan_data); + + //BIT0: Normal, Bit0: temprature status, BIT1:fan status, BIT2:vol status + if(temp_data & 0xff) + SET_BIT(val, 0); + if(fan_data & 0xff) + SET_BIT(val, 1); + if(vout_data & 0xff) + SET_BIT(val, 2); + + return sprintf(buf, "0x%02x\n", val); +} +static ssize_t get_psu_led_status(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 vout_data = 0, temp_data = 0,fan_data = 0,led_status = 0; + + vout_data = pega_fn8656_bnf_psu_read(client->addr, PSU_VOUT_STATUS_REG); + temp_data = pega_fn8656_bnf_psu_read(client->addr, PSU_TEMP_STATUS_REG); + fan_data = pega_fn8656_bnf_psu_read(client->addr, PSU_FANS_1_2_STATUS); + pega_print(DEBUG, "vout_data:0x%x,temp_data:0x%x,fan_data:0x%x\r\n", vout_data,temp_data,fan_data); + + //Kwai's led color definition:1 green,3 red + if(temp_data & 0xff || fan_data & 0xff || vout_data & 0xff) + { + led_status = 3; + } + else + { + led_status = 1; + } + + return sprintf(buf, "0x%02x\n", led_status); +} + + +static ssize_t read_psu_vout_over_voltage(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_VOUT_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_VOUT_OVER_VOLTAGE_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t read_psu_iout_over_current_fault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_IOUT_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_IOUT_OVER_CURRENT_FAULT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t read_psu_iout_over_current_warning(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_IOUT_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_IOUT_OVER_CURRENT_WARNING_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t read_psu_iput_over_current_warning(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_INPUT_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_IPUT_OVER_CURRENT_WARNING_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t read_psu_iput_insufficient(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_INPUT_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_IPUT_INSUFFICIENT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t read_psu_temp_over_temp_fault(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_TEMP_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_TEMP_OVER_TEMP_FAULT_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +static ssize_t read_psu_temp_over_temp_warning(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data = 0, reg = PSU_TEMP_STATUS_REG, val = 0; + + data = pega_fn8656_bnf_psu_read(client->addr, reg); + pega_print(DEBUG, "addr: 0x%x, reg: %x, data: %x\r\n", client->addr, reg, data); + GET_BIT(data, PSU_TEMP_OVER_TEMP_WARNING_BIT, val); + + return sprintf(buf, "%d\n", val); +} + +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 fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 read_value = 0; + int exponent, mantissa; + int multiplier = 1000; + int ret_val; + + read_value = pega_fn8656_bnf_psu_read_word(client->addr, psu_pmbus_reg_map[attr->index]); + exponent = two_complement_to_int(read_value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(read_value & 0x7ff, 11, 0x7ff); + + pega_print(DEBUG,"addr:0x%x, reg:0x%x, read_value:0x%x,exponent:%d,mantissa:%d\n",client->addr,psu_pmbus_reg_map[attr->index],read_value,exponent,mantissa); + if(exponent >= 0) + ret_val = (mantissa << exponent) * multiplier; + else + ret_val = (mantissa * multiplier) / (1 << -exponent); + + if(PSU_FAN1_SPEED == attr->index) + return sprintf(buf, "%d\n", ret_val/1000); + else if(PSU_POUT_MAX == attr->index) + ret_val = ret_val * 105 / 100; //the power_out_max can have a 5%tolenrence + return sprintf(buf, "%d.%d\n", ret_val/1000,ret_val%1000); +} + +static ssize_t read_psu_vol_out(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + int data = 0, ret_val = 0; + int exponent, mantissa; + int multiplier = 1000; + u16 vout_mode; + + vout_mode = pega_fn8656_bnf_psu_read(client->addr, PSU_VOUT_MODE_REG); + data = pega_fn8656_bnf_psu_read_word(client->addr, psu_pmbus_reg_map[attr->index]); + + exponent = two_complement_to_int(vout_mode, 5, 0x1f); + mantissa = data; + + pega_print(DEBUG, "addr:0x%x, reg:0x%x, read_value:0x%x,exponent:%d,mantissa:%d\n", client->addr, psu_pmbus_reg_map[attr->index], data, exponent, mantissa); + if (exponent >= 0) + ret_val = (mantissa << exponent) * multiplier; + else + ret_val = (mantissa * multiplier) / (1 << -exponent); + + /*the vol_out_max can have a 3% tolenrence.*/ + if(attr->index == PSU_VOUT_MAX) + ret_val = ret_val * 103 / 100; + else if(attr->index == PSU_VOUT_MIN) + ret_val = ret_val * 97 / 100; + + return sprintf(buf, "%d.%d\n", ret_val / 1000, ret_val % 1000); +} + +static ssize_t pega_fn8656_bnf_psu_read_data_direct(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 read_value = 0; + int ret_val; + /* X = 1/m * (Y * 10^-R - b) */ + int m = 1, b = 0, r = -3; + + pega_print(DEBUG, "m:%d,b:%d,r:%d\n", m, b, r); + read_value = pega_fn8656_bnf_psu_read_word(client->addr, psu_pmbus_reg_map[attr->index]); + ret_val = 1 / m * (read_value * (10 << (-r)) - b); + + return sprintf(buf, "%d.%d\n", ret_val / 1000, ret_val % 1000); +} + +static ssize_t show_manufacture_info(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u8 data[PM_BUS_BLOCK_MAX_LEN] = {0}, read_count; + + read_count = pega_fn8656_bnf_psu_read_block(client->addr, psu_pmbus_reg_map[attr->index], data); + data[read_count] = '\0'; + return sprintf(buf, "%s\n", data); +} + +static ssize_t get_label(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + ssize_t size = 0; + + switch (attr->index) { + case 0: + size = sprintf(buf, "PSU Ambient\n"); + break; + case 1: + size = sprintf(buf, "PSU SR Hotspot\n"); + break; + case 2: + size = sprintf(buf, "PSU PFC Hotspot\n"); + break; + default: + pega_print(WARNING, "only 3 PSU temp sensors\n"); + break; + } + return size; +} +static ssize_t get_psu_sensor_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "N/A\n"); +} + +static ssize_t get_psu_sensor_temp_min(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", drv_data->temp_min[attr->index]); +} + +static ssize_t get_psu_sensor_temp_max(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + + return sprintf(buf, "%d\n", drv_data->temp_max[attr->index]); +} + +static ssize_t set_psu_sensor_temp_max(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + long val = 0; + + if (kstrtol(buf, 10, &val)) { + return -EINVAL; + } + + drv_data->temp_max[attr->index] = val; + return count; +} + +static ssize_t get_psu_sensor_temperature(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 read_value = 0; + int exponent, mantissa; + int multiplier = 1000; + int ret_val; + u8 reg = attr->index + PSU_TEMP1_REG; + + if (attr->index >= MAX_PSU_TEMP_SENSORS) { + pega_print(WARNING, "only 3 PSU temp sensors\n"); + return -ENXIO; + } + read_value = pega_fn8656_bnf_psu_read_word(client->addr, reg); + exponent = two_complement_to_int(read_value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(read_value & 0x7ff, 11, 0x7ff); + + pega_print(DEBUG, "addr:0x%x, reg:0x%x, read_value:0x%x,exponent:%d,mantissa:%d\n", client->addr, reg, read_value, exponent, mantissa); + if (exponent >= 0) + ret_val = (mantissa << exponent) * multiplier; + else + ret_val = (mantissa * multiplier) / (1 << -exponent); + + return sprintf(buf, "%d\n", ret_val); +} + +static ssize_t get_psu_sensor_temp_crit(struct device *dev, + struct device_attribute *da, char *buf) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + struct i2c_client *client = drv_data->client; + u16 read_value = 0; + int exponent, mantissa; + int multiplier = 1000; + int ret_val; + u8 reg = attr->index + PSU_MFR_TEMP1_MAX_REG; + int temp_sensor = attr->index; + + if (attr->index >= MAX_PSU_TEMP_SENSORS) { + pega_print(WARNING, "only 3 PSU temp sensors\n"); + return -ENXIO; + } + read_value = pega_fn8656_bnf_psu_read_word(client->addr, reg); + exponent = two_complement_to_int(read_value >> 11, 5, 0x1f); + mantissa = two_complement_to_int(read_value & 0x7ff, 11, 0x7ff); + + pega_print(DEBUG, "addr:0x%x, reg:0x%x, read_value:0x%x,exponent:%d,mantissa:%d\n", client->addr, reg, read_value, exponent, mantissa); + if (exponent >= 0) + ret_val = (mantissa << exponent) * multiplier; + else + ret_val = (mantissa * multiplier) / (1 << -exponent); + + /* PSU vendor didnot set the max temperature*/ + if(ret_val == 0) + { + ret_val = drv_data->temp_crit[temp_sensor]; + } + + return sprintf(buf, "%d\n", ret_val); +} + +static ssize_t set_psu_sensor_temp_crit(struct device *dev, struct device_attribute *da, + const char *buf, size_t count) +{ + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + long val = 0; + // int temp_sensor = attr->index - PSU_MFR_TEMP1_MAX_REG; + int temp_sensor = attr->index; + + if (kstrtol(buf, 10, &val)) { + return -EINVAL; + } + + drv_data->temp_crit[temp_sensor] = val; + return count; +} + +static ssize_t get_total_psu_num(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + if (!drv_data) { + pega_print(ERR, "fn8656_bnf_psu_data is NULL!\n"); + return -ENOENT; + } + return sprintf(buf, "%d\n", drv_data->total_psu_num); +} +static ssize_t get_temp_sensor_num(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + if (!drv_data) { + pega_print(ERR, "fn8656_bnf_psu_data is NULL!\n"); + return -ENOENT; + } + return sprintf(buf, "%d\n", drv_data->temp_sensor_num); +} +static ssize_t get_psu_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct fn8656_bnf_psu_data *drv_data = dev_get_drvdata(dev); + if (!drv_data) { + pega_print(ERR, "fn8656_bnf_psu_data is NULL!\n"); + return -ENOENT; + } + return sprintf(buf, "%d\n", drv_data->type); +} + +static SENSOR_DEVICE_ATTR(psu_led_status, S_IRUGO, get_psu_led_status, NULL, 0); +static SENSOR_DEVICE_ATTR(psu_alarm, S_IRUGO, read_psu_alarm, NULL, 0); +static SENSOR_DEVICE_ATTR(vout_over_voltage, S_IRUGO, read_psu_vout_over_voltage, NULL, 0); +static SENSOR_DEVICE_ATTR(iout_over_current_fault, S_IRUGO, read_psu_iout_over_current_fault, NULL, 0); +static SENSOR_DEVICE_ATTR(iout_over_current_warning, S_IRUGO, read_psu_iout_over_current_warning, NULL, 0); +static SENSOR_DEVICE_ATTR(iput_over_current_warning, S_IRUGO, read_psu_iput_over_current_warning, NULL, 0); +static SENSOR_DEVICE_ATTR(iput_insufficient, S_IRUGO, read_psu_iput_insufficient, NULL, 0); +static SENSOR_DEVICE_ATTR(temp_over_temp_fault, S_IRUGO, read_psu_temp_over_temp_fault, NULL, 0); +static SENSOR_DEVICE_ATTR(temp_over_temp_warning, S_IRUGO, read_psu_temp_over_temp_warning, NULL, 0); +static SENSOR_DEVICE_ATTR(vol_out, S_IRUGO, read_psu_vol_out, NULL, PSU_V_OUT); +static SENSOR_DEVICE_ATTR(vol_in, S_IRUGO, show_linear, NULL, PSU_V_IN); +static SENSOR_DEVICE_ATTR(curr_out, S_IRUGO, show_linear, NULL, PSU_I_OUT); +static SENSOR_DEVICE_ATTR(curr_in, S_IRUGO, show_linear, NULL, PSU_I_IN); +static SENSOR_DEVICE_ATTR(power_out, S_IRUGO, show_linear, NULL, PSU_P_OUT); +static SENSOR_DEVICE_ATTR(power_in, S_IRUGO, show_linear, NULL, PSU_P_IN); +static SENSOR_DEVICE_ATTR(fan1_speed, S_IRUGO, show_linear, NULL, PSU_FAN1_SPEED); + +static SENSOR_DEVICE_ATTR(manuafacture_id,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_ID); +static SENSOR_DEVICE_ATTR(manuafacture_model,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_MODEL); +static SENSOR_DEVICE_ATTR(manuafacture_revision,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_REVISION); +static SENSOR_DEVICE_ATTR(manuafacture_serial,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_SERIAL); +static SENSOR_DEVICE_ATTR(manuafacture_date,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_DATE); +static SENSOR_DEVICE_ATTR(manuafacture_location,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_LOCATION); +static SENSOR_DEVICE_ATTR(manuafacture_part_num,S_IRUGO, show_manufacture_info, NULL, PSU_MFR_MODEL); + +static SENSOR_DEVICE_ATTR(vol_in_min,S_IRUGO, show_linear, NULL, PSU_VIN_MIN); +static SENSOR_DEVICE_ATTR(vol_in_max,S_IRUGO, show_linear, NULL, PSU_VIN_MAX); +static SENSOR_DEVICE_ATTR(curr_in_max,S_IRUGO, show_linear, NULL, PSU_IIN_MAX); +static SENSOR_DEVICE_ATTR(power_in_max,S_IRUGO, pega_fn8656_bnf_psu_read_data_direct, NULL, PSU_PIN_MAX); +static SENSOR_DEVICE_ATTR(vol_out_min,S_IRUGO, read_psu_vol_out, NULL, PSU_VOUT_MIN); +static SENSOR_DEVICE_ATTR(vol_out_max,S_IRUGO, read_psu_vol_out, NULL, PSU_VOUT_MAX); +static SENSOR_DEVICE_ATTR(curr_out_max,S_IRUGO, show_linear, NULL, PSU_IOUT_MAX); +static SENSOR_DEVICE_ATTR(power_out_max,S_IRUGO, pega_fn8656_bnf_psu_read_data_direct, NULL, PSU_POUT_MAX); + +static SENSOR_DEVICE_ATTR(psu_num, S_IRUGO, get_total_psu_num, NULL, 0); +static SENSOR_DEVICE_ATTR(sensor_num, S_IRUGO, get_temp_sensor_num, NULL, 0); +static SENSOR_DEVICE_ATTR(psu_type, S_IRUGO, get_psu_type, NULL, 0); +static SENSOR_DEVICE_ATTR(psu_sensor_type, S_IRUGO, get_psu_sensor_type, NULL, 0); + +#define SET_TEMP_ATTR(_num) \ + static SENSOR_DEVICE_ATTR(temp##_num##_input, S_IRUGO, get_psu_sensor_temperature, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_label, S_IRUGO, get_label, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_max, S_IRUGO, get_psu_sensor_temp_max, set_psu_sensor_temp_max, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_min, S_IRUGO, get_psu_sensor_temp_min, NULL, _num-1); \ + static SENSOR_DEVICE_ATTR(temp##_num##_crit, S_IRUGO, get_psu_sensor_temp_crit, set_psu_sensor_temp_crit, _num-1); + +SET_TEMP_ATTR(1);SET_TEMP_ATTR(2);SET_TEMP_ATTR(3); + +static struct attribute *pega_fn8656_bnf_psu_attrs[] = { + &sensor_dev_attr_psu_led_status.dev_attr.attr, + &sensor_dev_attr_psu_alarm.dev_attr.attr, + &sensor_dev_attr_vout_over_voltage.dev_attr.attr, + &sensor_dev_attr_iout_over_current_fault.dev_attr.attr, + &sensor_dev_attr_iout_over_current_warning.dev_attr.attr, + &sensor_dev_attr_iput_over_current_warning.dev_attr.attr, + &sensor_dev_attr_iput_insufficient.dev_attr.attr, + &sensor_dev_attr_temp_over_temp_fault.dev_attr.attr, + &sensor_dev_attr_temp_over_temp_warning.dev_attr.attr, + + &sensor_dev_attr_vol_out.dev_attr.attr, + &sensor_dev_attr_vol_in.dev_attr.attr, + &sensor_dev_attr_curr_out.dev_attr.attr, + &sensor_dev_attr_curr_in.dev_attr.attr, + &sensor_dev_attr_power_out.dev_attr.attr, + &sensor_dev_attr_power_in.dev_attr.attr, + &sensor_dev_attr_fan1_speed.dev_attr.attr, + + &sensor_dev_attr_temp1_input.dev_attr.attr, + &sensor_dev_attr_temp2_input.dev_attr.attr, + &sensor_dev_attr_temp3_input.dev_attr.attr, + &sensor_dev_attr_temp1_label.dev_attr.attr, + &sensor_dev_attr_temp2_label.dev_attr.attr, + &sensor_dev_attr_temp3_label.dev_attr.attr, + &sensor_dev_attr_temp1_max.dev_attr.attr, + &sensor_dev_attr_temp2_max.dev_attr.attr, + &sensor_dev_attr_temp3_max.dev_attr.attr, + &sensor_dev_attr_temp1_crit.dev_attr.attr, + &sensor_dev_attr_temp2_crit.dev_attr.attr, + &sensor_dev_attr_temp3_crit.dev_attr.attr, + + &sensor_dev_attr_manuafacture_id.dev_attr.attr, + &sensor_dev_attr_manuafacture_model.dev_attr.attr, + &sensor_dev_attr_manuafacture_revision.dev_attr.attr, + &sensor_dev_attr_manuafacture_serial.dev_attr.attr, + &sensor_dev_attr_manuafacture_date.dev_attr.attr, + &sensor_dev_attr_manuafacture_location.dev_attr.attr, + &sensor_dev_attr_manuafacture_part_num.dev_attr.attr, + &sensor_dev_attr_vol_in_min.dev_attr.attr, + &sensor_dev_attr_vol_in_max.dev_attr.attr, + &sensor_dev_attr_curr_in_max.dev_attr.attr, + &sensor_dev_attr_power_in_max.dev_attr.attr, + &sensor_dev_attr_vol_out_min.dev_attr.attr, + &sensor_dev_attr_vol_out_max.dev_attr.attr, + &sensor_dev_attr_curr_out_max.dev_attr.attr, + &sensor_dev_attr_power_out_max.dev_attr.attr, + + &sensor_dev_attr_psu_num.dev_attr.attr, + &sensor_dev_attr_sensor_num.dev_attr.attr, + &sensor_dev_attr_psu_type.dev_attr.attr, + &sensor_dev_attr_psu_sensor_type.dev_attr.attr, + NULL +}; + +//static const struct attribute_group pega_fn8656_bnf_psu_group = { .attrs = pega_fn8656_bnf_psu_attributes}; +ATTRIBUTE_GROUPS(pega_fn8656_bnf_psu); +static void pega_fn8656_bnf_psu_add_client(struct i2c_client *client) +{ + struct psu_client_node *node = kzalloc(sizeof(struct psu_client_node), GFP_KERNEL); + + if (!node) { + pega_print(ERR, "Can't allocate psu_client_node (0x%x)\n", client->addr); + return; + } + + node->client = client; + + mutex_lock(&list_lock); + list_add(&node->list, &psu_client_list); + mutex_unlock(&list_lock); +} + +static void pega_fn8656_bnf_psu_remove_client(struct i2c_client *client) +{ + struct list_head *list_node = NULL; + struct psu_client_node *psu_node = NULL; + int found = 0; + + mutex_lock(&list_lock); + + list_for_each(list_node, &psu_client_list) + { + psu_node = list_entry(list_node, struct psu_client_node, list); + + if (psu_node->client == client) { + found = 1; + break; + } + } + + if (found) { + list_del(list_node); + kfree(psu_node); + } + + mutex_unlock(&list_lock); +} + +static int pega_fn8656_bnf_psu_probe(struct i2c_client *client, + const struct i2c_device_id *dev_id) +{ + int status = 0 , i = 0; + struct device *dev = &client->dev; + struct fn8656_bnf_psu_data *data; + struct device *hwmon_dev; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + pega_print(ERR, "i2c_check_functionality failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + } + + data = devm_kzalloc(dev, sizeof(struct fn8656_bnf_psu_data), GFP_KERNEL); + if (data == NULL) + return -ENOMEM; + data->client = client; + data->total_psu_num = MAX_PSU_NUMS; + data->temp_sensor_num = MAX_PSU_TEMP_SENSORS; + data->type = POWER_AC; + for (i = 0; i < MAX_PSU_TEMP_SENSORS; i++) { + data->temp_max[i] = psu_temp_max[i] * 1000; + data->temp_min[i] = psu_temp_min[i] * 1000; + data->temp_crit[i] = psu_temp_crit[i] *1000; + } + + /* Register sysfs hooks */ + switch (client->addr) { + case PSU_58_ADDRESS: + case PSU_59_ADDRESS: + pega_print(ERR,"hwmon_dev register\n"); + hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name, + data, pega_fn8656_bnf_psu_groups); + if (IS_ERR(hwmon_dev)) + return PTR_ERR(hwmon_dev); + + break; + default: + pega_print(WARNING, "i2c_check_psu failed (0x%x)\n", client->addr); + status = -EIO; + goto exit; + break; + } + + if (status) { + goto exit; + } + + pega_print(INFO, "chip found\n"); + pega_fn8656_bnf_psu_add_client(client); + + return 0; + +exit: + return status; +} + +static int pega_fn8656_bnf_psu_remove(struct i2c_client *client) +{ + pega_fn8656_bnf_psu_remove_client(client); + return 0; +} + +static const struct i2c_device_id pega_fn8656_bnf_psu_id[] = { + { "fn8656_bnf_psu", 0 }, + {} +}; +MODULE_DEVICE_TABLE(i2c, pega_fn8656_bnf_psu_id); + +static struct i2c_driver pega_fn8656_bnf_psu_driver = { + .class = I2C_CLASS_HWMON, + .driver = { + .name = "pegatron_fn8656_bnf_psu", + }, + .probe = pega_fn8656_bnf_psu_probe, + .remove = pega_fn8656_bnf_psu_remove, + .id_table = pega_fn8656_bnf_psu_id, + .address_list = normal_i2c, +}; + +static int __init pega_fn8656_bnf_psu_init(void) +{ + mutex_init(&list_lock); + + return i2c_add_driver(&pega_fn8656_bnf_psu_driver); +} + +static void __exit pega_fn8656_bnf_psu_exit(void) +{ + i2c_del_driver(&pega_fn8656_bnf_psu_driver); +} + +module_param(loglevel, uint, 0644); +module_param_string(debug, debug, MAX_DEBUG_INFO_LEN, 0644); +MODULE_PARM_DESC(loglevel, "0x01-LOG_ERR,0x02-LOG_WARNING,0x04-LOG_INFO,0x08-LOG_DEBUG"); +MODULE_PARM_DESC(debug, "help info"); + +MODULE_AUTHOR("Peter5 Lin "); +MODULE_DESCRIPTION("pega_fn8656_bnf_psu driver"); +MODULE_LICENSE("GPL"); + +module_init(pega_fn8656_bnf_psu_init); +module_exit(pega_fn8656_bnf_psu_exit); diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_sfp.c b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_sfp.c new file mode 100644 index 000000000000..51dc830bdad9 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_sfp.c @@ -0,0 +1,1323 @@ +/* + * pegatron_fn8656_bnf_sfp.c - A driver to read and write the EEPROM on optical transceivers + * (SFP and QSFP) + * + * Copyright (C) 2014 Cumulus networks Inc. + * Copyright (C) 2017 Finisar Corp. + * Copyright (C) 2019 Pegatron Corp. + * + * 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 Freeoftware Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +/* + * Description: + * a) Optical transceiver EEPROM read/write transactions are just like + * the at24 eeproms managed by the at24.c i2c driver + * b) The register/memory layout is up to 256 128 byte pages defined by + * a "pages valid" register and switched via a "page select" + * register as explained in below diagram. + * c) 256 bytes are mapped at a time. 'Lower page 00h' is the first 128 + * bytes of address space, and always references the same + * location, independent of the page select register. + * All mapped pages are mapped into the upper 128 bytes + * (offset 128-255) of the i2c address. + * d) Devices with one I2C address (eg QSFP) use I2C address 0x50 + * (A0h in the spec), and map all pages in the upper 128 bytes + * of that address. + * e) Devices with two I2C addresses (eg SFP) have 256 bytes of data + * at I2C address 0x50, and 256 bytes of data at I2C address + * 0x51 (A2h in the spec). Page selection and paged access + * only apply to this second I2C address (0x51). + * e) The address space is presented, by the driver, as a linear + * address space. For devices with one I2C client at address + * 0x50 (eg QSFP), offset 0-127 are in the lower + * half of address 50/A0h/client[0]. Offset 128-255 are in + * page 0, 256-383 are page 1, etc. More generally, offset + * 'n' resides in page (n/128)-1. ('page -1' is the lower + * half, offset 0-127). + * f) For devices with two I2C clients at address 0x50 and 0x51 (eg SFP), + * the address space places offset 0-127 in the lower + * half of 50/A0/client[0], offset 128-255 in the upper + * half. Offset 256-383 is in the lower half of 51/A2/client[1]. + * Offset 384-511 is in page 0, in the upper half of 51/A2/... + * Offset 512-639 is in page 1, in the upper half of 51/A2/... + * Offset 'n' is in page (n/128)-3 (for n > 383) + * + * One I2c addressed (eg QSFP) Memory Map + * + * 2-Wire Serial Address: 1010000x + * + * Lower Page 00h (128 bytes) + * ===================== + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * | | + * |Page Select Byte(127)| + * ===================== + * | + * | + * | + * | + * V + * ------------------------------------------------------------ + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * | | | | + * V V V V + * ------------ -------------- --------------- -------------- + * | | | | | | | | + * | Upper | | Upper | | Upper | | Upper | + * | Page 00h | | Page 01h | | Page 02h | | Page 03h | + * | | | (Optional) | | (Optional) | | (Optional | + * | | | | | | | for Cable | + * | | | | | | | Assemblies) | + * | ID | | AST | | User | | | + * | Fields | | Table | | EEPROM Data | | | + * | | | | | | | | + * | | | | | | | | + * | | | | | | | | + * ------------ -------------- --------------- -------------- + * + * The SFF 8436 (QSFP) spec only defines the 4 pages described above. + * In anticipation of future applications and devices, this driver + * supports access to the full architected range, 256 pages. + * + * The CMIS (Common Management Interface Specification) defines use of + * considerably more pages (at least to page 0xAF), which this driver + * supports. + * + * NOTE: This version of the driver ONLY SUPPORTS BANK 0 PAGES on CMIS + * devices. + * + **/ + +#define PEGA_DEBUG 1 +/*#define pega_DEBUG*/ +#ifdef PEGA_DEBUG +#define DBG(x) x +#else +#define DBG(x) +#endif /* DEBUG */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pegatron_pub.h" +#include +#include +#include +#include +#include +#include + +#define NUM_ADDRESS 2 + +/* The maximum length of a port name */ +#define MAX_PORT_NAME_LEN 20 + +/* fundamental unit of addressing for EEPROM */ +#define SFP_PAGE_SIZE 128 + +/* + * Single address devices (eg QSFP) have 256 pages, plus the unpaged + * low 128 bytes. If the device does not support paging, it is + * only 2 'pages' long. + */ +#define SFP_ARCH_PAGES 256 +#define ONE_ADDR_EEPROM_SIZE ((1 + SFP_ARCH_PAGES) * SFP_PAGE_SIZE) +#define ONE_ADDR_EEPROM_UNPAGED_SIZE (2 * SFP_PAGE_SIZE) + +/* + * Dual address devices (eg SFP) have 256 pages, plus the unpaged + * low 128 bytes, plus 256 bytes at 0x50. If the device does not + * support paging, it is 4 'pages' long. + */ +#define TWO_ADDR_EEPROM_SIZE ((3 + SFP_ARCH_PAGES) * SFP_PAGE_SIZE) +#define TWO_ADDR_EEPROM_UNPAGED_SIZE (4 * SFP_PAGE_SIZE) +#define TWO_ADDR_NO_0X51_SIZE (2 * SFP_PAGE_SIZE) + +/* + * flags to distinguish one-address (QSFP family) from two-address (SFP family) + * If the family is not known, figure it out when the device is accessed + */ +#define ONE_ADDR 1 +#define TWO_ADDR 2 +#define CMIS_ADDR 3 + +/* a few constants to find our way around the EEPROM */\ +#define SFP_EEPROM_A0_ADDR 0xA0 +#define SFP_EEPROM_A2_ADDR 0xA2 +#define SFP_PAGE_SELECT_REG 0x7F +#define ONE_ADDR_PAGEABLE_REG 0x02 +#define QSFP_NOT_PAGEABLE (1<<2) +#define CMIS_NOT_PAGEABLE (1<<7) +#define TWO_ADDR_PAGEABLE_REG 0x40 +#define TWO_ADDR_PAGEABLE (1<<4) +#define TWO_ADDR_0X51_REG 92 +#define TWO_ADDR_0X51_SUPP (1<<6) +#define SFP_ID_REG 0 +#define SFP_READ_OP 0 +#define SFP_WRITE_OP 1 +#define SFP_EOF 0 /* used for access beyond end of device */ +#define MAX_PORT_NUM (56) +#define GET_BIT(data, bit, value) value = (data >> bit) & 0x1 +#define SET_BIT(data, bit) data |= (1 << bit) +#define CLEAR_BIT(data, bit) data &= ~(1 << bit) + +#define SFP_FAST_BYTE_LENGTH 4 + +#define SFP_LOWER_PAGE (0x0) +#define SFP_CACHE_PAGE_NUM (0x11) +#define MAX_CACHE_LEN (SFP_PAGE_SIZE*(SFP_CACHE_PAGE_NUM + 1)) //SFP_CACHE_PAGE_NUM upper pages and 1 lower page + +#define FPGA_I2C_RD_MODE_BLOCK 1 +#define FPGA_I2C_RD_MODE_BYTE 0 + +static struct task_struct *sfp_task; +static char sfp_eeprom_cache[MAX_PORT_NUM][MAX_CACHE_LEN]; +static int enable_sfp_eeprom_cache = FALSE; +static int enable_sfp_three_batch =TRUE; + +struct fn8656_bnf_sfp_platform_data { + u32 byte_len; /* size (sum of all addr) */ + u16 page_size; /* for writes */ + u8 flags; + void *dummy1; /* backward compatibility */ + void *dummy2; /* backward compatibility */ + + /* dev_class: ONE_ADDR (QSFP) or TWO_ADDR (SFP) */ + int dev_class; + int slave_addr; + unsigned int write_max; +}; + +struct kwai_fpga{ + struct pci_dev *pdev; + struct mutex lock; + void __iomem *mmio; + unsigned int i2c_mode; + struct fn8656_bnf_sfp_platform_data chip[MAX_PORT_NUM+1]; +}; + +/* + * This parameter is to help this driver avoid blocking other drivers out + * of I2C for potentially troublesome amounts of time. With a 100 kHz I2C + * clock, one 256 byte read takes about 1/43 second which is excessive; + * but the 1/170 second it takes at 400 kHz may be quite reasonable; and + * at 1 MHz (Fm+) a 1/430 second delay could easily be invisible. + * + * This value is forced to be a power of two so that writes align on pages. + */ +//static unsigned int io_limit = SFP_PAGE_SIZE; + +/* + * specs often allow 5 msec for a page write, sometimes 20 msec; + * it's important to recover from write timeouts. + */ +static unsigned int write_timeout = 250; + +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; +static char fpga_debug[MAX_DEBUG_INFO_LEN] = "fpga debug info: \n"; +/*-------------------------------------------------------------------------*/ +/* + * This routine computes the addressing information to be used for + * a given r/w request. + * + * Task is to calculate the client (0 = i2c addr 50, 1 = i2c addr 51), + * the page, and the offset. + * + * Handles both single address (eg QSFP) and two address (eg SFP). + * For SFP, offset 0-255 are on client[0], >255 is on client[1] + * Offset 256-383 are on the lower half of client[1] + * Pages are accessible on the upper half of client[1]. + * Offset >383 are in 128 byte pages mapped into the upper half + * + * For QSFP, all offsets are on client[0] + * offset 0-127 are on the lower half of client[0] (no paging) + * Pages are accessible on the upper half of client[1]. + * Offset >127 are in 128 byte pages mapped into the upper half + * + * Callers must not read/write beyond the end of a client or a page + * without recomputing the client/page. Hence offset (within page) + * plus length must be less than or equal to 128. (Note that this + * routine does not have access to the length of the call, hence + * cannot do the validity check.) + * + * Offset within Lower Page 00h and Upper Page 00h are not recomputed + */ + +#define FPGA_HW_VERSION (0) +#define FPGA_SW_VERSION (4) + +#define FPGA_NUM 1 + +static ssize_t get_fpga_chip_num(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "%d\n", FPGA_NUM); +} +static ssize_t get_fpga_type(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "xilinx artix-7:xc7a75tfgg484-2\n"); +} +static ssize_t get_fpga_alias(struct device *dev, struct device_attribute *da, + char *buf) +{ + return sprintf(buf, "fpga\n"); +} + +static ssize_t read_fpga_HWversion(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct kwai_fpga *fpga = pdev->sysdata; + + uint8_t data = readl(fpga->mmio + FPGA_HW_VERSION); + pega_print(DEBUG,"read fpga addr:0x%x,data:0x%x\n",fpga->mmio + FPGA_HW_VERSION,data); + + return sprintf(buf, "%02d\n", data); +} + +static ssize_t read_fpga_SWversion(struct device *dev, struct device_attribute *da, + char *buf) +{ + struct pci_dev *pci_dev = to_pci_dev(dev); + struct kwai_fpga *fpga = pci_dev->sysdata; + + uint8_t data = readl(fpga->mmio + FPGA_SW_VERSION); + pega_print(DEBUG,"read fpga addr:0x%x,data:0x%x\n",fpga->mmio + FPGA_SW_VERSION,data); + + return sprintf(buf, "%02d\n", data); +} + +struct fpga_device_attribute{ + struct device_attribute dev_attr; + int index; +}; +#define to_fpga_dev_attr(_dev_attr) \ + container_of(_dev_attr, struct fpga_device_attribute, dev_attr) + +#define FPGA_ATTR(_name, _mode, _show, _store, _index) \ + { .dev_attr = __ATTR(_name, _mode, _show, _store), \ + .index = _index } + +#define FPGA_DEVICE_ATTR(_name, _mode, _show, _store, _index) \ +struct fpga_device_attribute fpga_dev_attr_##_name \ + = FPGA_ATTR(_name, _mode, _show, _store, _index) + +static FPGA_DEVICE_ATTR(fpga_chip_num, S_IRUGO, get_fpga_chip_num, NULL, 0); +static FPGA_DEVICE_ATTR(fpga_alias, S_IRUGO, get_fpga_alias, NULL, 0); +static FPGA_DEVICE_ATTR(fpga_type, S_IRUGO, get_fpga_type, NULL, 0); +static FPGA_DEVICE_ATTR(fpga_hw_version, S_IRUGO, read_fpga_HWversion, NULL, 0); +static FPGA_DEVICE_ATTR(fpga_sw_version, S_IRUGO, read_fpga_SWversion, NULL, 0); + +static struct attribute *fn8656_bnf_fpga_attributes[] = { + &fpga_dev_attr_fpga_type.dev_attr.attr, + &fpga_dev_attr_fpga_alias.dev_attr.attr, + &fpga_dev_attr_fpga_chip_num.dev_attr.attr, + &fpga_dev_attr_fpga_hw_version.dev_attr.attr, + &fpga_dev_attr_fpga_sw_version.dev_attr.attr, + NULL +}; +static const struct attribute_group fn8656_bnf_fpga_group = { .attrs = fn8656_bnf_fpga_attributes}; + +static uint8_t fn8656_bnf_sfp_translate_offset(struct kwai_fpga *sfp, + loff_t *offset, int num) +{ + unsigned int page = 0; + + /* if SFP style, offset > 255, shift to i2c addr 0x51 */ + if (sfp->chip[num].dev_class == TWO_ADDR) { + if (*offset > 255) { + sfp->chip[num].slave_addr = SFP_EEPROM_A2_ADDR; + *offset -= 256; + } else { + sfp->chip[num].slave_addr = SFP_EEPROM_A0_ADDR; + } + } + + /* + * if offset is in the range 0-128... + * page doesn't matter (using lower half), return 0. + * offset is already correct (don't add 128 to get to paged area) + */ + if (*offset < SFP_PAGE_SIZE) + return page; + + /* note, page will always be positive since *offset >= 128 */ + page = (*offset >> 7)-1; + /* 0x80 places the offset in the top half, offset is last 7 bits */ + *offset = SFP_PAGE_SIZE + (*offset & 0x7f); + + return page; /* note also returning clifn8656_bnf_sfp_translate_offsetent and offset */ +} + +#define FPGA_PORT_MGR_CFG (0x1000) +#define FPGA_PORT_MGR_CTRL (0x1004) +#define FPGA_PORT_MGR_STAT (0x1008) +#define FPGA_PORT_MGR_MUX (0x1010) +#define FPGA_PORT_BATCH_DATA (0x100000) +/* + *i2c controller 0 is used for port 0~24 + *i2c controller 1 is used for port 24~48 + *i2c controller 2 is used for port 48~56 +*/ +#define i2c_dev(mode, port, idx) \ +do { \ + if (((port) < 24 ) || (!mode)) \ + idx = 0; \ + else if ((port) < 48) \ + idx = 1; \ + else \ + idx = 2; \ +}while(0) + +#define port_mgr_cfg_reg(base_addr, idx) \ +(base_addr + FPGA_PORT_MGR_CFG + 0x20 * (idx)) + +#define port_mgr_ctrl_reg(base_addr, idx) \ +(base_addr + FPGA_PORT_MGR_CTRL + 0x20 * (idx)) + +#define port_mgr_stat_reg(base_addr, idx) \ +(base_addr + FPGA_PORT_MGR_STAT + 0x20 * (idx)) + +#define port_mgr_mux_reg(base_addr, idx) \ +(base_addr + FPGA_PORT_MGR_MUX + 0x20 * (idx)) + +#define port_mgr_batch_reg(base_addr, idx, offset) \ +(base_addr + FPGA_PORT_BATCH_DATA + 0x10000 * (idx) + offset) + +#define port2data(mode, port, data) \ +do { \ + if (((port) < 24) || (!mode)) \ + data = (port); \ + else if ((port) < 48 ) \ + data = (port) % 24; \ + else \ + data = (port) % 48; \ +}while(0) + + +static int fpga_i2c_byte_read(struct kwai_fpga *sfp, + int port, + char *buf, unsigned int offset) +{ + uint32_t data; + uint32_t idx = 0; + int i = 0; + + i2c_dev(sfp->i2c_mode, (port - 1), idx); + data = 0x80000000; + writel(data, port_mgr_cfg_reg(sfp->mmio, idx)); + + data = 0x40fa0100 | ((sfp->chip[port].slave_addr & 0xFF) << 8) | (sfp->chip[port].slave_addr & 0xFF); + writel(data, port_mgr_cfg_reg(sfp->mmio, idx)); + + port2data(sfp->i2c_mode, (port - 1), data); + writel(data, port_mgr_mux_reg(sfp->mmio, idx)); + + data = 0x81000000 | ((offset&0xFF) << 16); + writel(data, port_mgr_ctrl_reg(sfp->mmio, idx)); + pega_print(DEBUG, "fpga_i2c_byte_read port %d, offset:0x%x, idx:%d,cfg:%x@%x mux:%x@%x ctrl:%x@%x stat:%x@%x\n", port, offset, idx, + port_mgr_cfg_reg(sfp->mmio, idx), readl(port_mgr_cfg_reg(sfp->mmio, idx)), + port_mgr_mux_reg(sfp->mmio, idx), readl(port_mgr_mux_reg(sfp->mmio, idx)), + port_mgr_ctrl_reg(sfp->mmio, idx), readl(port_mgr_ctrl_reg(sfp->mmio, idx)), + port_mgr_stat_reg(sfp->mmio, idx), readl(port_mgr_stat_reg(sfp->mmio, idx)) + ); + do { + data = readl(port_mgr_stat_reg(sfp->mmio, idx)); + if ((data & 0xC0000000) == 0x80000000) { + *buf = data & 0xFF; + return 0; + } + usleep_range(100,200); + }while(i++ < 1000); + return -ENXIO; +} +static int fpga_i2c_block_read(struct kwai_fpga *sfp, + int port, + char *buf, unsigned int offset,size_t count) +{ + uint32_t data; + uint32_t idx = 0; + int i = 0; + int buf_offset = 0; + + i2c_dev(sfp->i2c_mode, (port - 1), idx); + data = 0x80000000; + writel(data, port_mgr_cfg_reg(sfp->mmio, idx)); + + data = 0x40fa0100 | ((sfp->chip[port].slave_addr & 0xFF) << 8) | (sfp->chip[port].slave_addr & 0xFF); + writel(data, port_mgr_cfg_reg(sfp->mmio, idx)); + + port2data(sfp->i2c_mode, (port - 1), data); + writel(data, port_mgr_mux_reg(sfp->mmio, idx)); + + data = 0x82000000 | ((offset&0xFF) << 16) | ((count & 0xFF) << 8); + writel(data, port_mgr_ctrl_reg(sfp->mmio, idx)); + pega_print(DEBUG, "fpga_i2c_block_read port %d, offset:0x%x, idx:%d,cfg:%x@%x mux:%x@%x ctrl:%x@%x stat:%x@%x\n", port, offset, idx, + port_mgr_cfg_reg(sfp->mmio, idx), readl(port_mgr_cfg_reg(sfp->mmio, idx)), + port_mgr_mux_reg(sfp->mmio, idx), readl(port_mgr_mux_reg(sfp->mmio, idx)), + port_mgr_ctrl_reg(sfp->mmio, idx), readl(port_mgr_ctrl_reg(sfp->mmio, idx)), + port_mgr_stat_reg(sfp->mmio, idx), readl(port_mgr_stat_reg(sfp->mmio, idx)) + ); + do { + data = readl(port_mgr_stat_reg(sfp->mmio, idx)); + if ((data & 0xC0000000) == 0x80000000) { + for(buf_offset = 0; buf_offset < count;buf_offset++){ + if ((enable_sfp_three_batch == FALSE) && (idx)) + { + pega_print(DEBUG, "fpga_i2c_block_read bach:@%x\n", port_mgr_batch_reg(sfp->mmio, idx, buf_offset)); + } +else + *buf++ = readb(port_mgr_batch_reg(sfp->mmio, idx, buf_offset)); + } + return buf_offset; + } + usleep_range(100,200); + } while(i++ < 1000); + return -ENXIO; +} + +static int fpga_i2c_byte_write(struct kwai_fpga *sfp, + int port, + char *buf, unsigned int offset) +{ + uint32_t data; + uint32_t idx = 0; + int i = 0; + + i2c_dev(sfp->i2c_mode, (port - 1), idx); + data = 0x80000000; + writel(data, port_mgr_cfg_reg(sfp->mmio, idx)); + + data = 0x40fa0100 | ((sfp->chip[port].slave_addr & 0xFF) << 8) | (sfp->chip[port].slave_addr & 0xFF); + writel(data, port_mgr_cfg_reg(sfp->mmio, idx)); + + port2data(sfp->i2c_mode, (port - 1), data); + writel(data, port_mgr_mux_reg(sfp->mmio, idx)); + + data = 0x84000000 | ((offset & 0xFF) << 16) | (*buf & 0xFF); + writel(data, port_mgr_ctrl_reg(sfp->mmio, idx)); + pega_print(DEBUG, "fpga_i2c_byte_write port %d, offset:0x%x, idx:%d,cfg:%x@%x mux:%x@%x ctrl:%x@%x stat:%x@%x\n", port, offset, idx, + port_mgr_cfg_reg(sfp->mmio, idx), readl(port_mgr_cfg_reg(sfp->mmio, idx)), + port_mgr_mux_reg(sfp->mmio, idx), readl(port_mgr_mux_reg(sfp->mmio, idx)), + port_mgr_ctrl_reg(sfp->mmio, idx), readl(port_mgr_ctrl_reg(sfp->mmio, idx)), + port_mgr_stat_reg(sfp->mmio, idx), readl(port_mgr_stat_reg(sfp->mmio, idx)) + ); + do { + data = readl(port_mgr_stat_reg(sfp->mmio, idx)); + if (data & 0x80000000) { + return 0; + } + }while(i++ < 1000); + return -ENXIO; +} + +static ssize_t fn8656_bnf_sfp_eeprom_read_byte_by_byte(struct kwai_fpga *sfp, + int port, + char *buf, unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + int ret; + int i = 0; + + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + write_time = jiffies; + ret = fpga_i2c_byte_read(sfp, port, buf + i, (offset + i)); + pega_print(DEBUG, "read register byte by byte %d, offset:0x%x, data :0x%x ret:%d\n", i, offset + i, *(buf + i), ret); + if (ret == -ENXIO) /* no module present */ + return ret; + i++; + } while (time_before(write_time, timeout) && (i < count)); + + if (i == count) + return count; + + return -ETIMEDOUT; +} + +static int fpga_i2c_read(struct kwai_fpga *sfp, + int port, + char *buf, unsigned int offset,size_t count) +{ + if (sfp->i2c_mode == FPGA_I2C_RD_MODE_BLOCK) + return fpga_i2c_block_read(sfp, port, buf, offset, count); + else + return fn8656_bnf_sfp_eeprom_read_byte_by_byte(sfp, port, buf, offset, count); +} + +static ssize_t fn8656_bnf_sfp_eeprom_read(struct kwai_fpga *sfp, + int port, + char *buf, unsigned int offset, size_t count) +{ + unsigned long timeout, read_time; + int status; + if (count < SFP_FAST_BYTE_LENGTH) + { + return fn8656_bnf_sfp_eeprom_read_byte_by_byte(sfp, port, buf, offset, count); + } + /*smaller eeproms can work given some SMBus extension calls */ + if (count > SFP_PAGE_SIZE) + count = SFP_PAGE_SIZE; + + /* + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + read_time = jiffies; + + status = fpga_i2c_read(sfp, port, buf, offset, count); + + pega_print(DEBUG, "eeprom read %zu@%d --> %d (%ld)\n", + count, offset, status, jiffies); + + if (status == count) /* happy path */ + return count; + + if (status == -ENXIO) /* no module present */ + return status; + + } while (time_before(read_time, timeout)); + + return -ETIMEDOUT; +} + +static ssize_t fn8656_bnf_sfp_eeprom_write_byte_by_byte( + struct kwai_fpga *sfp, + int port, + const char *buf, unsigned int offset, size_t count) +{ + unsigned long timeout, write_time; + int ret; + int i = 0; + + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + write_time = jiffies; + ret = fpga_i2c_byte_write(sfp, port, (char *)buf + i, (offset + i)); + pega_print(DEBUG, "Write register byte by byte %zu, offset:0x%x, data :0x%x ret:%d\n", + count, offset + i, *(buf + i), ret); + if (ret == -ENXIO) + return ret; + i++; + //usleep_range(10000, 15000); + } while (time_before(write_time, timeout) && (i < count)); + + if (i == count) { + return count; + } + + return -ETIMEDOUT; +} + + +static ssize_t fn8656_bnf_sfp_eeprom_write(struct kwai_fpga *sfp, + int port, + const char *buf, + unsigned int offset, size_t count) +{ + ssize_t status; + unsigned long timeout, write_time; + unsigned int next_page_start; + + /* write max is at most a page + * (In this driver, write_max is actually one byte!) + */ + if (count > sfp->chip[port].write_max) + count = sfp->chip[port].write_max; + + /* shorten count if necessary to avoid crossing page boundary */ + next_page_start = roundup(offset + 1, SFP_PAGE_SIZE); + if ((offset + count) > next_page_start) + count = next_page_start - offset; + + if (count > I2C_SMBUS_BLOCK_MAX) + count = I2C_SMBUS_BLOCK_MAX; + + /* + * Reads fail if the previous write didn't complete yet. We may + * loop a few times until this one succeeds, waiting at least + * long enough for one entire page write to work. + */ + timeout = jiffies + msecs_to_jiffies(write_timeout); + do { + write_time = jiffies; + + status = fn8656_bnf_sfp_eeprom_write_byte_by_byte(sfp, port, buf, offset, count); + if (status == count) /* happy path */ + return count; + + if (status == -ENXIO) /* no module present */ + return status; + + } while (time_before(write_time, timeout)); + + return -ETIMEDOUT; +} + +static ssize_t fn8656_bnf_sfp_eeprom_update_client(struct kwai_fpga *sfp, + char *buf, loff_t off, size_t count, int num) +{ + ssize_t retval = 0; + uint8_t page = 0; + uint8_t page_check = 0; + loff_t phy_offset = off; + int ret = 0; + + page = fn8656_bnf_sfp_translate_offset(sfp, &phy_offset, num); + + pega_print(DEBUG,"off %lld page:%d phy_offset:%lld, count:%ld\n", + off, page, phy_offset, (long int) count); + if (page > 0) { + ret = fn8656_bnf_sfp_eeprom_write(sfp, num, &page, + SFP_PAGE_SELECT_REG, 1); + if (ret < 0) { + pega_print(WARNING,"Write page register for page %d failed ret:%d!\n",page, ret); + return ret; + } + } + wmb(); + + ret = fn8656_bnf_sfp_eeprom_read(sfp, num, + &page_check , SFP_PAGE_SELECT_REG, 1); + if (ret < 0) { + pega_print(DEBUG,"Read page register for page %d failed ret:%d!\n",page, ret); + return ret; + } + pega_print(DEBUG,"read page register %d checked %d, ret:%d\n",page, page_check, ret); + + while (count) { + ssize_t status; + + status = fn8656_bnf_sfp_eeprom_read(sfp, num, + buf, phy_offset, count); + + if (status <= 0) { + if (retval == 0) + retval = status; + break; + } + buf += status; + phy_offset += status; + count -= status; + retval += status; + } + + + if (page > 0) { + /* return the page register to page 0 (why?) */ + page = 0; + ret = fn8656_bnf_sfp_eeprom_write(sfp, num, &page, + SFP_PAGE_SELECT_REG, 1); + if (ret < 0) { + pega_print(ERR,"Restore page register to 0 failed:%d!\n", ret); + /* error only if nothing has been transferred */ + if (retval == 0) + retval = ret; + } + } + return retval; +} + +static ssize_t fn8656_bnf_sfp_eeprom_write_client(struct kwai_fpga *sfp, + char *buf, loff_t off, size_t count, int num) +{ + ssize_t retval = 0; + uint8_t page = 0; + uint8_t page_check = 0; + loff_t phy_offset = off; + int ret = 0; + + page = fn8656_bnf_sfp_translate_offset(sfp, &phy_offset, num); + + pega_print(DEBUG,"off %lld page:%d phy_offset:%lld, count:%ld\n", + off, page, phy_offset, (long int) count); + if (page > 0) { + ret = fn8656_bnf_sfp_eeprom_write(sfp, num, &page, + SFP_PAGE_SELECT_REG, 1); + if (ret < 0) { + pega_print(WARNING,"Write page register for page %d failed ret:%d!\n",page, ret); + return ret; + } + } + wmb(); + + ret = fn8656_bnf_sfp_eeprom_read(sfp, num, + &page_check , SFP_PAGE_SELECT_REG, 1); + if (ret < 0) { + pega_print(WARNING,"Read page register for page %d failed ret:%d!\n",page, ret); + return ret; + } + pega_print(DEBUG,"read page register %d checked %d, ret:%d\n",page, page_check, ret); + + ret = fn8656_bnf_sfp_eeprom_write(sfp, num, + buf, phy_offset, count); + + if (ret < 0) { + retval = ret; + pega_print(ERR,"write eeprom failed:offset:0x%x bytes:%d ret:%d!\n", phy_offset, num, ret); + } + /*update sfp eeprom cache buffer after write*/ + if(enable_sfp_eeprom_cache == TRUE) + fn8656_bnf_sfp_eeprom_read(sfp,num, &sfp_eeprom_cache[num-1][page*SFP_PAGE_SIZE+phy_offset], phy_offset, count); + + if (page > 0) { + /* return the page register to page 0 (why?) */ + page = 0; + ret = fn8656_bnf_sfp_eeprom_write(sfp, num, &page, + SFP_PAGE_SELECT_REG, 1); + if (ret < 0) { + pega_print(ERR,"Restore page register to 0 failed:%d!\n", ret); + /* error only if nothing has been transferred */ + if (retval == 0) + retval = ret; + } + } + return retval; +} + +/* + * Figure out if this access is within the range of supported pages. + * Note this is called on every access because we don't know if the + * module has been replaced since the last call. + * If/when modules support more pages, this is the routine to update + * to validate and allow access to additional pages. + * + * Returns updated len for this access: + * - entire access is legal, original len is returned. + * - access begins legal but is too long, len is truncated to fit. + * - initial offset exceeds supported pages, return OPTOE_EOF (zero) + */ +static ssize_t fn8656_bnf_sfp_page_legal(struct kwai_fpga *sfp, + loff_t off, size_t len, int num) +{ + u8 regval; + int not_pageable; + int status; + size_t maxlen; + + if (off < 0) + return -EINVAL; + + if (sfp->chip[num].dev_class == TWO_ADDR) { + /* SFP case */ + /* if only using addr 0x50 (first 256 bytes) we're good */ + if ((off + len) <= TWO_ADDR_NO_0X51_SIZE) + return len; + /* if offset exceeds possible pages, we're not good */ + if (off >= TWO_ADDR_EEPROM_SIZE) + return SFP_EOF; + /* in between, are pages supported? */ + status = fn8656_bnf_sfp_eeprom_read(sfp, num, ®val, + TWO_ADDR_PAGEABLE_REG, 1); + if (status < 0) + return status; /* error out (no module?) */ + if (regval & TWO_ADDR_PAGEABLE) { + /* Pages supported, trim len to the end of pages */ + maxlen = TWO_ADDR_EEPROM_SIZE - off; + } else { + /* pages not supported, trim len to unpaged size */ + if (off >= TWO_ADDR_EEPROM_UNPAGED_SIZE) + return SFP_EOF; + + /* will be accessing addr 0x51, is that supported? */ + /* byte 92, bit 6 implies DDM support, 0x51 support */ + status = fn8656_bnf_sfp_eeprom_read(sfp, num, ®val, + TWO_ADDR_0X51_REG, 1); + if (status < 0) + return status; + if (regval & TWO_ADDR_0X51_SUPP) { + /* addr 0x51 is OK */ + maxlen = TWO_ADDR_EEPROM_UNPAGED_SIZE - off; + } else { + /* addr 0x51 NOT supported, trim to 256 max */ + if (off >= TWO_ADDR_NO_0X51_SIZE) + return SFP_EOF; + maxlen = TWO_ADDR_NO_0X51_SIZE - off; + } + } + len = (len > maxlen) ? maxlen : len; + pega_print(DEBUG,"page_legal, SFP, off %lld len %ld\n", + off, (long int) len); + } else { + /* QSFP case, CMIS case */ + /* if no pages needed, we're good */ + if ((off + len) <= ONE_ADDR_EEPROM_UNPAGED_SIZE) + return len; + /* if offset exceeds possible pages, we're not good */ + if (off >= ONE_ADDR_EEPROM_SIZE) + return SFP_EOF; + /* in between, are pages supported? */ + status = fn8656_bnf_sfp_eeprom_read(sfp, num, ®val, + ONE_ADDR_PAGEABLE_REG, 1); + if (status < 0) + return status; /* error out (no module?) */ + + if (sfp->chip[num].dev_class == ONE_ADDR) { + not_pageable = QSFP_NOT_PAGEABLE; + } else { + not_pageable = CMIS_NOT_PAGEABLE; + } + pega_print(DEBUG,"Paging Register: 0x%x; not_pageable mask: 0x%x\n", + regval, not_pageable); + + if (regval & not_pageable) { + /* pages not supported, trim len to unpaged size */ + if (off >= ONE_ADDR_EEPROM_UNPAGED_SIZE) + return SFP_EOF; + maxlen = ONE_ADDR_EEPROM_UNPAGED_SIZE - off; + } else { + /* Pages supported, trim len to the end of pages */ + maxlen = ONE_ADDR_EEPROM_SIZE - off; + } + len = (len > maxlen) ? maxlen : len; + pega_print(DEBUG,"page_legal, QSFP, off %lld len %ld\n", + off, (long int) len); + } + return len; +} + +static ssize_t fn8656_bnf_sfp_read(struct kwai_fpga *sfp, + char *buf, loff_t off, size_t len, int num) +{ + int chunk; + int status = 0; + ssize_t retval; + size_t pending_len = 0, chunk_len = 0; + loff_t chunk_offset = 0, chunk_start_offset = 0; + loff_t chunk_end_offset = 0; + + if (unlikely(!len)) + return len; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&sfp->lock); + + /* + * Confirm this access fits within the device suppored addr range + */ + status = fn8656_bnf_sfp_page_legal(sfp, off, len, num); + if ((status == SFP_EOF) || (status < 0)) { + mutex_unlock(&sfp->lock); + return status; + } + len = status; + + /* + * For each (128 byte) chunk involved in this request, issue a + * separate call to sff_eeprom_update_client(), to + * ensure that each access recalculates the client/page + * and writes the page register as needed. + * Note that chunk to page mapping is confusing, is different for + * QSFP and SFP, and never needs to be done. Don't try! + */ + pending_len = len; /* amount remaining to transfer */ + retval = 0; /* amount transferred */ + for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { + + /* + * Compute the offset and number of bytes to be read/write + * + * 1. start at an offset not equal to 0 (within the chunk) + * and read/write less than the rest of the chunk + * 2. start at an offset not equal to 0 and read/write the rest + * of the chunk + * 3. start at offset 0 (within the chunk) and read/write less + * than entire chunk + * 4. start at offset 0 (within the chunk), and read/write + * the entire chunk + */ + chunk_start_offset = chunk * SFP_PAGE_SIZE; + chunk_end_offset = chunk_start_offset + SFP_PAGE_SIZE; + + if (chunk_start_offset < off) { + chunk_offset = off; + if ((off + pending_len) < chunk_end_offset) + chunk_len = pending_len; + else + chunk_len = chunk_end_offset - off; + } else { + chunk_offset = chunk_start_offset; + if (pending_len < SFP_PAGE_SIZE) + chunk_len = pending_len; + else + chunk_len = SFP_PAGE_SIZE; + } + + /* + * note: chunk_offset is from the start of the EEPROM, + * not the start of the chunk + */ + status = fn8656_bnf_sfp_eeprom_update_client(sfp, buf, + chunk_offset, chunk_len, num); + if (status != chunk_len) { + /* This is another 'no device present' path */ + if (status > 0) + retval += status; + if (retval == 0) + retval = status; + break; + } + buf += status; + pending_len -= status; + retval += status; + } + mutex_unlock(&sfp->lock); + + return retval; +} + +static ssize_t fn8656_bnf_sfp_write(struct kwai_fpga *sfp, + char *buf, loff_t off, size_t len, int num) +{ + int chunk; + int status = 0; + ssize_t retval; + size_t pending_len = 0, chunk_len = 0; + loff_t chunk_offset = 0, chunk_start_offset = 0; + loff_t chunk_end_offset = 0; + + if (unlikely(!len)) + return len; + + /* + * Read data from chip, protecting against concurrent updates + * from this host, but not from other I2C masters. + */ + mutex_lock(&sfp->lock); + + /* + * Confirm this access fits within the device suppored addr range + */ + status = fn8656_bnf_sfp_page_legal(sfp, off, len, num); + if ((status == SFP_EOF) || (status < 0)) { + mutex_unlock(&sfp->lock); + return status; + } + len = status; + + /* + * For each (128 byte) chunk involved in this request, issue a + * separate call to sff_eeprom_update_client(), to + * ensure that each access recalculates the client/page + * and writes the page register as needed. + * Note that chunk to page mapping is confusing, is different for + * QSFP and SFP, and never needs to be done. Don't try! + */ + pending_len = len; /* amount remaining to transfer */ + retval = 0; /* amount transferred */ + for (chunk = off >> 7; chunk <= (off + len - 1) >> 7; chunk++) { + + /* + * Compute the offset and number of bytes to be read/write + * + * 1. start at an offset not equal to 0 (within the chunk) + * and read/write less than the rest of the chunk + * 2. start at an offset not equal to 0 and read/write the rest + * of the chunk + * 3. start at offset 0 (within the chunk) and read/write less + * than entire chunk + * 4. start at offset 0 (within the chunk), and read/write + * the entire chunk + */ + chunk_start_offset = chunk * SFP_PAGE_SIZE; + chunk_end_offset = chunk_start_offset + SFP_PAGE_SIZE; + + if (chunk_start_offset < off) { + chunk_offset = off; + if ((off + pending_len) < chunk_end_offset) + chunk_len = pending_len; + else + chunk_len = chunk_end_offset - off; + } else { + chunk_offset = chunk_start_offset; + if (pending_len < SFP_PAGE_SIZE) + chunk_len = pending_len; + else + chunk_len = SFP_PAGE_SIZE; + } + + /* + * note: chunk_offset is from the start of the EEPROM, + * not the start of the chunk + */ + status = fn8656_bnf_sfp_eeprom_write_client(sfp, buf, + chunk_offset, chunk_len, num); + if (status != chunk_len) { + /* This is another 'no device present' path */ + if (status > 0) + retval += status; + if (retval == 0) + retval = status; + break; + } + buf += status; + pending_len -= status; + retval += status; + } + mutex_unlock(&sfp->lock); + + return retval; +} + + +int sfp_poll(void *data) +{ + struct kwai_fpga * sfp = (struct kwai_fpga *)data; + int port = 0; + unsigned int offset = 0 ; + int ret = 0; + + while(!kthread_should_stop()) + { + if(enable_sfp_eeprom_cache == FALSE) + { + usleep_range(1000000, 1500000); + continue; + } + + for(port = 0; port < MAX_PORT_NUM; port ++) + { + if(kthread_should_stop()) + return 0; + ret = fn8656_bnf_sfp_read(sfp, sfp_eeprom_cache[port], 0,MAX_CACHE_LEN, port+1); + if(ret != MAX_CACHE_LEN) + { + memset(sfp_eeprom_cache[port],0x0,MAX_CACHE_LEN); + sfp_eeprom_cache[port][0] = ret; + pega_print(DEBUG,"port:%d,ret:%d\n",port+1,sfp_eeprom_cache[port][0]); + } + usleep_range(1000000, 1500000); + } + } + return 0; +} + +static ssize_t +fn8656_bnf_sfp_bin_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, kobj)); + struct kwai_fpga *fpga = dev->sysdata; + int port = (char *)(attr->private) - (char *)NULL; + + if(enable_sfp_eeprom_cache == TRUE) + { + memcpy(buf,&sfp_eeprom_cache[port-1][off],count); + if(sfp_eeprom_cache[port-1][0] < 0) + count = buf[0]; + return count; + } + + return fn8656_bnf_sfp_read(fpga, buf, off, count, port); +} + +static ssize_t +fn8656_bnf_sfp_bin_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct pci_dev *dev = to_pci_dev(container_of(kobj, struct device, kobj)); + struct kwai_fpga *fpga = dev->sysdata; + + return fn8656_bnf_sfp_write(fpga, buf, off, count, (char *)(attr->private) - (char *)NULL); +} + +#define SFP_EEPROM_ATTR(_num) \ + static struct bin_attribute sfp##_num##_eeprom_attr = { \ + .attr = { \ + .name = __stringify(sfp##_num##_eeprom), \ + .mode = S_IRUGO|S_IWUSR \ + }, \ + .private = (void *)_num, \ + .size = TWO_ADDR_EEPROM_SIZE, \ + .read = fn8656_bnf_sfp_bin_read, \ + .write = fn8656_bnf_sfp_bin_write, \ + } + +SFP_EEPROM_ATTR(1);SFP_EEPROM_ATTR(2);SFP_EEPROM_ATTR(3);SFP_EEPROM_ATTR(4);SFP_EEPROM_ATTR(5); +SFP_EEPROM_ATTR(6);SFP_EEPROM_ATTR(7);SFP_EEPROM_ATTR(8);SFP_EEPROM_ATTR(9);SFP_EEPROM_ATTR(10); +SFP_EEPROM_ATTR(11);SFP_EEPROM_ATTR(12);SFP_EEPROM_ATTR(13);SFP_EEPROM_ATTR(14);SFP_EEPROM_ATTR(15); +SFP_EEPROM_ATTR(16);SFP_EEPROM_ATTR(17);SFP_EEPROM_ATTR(18);SFP_EEPROM_ATTR(19);SFP_EEPROM_ATTR(20); +SFP_EEPROM_ATTR(21);SFP_EEPROM_ATTR(22);SFP_EEPROM_ATTR(23);SFP_EEPROM_ATTR(24);SFP_EEPROM_ATTR(25); +SFP_EEPROM_ATTR(26);SFP_EEPROM_ATTR(27);SFP_EEPROM_ATTR(28);SFP_EEPROM_ATTR(29);SFP_EEPROM_ATTR(30); +SFP_EEPROM_ATTR(31);SFP_EEPROM_ATTR(32);SFP_EEPROM_ATTR(33);SFP_EEPROM_ATTR(34);SFP_EEPROM_ATTR(35); +SFP_EEPROM_ATTR(36);SFP_EEPROM_ATTR(37);SFP_EEPROM_ATTR(38);SFP_EEPROM_ATTR(39);SFP_EEPROM_ATTR(40); +SFP_EEPROM_ATTR(41);SFP_EEPROM_ATTR(42);SFP_EEPROM_ATTR(43);SFP_EEPROM_ATTR(44);SFP_EEPROM_ATTR(45); +SFP_EEPROM_ATTR(46);SFP_EEPROM_ATTR(47);SFP_EEPROM_ATTR(48);SFP_EEPROM_ATTR(49);SFP_EEPROM_ATTR(50); +SFP_EEPROM_ATTR(51);SFP_EEPROM_ATTR(52);SFP_EEPROM_ATTR(53);SFP_EEPROM_ATTR(54);SFP_EEPROM_ATTR(55); +SFP_EEPROM_ATTR(56); + +static struct bin_attribute *fn8656_bnf_sfp_epprom_attributes[] = { + &sfp1_eeprom_attr, &sfp2_eeprom_attr, &sfp3_eeprom_attr, &sfp4_eeprom_attr, &sfp5_eeprom_attr, + &sfp6_eeprom_attr, &sfp7_eeprom_attr, &sfp8_eeprom_attr, &sfp9_eeprom_attr, &sfp10_eeprom_attr, + &sfp11_eeprom_attr, &sfp12_eeprom_attr, &sfp13_eeprom_attr, &sfp14_eeprom_attr, &sfp15_eeprom_attr, + &sfp16_eeprom_attr, &sfp17_eeprom_attr, &sfp18_eeprom_attr, &sfp19_eeprom_attr, &sfp20_eeprom_attr, + &sfp21_eeprom_attr, &sfp22_eeprom_attr, &sfp23_eeprom_attr, &sfp24_eeprom_attr, &sfp25_eeprom_attr, + &sfp26_eeprom_attr, &sfp27_eeprom_attr, &sfp28_eeprom_attr, &sfp29_eeprom_attr, &sfp30_eeprom_attr, + &sfp31_eeprom_attr, &sfp32_eeprom_attr, &sfp33_eeprom_attr, &sfp34_eeprom_attr, &sfp35_eeprom_attr, + &sfp36_eeprom_attr, &sfp37_eeprom_attr, &sfp38_eeprom_attr, &sfp39_eeprom_attr, &sfp40_eeprom_attr, + &sfp41_eeprom_attr, &sfp42_eeprom_attr, &sfp43_eeprom_attr, &sfp44_eeprom_attr, &sfp45_eeprom_attr, + &sfp46_eeprom_attr, &sfp47_eeprom_attr, &sfp48_eeprom_attr, &sfp49_eeprom_attr, &sfp50_eeprom_attr, + &sfp51_eeprom_attr, &sfp52_eeprom_attr, &sfp53_eeprom_attr, &sfp54_eeprom_attr, &sfp55_eeprom_attr, + &sfp56_eeprom_attr, + NULL +}; + +static const struct attribute_group fn8656_bnf_sfp_group = { .bin_attrs = fn8656_bnf_sfp_epprom_attributes}; + +static int kwai_fpga_probe(struct pci_dev *pdev, + const struct pci_device_id *pci_id) +{ + struct kwai_fpga *fpga; + int err, i = 0; + int status = 0; + uint8_t sw_ver = 0; + + + fpga = kzalloc(sizeof(struct kwai_fpga), GFP_KERNEL); + if (!fpga) + return -ENOMEM; + + fpga->pdev = pdev; + pdev->sysdata = (void *)fpga; + mutex_init(&fpga->lock); + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR "kwai_fpga: Can't enable device.\n"); + goto err_dev; + } + if (!devm_request_mem_region(&pdev->dev, pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), + "kwai_fpga")) { + printk(KERN_WARNING "kwai_fpga: Can't request iomem (0x%llx).\n", + (unsigned long long)pci_resource_start(pdev, 0)); + err = -EBUSY; + goto err_disable; + } + pci_set_master(pdev); + pci_set_drvdata(pdev, fpga); + + fpga->mmio = devm_ioremap(&pdev->dev, pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!fpga->mmio) { + printk(KERN_ERR "kwai_fpga: ioremap() failed\n"); + err = -EIO; + goto err_disable; + } + + for(i = 1; i <= MAX_PORT_NUM; i++) + { + fpga->chip[i].dev_class = CMIS_ADDR; + fpga->chip[i].byte_len = ONE_ADDR_EEPROM_SIZE; + fpga->chip[i].write_max = I2C_SMBUS_BLOCK_MAX; + fpga->chip[i].slave_addr = SFP_EEPROM_A0_ADDR; + } + status = sysfs_create_group(&pdev->dev.kobj, &fn8656_bnf_sfp_group); + if (status) { + goto err_disable; + } + status = sysfs_create_group(&pdev->dev.kobj, &fn8656_bnf_fpga_group); + if (status) { + goto err_disable; + } + + sfp_task = kthread_run(sfp_poll, (void*)fpga, "sfpd"); + if(!sfp_task){ + pega_print(ERR,"Unable to start kernel thread.\n"); + return -ECHILD; + } + + sw_ver = readl(fpga->mmio + FPGA_SW_VERSION); + if(sw_ver > 0x6) { + fpga->i2c_mode = FPGA_I2C_RD_MODE_BLOCK; + } + else { + fpga->i2c_mode = FPGA_I2C_RD_MODE_BYTE; + } + + return 0; + +err_disable: + pci_disable_device(pdev); +err_dev: + kfree(fpga); + + return err; +} + +static void kwai_fpga_remove(struct pci_dev *pdev) +{ + struct kwai_fpga *fpga = pdev->sysdata; + + if(sfp_task) + { + kthread_stop(sfp_task); + sfp_task = NULL; + } + sysfs_remove_group(&pdev->dev.kobj, &fn8656_bnf_sfp_group); + sysfs_remove_group(&pdev->dev.kobj, &fn8656_bnf_fpga_group); + devm_iounmap(&pdev->dev, fpga->mmio); + pci_disable_device(pdev); + kfree(fpga); +} + +static const struct pci_device_id kwai_fpga_pci_tbl[] = { + { PCI_DEVICE(0x10EE, 0x7021) }, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, kwai_fpga_pci_tbl); + +static struct pci_driver kwai_fpga_pci_driver = { + .name = "kwai_fpga", + .id_table = kwai_fpga_pci_tbl, + .probe = kwai_fpga_probe, + .remove = kwai_fpga_remove, + .suspend = NULL, + .resume = NULL, +}; + +module_pci_driver(kwai_fpga_pci_driver); + +module_param(loglevel, uint, 0664); +module_param(enable_sfp_eeprom_cache, uint, 0664); +module_param(enable_sfp_three_batch, uint, 0664); +module_param_string(fpga_debug, fpga_debug, MAX_DEBUG_INFO_LEN, 0664); + +MODULE_AUTHOR("Bao Hengxi "); +MODULE_DESCRIPTION("fn8656_bnf_sfp driver"); +MODULE_LICENSE("GPL"); diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_watchdog.c b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_watchdog.c new file mode 100644 index 000000000000..d05c899db78d --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/modules/pegatron_fn8656_bnf_watchdog.c @@ -0,0 +1,464 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "linux/kthread.h" +#include +#include +#include +#include +#include +#include +#include "pegatron_pub.h" + +enum watchdog_sensor_sysfs_attributes +{ + ARM, + DISARM, + IS_ARMED, + FEED_DOG, + IDENTIFY, + STATE, + TIMELEFT, + TIMEOUT, + RESET, + WDT_ENABLE, + WDT_DEBUG +}; + +#define MODULE_NAME "pegatron_fn8656_watchdog" +#define ERROR_SUCCESS 0 + +struct kobject *kobj_switch = NULL; + +extern int pegatron_fn8656_bnf_cpld_read(unsigned short cpld_addr, u8 reg); +extern int pegatron_fn8656_bnf_cpld_write(unsigned short cpld_addr, u8 reg, u8 value); + + +static uint loglevel = LOG_INFO | LOG_WARNING | LOG_ERR; +static struct kobject * kobj_watchdog_root = NULL; + +unsigned long armed_jiffies; +unsigned long curr_jiffies; +u32 timeout = 32; + +#define WATCHDOG_CPLD_ADDRESS 0x18 + +#define WATCHDOG_CPLD_WDT_REG 0x12 +#define WATCHDOG_CPLD_WDT_ENB 0x1 /*0: Enable 1: Disable*/ +#define WATCHDOG_CPLD_WDT_ENB_MASK 0x1 +#define WATCHDOG_CPLD_WDT_FEED 0x80 /*WDT_CPU_FLAG*/ +#define WATCHDOG_CPLD_WDT_TIMEOUT_MASK 0xe +#define WATCHDOG_CPLD_WDT_TIMEOUT_1S (0 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_3S (1 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_5S (2 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_10S (3 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_30S (4 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_60S (5 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_120S (6 << 1) +#define WATCHDOG_CPLD_WDT_TIMEOUT_180S (7 << 1) + +#define WATCHDOG_CPLD_WDT_TIMELEFT_REG 0x14 + + +#define timeout_set(timeout, set_value) \ +do { \ + set_value &= (~WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ + if (timeout <= 5) \ + set_value |= (WATCHDOG_CPLD_WDT_TIMEOUT_5S & WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ + else if (timeout <= 10) \ + set_value |= (WATCHDOG_CPLD_WDT_TIMEOUT_10S & WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ + else if (timeout <= 30) \ + set_value |= (WATCHDOG_CPLD_WDT_TIMEOUT_30S & WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ + else if (timeout <= 60) \ + set_value |= (WATCHDOG_CPLD_WDT_TIMEOUT_60S & WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ + else if (timeout <= 120) \ + set_value |= (WATCHDOG_CPLD_WDT_TIMEOUT_120S & WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ + else \ + set_value |= (WATCHDOG_CPLD_WDT_TIMEOUT_180S & WATCHDOG_CPLD_WDT_TIMEOUT_MASK); \ +}while(0) + + +static ssize_t bsp_cpu_cpld_write_byte(u8 data, u8 reg) +{ + return pegatron_fn8656_bnf_cpld_write(WATCHDOG_CPLD_ADDRESS, reg, data); +} + +static ssize_t bsp_cpu_cpld_read_byte(u8 *data, u8 reg) +{ + *data = pegatron_fn8656_bnf_cpld_read(WATCHDOG_CPLD_ADDRESS, reg); + return 0; +} + +static ssize_t bsp_sysfs_watchdog_custom_set_attr(struct device *kobject, struct device_attribute *da, const char *buf, size_t count) +{ + int temp = 0; + int ret = ERROR_SUCCESS; + u8 set_value = 0; + u8 get_value = 0; + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + switch (attr->index) + { + case ARM: + { + if (sscanf(buf, "%d", &temp) <= 0) + { + pega_print(ERR, "Format '%s' error, integer expected!", buf); + ret = -EINVAL; + } + else + { + if (0 == temp) + { + set_value |= WATCHDOG_CPLD_WDT_ENB; + pega_print(DEBUG,"watchdog timer disabled!"); + } + else + { + set_value &= (~WATCHDOG_CPLD_WDT_ENB); + pega_print(DEBUG,"watchdog timer enabled!"); + } + + armed_jiffies = jiffies; + if (temp > 255) + temp = 255; + timeout_set(temp, set_value); + timeout = temp; + ret = bsp_cpu_cpld_write_byte(set_value, WATCHDOG_CPLD_WDT_REG); + } + break; + } + case TIMEOUT: + { + if (sscanf(buf, "%d", &temp) <= 0) + { + pega_print(DEBUG, "Format '%s' error, integer expected!", buf); + ret = -EINVAL; + } + else + { + if (temp > 255) + temp = 255; + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + set_value = get_value; + timeout_set(temp, set_value); + timeout = temp; + ret = bsp_cpu_cpld_write_byte(set_value, WATCHDOG_CPLD_WDT_REG); + } + break; + } + case DISARM: + { + if (sscanf(buf, "%d", &temp) <= 0) + { + pega_print(DEBUG, "Format '%s' error, integer expected!", buf); + ret = -EINVAL; + } + else + { + timeout_set(temp, set_value); + set_value |= WATCHDOG_CPLD_WDT_ENB; + ret = bsp_cpu_cpld_write_byte(set_value, WATCHDOG_CPLD_WDT_REG); + pega_print(DEBUG,"watchdog timer disabled!"); + } + break; + } + case WDT_ENABLE: + { + if (sscanf(buf, "%d", &temp) <= 0) + { + pega_print(DEBUG, "Format '%s' error, integer expected!", buf); + ret = -EINVAL; + } + else + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + if(((get_value & WATCHDOG_CPLD_WDT_ENB_MASK) == 1) && (temp == 1)) + { + armed_jiffies = jiffies; + set_value = get_value & (~WATCHDOG_CPLD_WDT_ENB); + ret = bsp_cpu_cpld_write_byte(set_value, WATCHDOG_CPLD_WDT_REG); + pega_print(DEBUG,"watchdog timer enabled!"); + } + else if(((get_value & WATCHDOG_CPLD_WDT_ENB_MASK) == 0) && (temp == 0)) + { + set_value = get_value | WATCHDOG_CPLD_WDT_ENB; + ret = bsp_cpu_cpld_write_byte(set_value, WATCHDOG_CPLD_WDT_REG); + pega_print(DEBUG,"watchdog timer disabled!"); + } + } + break; + } + case FEED_DOG: + case RESET: + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + armed_jiffies = jiffies; + pega_print(DEBUG,"feed dog!"); + break; + } + default: + { + pega_print(ERR, "Not found attr %d for watchdog", attr->index); + ret = -ENOSYS; + break; + } + } + +exit: + if (ret != ERROR_SUCCESS) + { + count = ret; + } + return count; +} + +static ssize_t bsp_sysfs_watchdog_custom_get_attr(struct device *kobj, struct device_attribute *da, char *buf) +{ + ssize_t index = 0; + int ret = ERROR_SUCCESS; + u8 get_value; + int int_value =0; + //int float_value =0; + unsigned int run_time = 0; + int left_time = 0; + u8 timeout_data[8] = {1, 3, 5, 10, 30, 60, 120, 180}; + + struct sensor_device_attribute *attr = to_sensor_dev_attr(da); + + switch(attr->index) + { + case ARM: + case TIMEOUT: + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + index = scnprintf(buf, PAGE_SIZE, "%d\n", timeout_data[(get_value >> 1) & 0x7]); + break; + } + case WDT_ENABLE: + case IS_ARMED: + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + if((get_value & WATCHDOG_CPLD_WDT_ENB_MASK) == 1) + { + index = sprintf(buf, "%d\n", 0); + } + else + { + index = sprintf(buf, "%d\n", 1); + } + break; + } + case DISARM: + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + if((get_value & WATCHDOG_CPLD_WDT_ENB_MASK) == 1) + { + index = scnprintf(buf, PAGE_SIZE, "%d\n", 1); + } + else + { + index = scnprintf(buf, PAGE_SIZE, "%d\n", 0); + } + break; + } + case IDENTIFY: + { + index = scnprintf(buf, PAGE_SIZE, "pegatron_cpld_wdt\n"); + break; + } + case STATE: + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + if((get_value & WATCHDOG_CPLD_WDT_ENB_MASK) == 1) + { + index = scnprintf(buf, PAGE_SIZE, "inactive\n"); + } + else + { + index = scnprintf(buf, PAGE_SIZE, "active\n"); + } + break; + } + case TIMELEFT: + { +#if 0 + curr_jiffies = jiffies; + + run_time = jiffies_to_msecs(curr_jiffies - armed_jiffies) / 1000; + + left_time = timeout - run_time; + if (left_time < 0) + left_time = 0; +#else + + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_TIMELEFT_REG); + left_time = get_value; +#endif + + index = sprintf(buf, "%d\n", left_time); + break; + } + case WDT_DEBUG: + { + ret = bsp_cpu_cpld_read_byte(&get_value, WATCHDOG_CPLD_WDT_REG); + int_value = timeout_data[(get_value >> 1) & 0x7]; + + if((get_value & WATCHDOG_CPLD_WDT_ENB_MASK) == 0) + { + index = scnprintf(buf, PAGE_SIZE, "enable: 1\ntimeout:%d\n", int_value); + } + else + { + index = scnprintf(buf, PAGE_SIZE, "enable: 0\ntimeout:%d\n", int_value); + } + index += scnprintf(buf + index, PAGE_SIZE - index, "%s\n", "BSP DEBUG WDT"); + break; + } + default: + { + pega_print(DEBUG, "watchdog attribte %d is invalid\n", attr->index); + break; + } + } +exit: + return index; +} + +//debug node +static SENSOR_DEVICE_ATTR(arm, S_IRUGO|S_IWUSR, bsp_sysfs_watchdog_custom_get_attr, bsp_sysfs_watchdog_custom_set_attr, ARM); +static SENSOR_DEVICE_ATTR(disarm, S_IRUGO|S_IWUSR, bsp_sysfs_watchdog_custom_get_attr, bsp_sysfs_watchdog_custom_set_attr, DISARM); +static SENSOR_DEVICE_ATTR(is_armed, S_IRUGO, bsp_sysfs_watchdog_custom_get_attr, NULL, IS_ARMED); +static SENSOR_DEVICE_ATTR(feed_dog, S_IWUSR, NULL, bsp_sysfs_watchdog_custom_set_attr, FEED_DOG); + +static SENSOR_DEVICE_ATTR(identify, S_IRUGO, bsp_sysfs_watchdog_custom_get_attr, NULL, IDENTIFY); +static SENSOR_DEVICE_ATTR(state, S_IRUGO, bsp_sysfs_watchdog_custom_get_attr, NULL, STATE); +static SENSOR_DEVICE_ATTR(timeleft, S_IRUGO, bsp_sysfs_watchdog_custom_get_attr, NULL, TIMELEFT); +static SENSOR_DEVICE_ATTR(timeout, S_IRUGO|S_IWUSR, bsp_sysfs_watchdog_custom_get_attr, bsp_sysfs_watchdog_custom_set_attr, TIMEOUT); +static SENSOR_DEVICE_ATTR(reset, S_IWUSR, NULL, bsp_sysfs_watchdog_custom_set_attr, RESET); +static SENSOR_DEVICE_ATTR(enable, S_IRUGO|S_IWUSR, bsp_sysfs_watchdog_custom_get_attr, bsp_sysfs_watchdog_custom_set_attr, WDT_ENABLE); + +static SENSOR_DEVICE_ATTR(debug, S_IRUGO, bsp_sysfs_watchdog_custom_get_attr, NULL, WDT_DEBUG); +//BSPMODULE_DEBUG_RW_ATTR_DEF(loglevel, BSP_WATCHDOG_MODULE); + +static struct attribute *watchdog_debug_attributes[] = +{ + &sensor_dev_attr_arm.dev_attr.attr, + &sensor_dev_attr_disarm.dev_attr.attr, + &sensor_dev_attr_is_armed.dev_attr.attr, + &sensor_dev_attr_feed_dog.dev_attr.attr, + + &sensor_dev_attr_identify.dev_attr.attr, + &sensor_dev_attr_state.dev_attr.attr, + &sensor_dev_attr_timeleft.dev_attr.attr, + &sensor_dev_attr_timeout.dev_attr.attr, + &sensor_dev_attr_reset.dev_attr.attr, + &sensor_dev_attr_enable.dev_attr.attr, + &sensor_dev_attr_debug.dev_attr.attr, +// &bspmodule_loglevel.attr, + NULL +}; + +static const struct attribute_group watchdog_switch_attribute_group = +{ + .attrs = watchdog_debug_attributes, +}; + +void watchdog_sysfs_exit(void) +{ + if (kobj_watchdog_root != NULL && kobj_watchdog_root->state_initialized) + { + sysfs_remove_group(kobj_watchdog_root, &watchdog_switch_attribute_group); + kobject_put(kobj_watchdog_root); + } + return; +} + +int watchdog_sysfs_init(void) +{ + int ret = ERROR_SUCCESS; + kobj_watchdog_root = kobject_create_and_add("watchdog", kobj_switch); + + if (kobj_watchdog_root == NULL) + { + pega_print(ERR, "create kobj_watchdog_root failed!"); + ret = -ENOMEM; + goto exit; + } + + ret = sysfs_create_group(kobj_watchdog_root, &watchdog_switch_attribute_group); + +exit: + if (ret != 0) + { + pega_print(ERR, "watchdog sysfs init failed!\n"); + watchdog_sysfs_exit(); + } + + return ret; +} + +int bsp_sysfs_init(void) +{ + int ret = ERROR_SUCCESS; + + kobj_switch = kobject_create_and_add("clx", kernel_kobj->parent); + + + return ret; +} + + +void bsp_sysfs_release_kobjs(void) +{ + if (kobj_switch != NULL) + { + kobject_put(kobj_switch); + } + return; +} + + + +static int __init watchdog_init(void) +{ + int ret = ERROR_SUCCESS; + + bsp_sysfs_init(); + ret = watchdog_sysfs_init(); + if (ERROR_SUCCESS == ret) + { + pega_print(INFO,"pegatron_fn8656_watchdog module finished and success!"); + } + else + { + pega_print(INFO,"pegatron_fn8656_watchdog module finished and failed!"); + } + + return ret; +} + + +static void __exit watchdog_exit(void) +{ + watchdog_sysfs_exit(); + bsp_sysfs_release_kobjs(); + pega_print(INFO,"pegatron_fn8656_watchdog module uninstalled !\n"); + return; +} + +module_param(loglevel,uint,0644); + +MODULE_PARM_DESC(loglevel,"0x01-LOG_ERR,0x02-LOG_WARNING,0x04-LOG_INFO,0x08-LOG_DEBUG"); + + +module_init(watchdog_init); +module_exit(watchdog_exit); + +MODULE_AUTHOR("Junde Zhou "); +MODULE_DESCRIPTION("pegatron watchdog driver"); +MODULE_LICENSE("Dual BSD/GPL"); diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/__init__.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/__init__.py new file mode 100755 index 000000000000..e69de29bb2d1 diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/common.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/common.py new file mode 100755 index 000000000000..1503bb660594 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/common.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 +# +# 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 . + +import sys +import subprocess, threading +import socket +#import signal, select +#from functools import partial +#import queue as Queue + +RUN = False +PASS = 0 +FAIL = 1 + +SOCKET_PORT = 50000 +SOCKET_RECV_BUFFER = 4096 +SOCKET_TIME_OUT = 20 +FILE_LOCK = threading.Lock() +SOCKET_LOCK = threading.Lock() + +CMD_TYPE = ['global', 'device'] +RESPONSE_ERROR_PARAMETER = "Parameters error" +I2C_PREFIX = '/sys/bus/i2c/devices/' + +def doBash(cmd): + status, output = subprocess.getstatusoutput(cmd) + + return status, output + +def doSend(msg, port): + if SOCKET_LOCK.acquire(): + host = socket.gethostname() + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(SOCKET_TIME_OUT) + + try: + s.connect((host, port)) + except Exception: + sys.exit(0) + + s.sendall(msg.encode(encoding='utf-8')) + result = s.recv(SOCKET_RECV_BUFFER).decode(encoding='utf-8') + s.close() + SOCKET_LOCK.release() + return result + +def readFile(path): + if FILE_LOCK.acquire(): + try: + file = open(path) + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + FILE_LOCK.release() + return 'Error' + + value = file.readline().rstrip() + file.close() + FILE_LOCK.release() + + return value + +def writeFile(path, value): + if FILE_LOCK.acquire(): + try: + file = open(path, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + FILE_LOCK.release() + return 'Error' + + file.seek(0) + file.write(str(value)) + file.close() + FILE_LOCK.release() + + return "Success" diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/device.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/device.py new file mode 100755 index 000000000000..4cb877d311ea --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/device.py @@ -0,0 +1,471 @@ +#!/usr/bin/env python3 +# +# 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 . + +import common + +TOTAL_PORT_NUM = 56 +SFP_MAX_NUM = 0 +CPLDA_SFP_NUM = 0 +CPLDB_SFP_NUM = 28 +CPLDC_SFP_NUM = 28 +FAN_NUM = 6 +MOTOR_NUM_PER_FAN = 1 +CPLD_NUM = 4 +PSU_NUM = 2 +TEMP_SENSOR_NUM_PER_PSU = 3 + +THERMAL_SENSOR_NUM = 8 +NEED_WORK = 5 +PATH_INDEX = 5 +SYSSENSOR_PREFIX = '/sys/switch/sensor/' +SENSOR_PATH = SYSSENSOR_PREFIX+"temp"+'{}'+'/' + +THERMAL_NODE_COMBINATION = ( + "temp_input", + "temp_max_hyst", + "temp_max", + "temp_alias", + "temp_type", +) + +THERMAL_COMBINATION = { + 0: ( + "temp1_input", + "temp1_max", + "temp1_crit", + "Ambient MAC side", + "LM75BD / Ambient MAC side", + "/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/", + ), + 1: ( + "temp2_input", + "temp2_max", + "temp2_crit", + "Ambient MAC", + "ASIC", + "/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/", + ), + 2: ( + "temp3_input", + "temp3_max", + "temp3_crit", + "Ambient FAN", + "LM75BD / Ambient FAN", + "/sys/bus/i2c/devices/4-0070/hwmon/hwmon4/", + ), + 3: ( + "temp1_input", + "temp1_max", + "temp1_max_hyst", + "Ambient NPU", + "LM75BD / Ambient NPU", + "/sys/bus/i2c/devices/1-004a/hwmon/hwmon1/", + ), + 4: ( + "temp2_input", + "temp2_max", + "temp2_crit", + "CPU", + "Core 0", + "/sys/devices/platform/coretemp.0/hwmon/hwmon0/" + ), + 5: ( + "temp3_input", + "temp3_max", + "temp3_crit", + "CPU", + "Core 1", + "/sys/devices/platform/coretemp.0/hwmon/hwmon0/" + ), + 6: ( + "temp4_input", + "temp4_max", + "temp4_crit", + "CPU", + "Core 2", + "/sys/devices/platform/coretemp.0/hwmon/hwmon0/" + ), + 7: ( + "temp5_input", + "temp5_max", + "temp5_crit", + "CPU", + "Core 3", + "/sys/devices/platform/coretemp.0/hwmon/hwmon0/" + ), +} + +DEVICE_BUS = {'cpld': ['6-0074', '7-0075', '8-0076'], + 'fan': ['4-0070'], + 'psu': ['2-0058', '3-0059'], + 'status_led': ['6-0074'], + 'fp_0_led': ['7-0075'], + 'fp_1_led': ['8-0076'] + } +DEVICE_BUS_FAN_NODE = ['4-0070/hwmon/hwmon4/'] +DEVICE_BUS_PSU_NODE = ['2-0058/hwmon/hwmon2/', '3-0059/hwmon/hwmon3/'] + +class DeviceThread(common.threading.Thread): + def __init__(self,threadname, q): + common.threading.Thread.__init__(self,name = threadname) + self.queue = q + + def run(self): + while common.RUN: + message = self.queue.get() + self.onMessage(message) + + def onMessage(self, message): + """ + Commands: + led : Led controls + locate : Blink locator LED + sensors : Read HW monitors + """ + + if len(message.command) < 1: + result = self.onMessage.__doc__ + else: + if message.command[0] == 'init': + result = deviceInit() + elif message.command[0] == 'led': + result = ledControls(message.command[1:]) + elif message.command[0] == 'locate': + locatethread = common.threading.Thread(target = locateDeviceLed) + locatethread.start() + result = 'Success' + elif message.command[0] == 'sensors': + result = getSensors() + else: + result = self.onMessage.__doc__ + + if (message.callback is not None): + message.callback(result) + +STATUS_ALERT = {'fan': ['wrongAirflow_alert', 'outerRPMOver_alert', 'outerRPMUnder_alert', 'outerRPMZero_alert', + 'innerRPMOver_alert', 'innerRPMUnder_alert', 'innerRPMZero_alert', 'notconnect_alert'], + 'psu': ['vout_over_voltage', 'iout_over_current_fault', 'iout_over_current_warning', + 'iput_over_current_warning', 'iput_insufficient', 'temp_over_temp_fault', 'temp_over_temp_warning']} +class PlatformStatusThread(common.threading.Thread): + def __init__(self,threadname, timer): + self.running = True + common.threading.Thread.__init__(self,name = threadname) + self.timer = timer + self.fan_led_status = 'off' + self.psu_led_status = 'off' + + def run(self): + while common.RUN: + self.checkPlatformStatus() + common.time.sleep(self.timer) + + def checkPlatformStatus(self): + total_result = common.PASS + total_result += self.checkFanStatus() + total_result += self.checkPsuStatus() + + def checkFanStatus(self): + fan_result = common.PASS + fan_bus = DEVICE_BUS['fan'] + fan_bus_nodes = DEVICE_BUS_FAN_NODE + fan_alert = STATUS_ALERT['fan'] + fan_led = LED_COMMAND['fan_led'] + fan_normal = 'green' + fan_abnormal = 'blink_amber' + led_bus = DEVICE_BUS['status_led'] + led_path = common.I2C_PREFIX + led_bus[0] + '/' + LED_NODES[3] + + status, output = common.doBash("ls " + common.I2C_PREFIX) + if output.find(fan_bus[0]) != -1: + for num in range(0,FAN_NUM): + for alert_type in fan_alert: + path = common.I2C_PREFIX + fan_bus_nodes[0] + "/fan" + str(num+1) + "_" + alert_type + result = common.readFile(path) + if result != 'Error': + fan_result += int(result) + if fan_result != common.PASS: + if self.fan_led_status != fan_abnormal: + common.writeFile(led_path, fan_led[fan_abnormal]) + self.fan_led_status = fan_abnormal + common.syslog.syslog(common.syslog.LOG_ERR, 'FAN Status Error !!!') + return common.FAIL + + if self.fan_led_status != fan_normal: + common.writeFile(led_path, fan_led[fan_normal]) + self.fan_led_status = fan_normal + common.syslog.syslog(common.syslog.LOG_ERR, 'FAN Status Normal !!!') + return common.PASS + + def checkPsuStatus(self): + psu_result = common.PASS + psu_bus = DEVICE_BUS['psu'] + psu_bus_nodes = DEVICE_BUS_PSU_NODE + psu_alert = STATUS_ALERT['psu'] + psu_led = LED_COMMAND['pwr_led'] + psu_normal = 'green' + psu_abnormal = 'blink_amber' + led_bus = DEVICE_BUS['status_led'] + led_path = common.I2C_PREFIX + led_bus[0] + '/' + LED_NODES[1] + + status, output = common.doBash("ls " + common.I2C_PREFIX) + if output.find(psu_bus[0]) != -1 and output.find(psu_bus[1]) != -1: + for nodes in psu_bus_nodes: + for alert_type in psu_alert: + path = common.I2C_PREFIX + nodes + "/" + alert_type + result = common.readFile(path) + if result != 'Error': + psu_result += int(result) + if psu_result != common.PASS: + if self.psu_led_status != psu_abnormal: + common.writeFile(led_path, psu_led[psu_abnormal]) + self.psu_led_status = psu_abnormal + common.syslog.syslog(common.syslog.LOG_ERR, 'PSU Status Error !!!') + return common.FAIL + + if self.psu_led_status != psu_normal: + common.writeFile(led_path, psu_led[psu_normal]) + self.psu_led_status = psu_normal + common.syslog.syslog(common.syslog.LOG_ERR, 'PSU Status Normal !!!') + return common.PASS + +LED_COMMAND = {'sys_led': {'green':'1', 'amber':'3', 'off':'0', 'blink_green':'4', 'blink_amber':'6'}, + 'pwr_led': {'green':'1', 'amber':'3', 'off':'0', 'blink_green':'4', 'blink_amber':'6'}, + 'loc_led': {'on':'0', 'off':'1', 'blink':'2'}, + 'fan_led': {'green':'1', 'amber':'3', 'off':'0', 'blink_green':'4', 'blink_amber':'6'}, + 'cpld_allled_ctrl': {'off':'3', 'mix':'1', 'amber':'2', 'normal':'0'}, + 'fp_0_led': {'disable':'0', 'enable':'1'}, + 'fp_1_led': {'disable':'0', 'enable':'1'}, + 'serial_led_enable': {'disable':'0', 'enable':'1'}} +LED_NODES = ['sys_led', 'pwr_led', 'loc_led', 'fan_led', "cpld_allled_ctrl", "serial_led_enable"] +def ledControls(args): + """ + Commands: + set : Set led config + get : Get led status + """ + COMMAND_TYPE = ['set', 'get'] + if len(args) < 1 or args[0] not in COMMAND_TYPE: + return ledControls.__doc__ + + result = setGetLed(args[0:]) + + return result + +def setGetLed(args): + """ + Commands: + sys_led : System status led [green/amber/off/blink_green/blink_amber] + pwr_led : Power status led [green/amber/off/blink_green/blink_amber] + loc_led : Locator led [on/off/blink] + fan_led : Fan led [green/amber/off/blink_green/blink_amber] + """ + if len(args) < 3 or args[1] not in LED_COMMAND: + return setGetLed.__doc__ + + for i in range(0,len(LED_NODES)): + if args[1] == LED_NODES[i]: + led_bus = DEVICE_BUS['status_led'] + path = common.I2C_PREFIX + led_bus[0] + '/' + LED_NODES[i] + if args[1] == 'fp_0_led': + led_bus = DEVICE_BUS['fp_0_led'] + path = common.I2C_PREFIX + led_bus[0] + '/' + 'serial_led_enable' + if args[1] == 'fp_1_led': + led_bus = DEVICE_BUS['fp_1_led'] + path = common.I2C_PREFIX + led_bus[0] + '/' + 'serial_led_enable' + command = LED_COMMAND[args[1]] + + if args[0] == 'set': + if args[2] in command: + data = command[args[2]] + result = common.writeFile(path, data) + else: + result = setGetLed.__doc__ + else: + result = common.readFile(node) + if result != "Error": + result = list (command.keys()) [list (command.values()).index (result)] + + return result + +def locateDeviceLed(): + setGetLed(['set', 'loc_led', 'blink']) + common.time.sleep(20) + setGetLed(['set', 'loc_led', 'off']) + +SENSORS_PATH = common.I2C_PREFIX + '4-0070/hwmon/hwmon4/' #maurice arbiter +SENSORS_NODES = {'fan_rpm': ['_inner_rpm', '_outer_rpm'], + 'fan_vol': ['ADC1_vol', 'ADC2_vol','ADC3_vol', 'ADC4_vol','ADC5_vol', 'ADC6_vol', 'ADC7_vol', 'ADC8_vol'], + 'temp':['temp1_input', 'temp2_input', 'temp3_input'], + 'fan_alert':['_status_alert', '_wrongAirflow_alert', '_outerRPMOver_alert', '_outerRPMUnder_alert', + '_outerRPMZero_alert', '_innerRPMOver_alert', '_innerRPMUnder_alert', '_innerRPMZero_alert', '_notconnect_alert'], + 'vol_alert':['_under_alert', '_over_alert'], + 'temp_alert':['lm75_48_temp_alert', 'lm75_49_temp_alert', 'lm75_4a_temp_alert', 'sa56004x_Ltemp_alert', 'sa56004x_Rtemp_alert']} +SENSORS_TYPE = {'fan_rpm': ['Inner RPM', 'Outer RPM'], + 'fan_vol': ['P0.1', 'P0.2','P0.6', 'P0.7','P1.0', 'P1.1', 'P1.2', 'P1.6']} +def getSensors(): + string = '' + # Firmware version + val = common.readFile(SENSORS_PATH + 'mb_fw_version') + string = '\n' + "MB-SW Version: " + val + + val = common.readFile(SENSORS_PATH + 'fb_fw_version') + string += '\n' + "FB-SW Version: " + val + + # Fan + string += getFan() + + # HW Monitor + #string += '\n' + getHWMonitor() + + # Voltage + string += '\n' + getVoltage() + + return string + +def getFan(): + string = '' + for i in range(0,FAN_NUM): + # Status + result = getFanStatus(i) + string += '\n\n' + "FAN " + str(i+1) + ": " + result + + if result == 'Disconnect': + continue + + # Alert + result = getFanAlert(i) + string += '\n' + " Status: " + result + + # Inner RPM + result = getFanInnerRPM(i) + string += '\n' + " Inner RPM: " + result.rjust(10) + " RPM" + + # Outer RPM + result = getFanOuterRPM(i) + string += '\n' + " Outer RPM: " + result.rjust(10) + " RPM" + + return string + +def getFanStatus(num): + val = common.readFile(SENSORS_PATH + 'fan' + str(num+1) + '_present') + if val != 'Error': + if (int(val, 16) & 0x1) == 0x1: + result = 'Connect' + else: + result = 'Disconnect' + else: + result = val + return result + +def getFanAlert(num): + alert = 0 + alert_types = SENSORS_NODES['fan_alert'] + for alert_type in alert_types: + val = common.readFile(SENSORS_PATH + 'fan' + str(num+1) + alert_type) + if val != 'Error': + alert += int(val, 16) + else: + return val + + if alert > 0: + result = 'Warning' + else: + result = 'Normal' + + return result + +def getFanInnerRPM(num): + return common.readFile(SENSORS_PATH + 'fan' + str(num+1) + '_inner_rpm') + +def getFanOuterRPM(num): + return common.readFile(SENSORS_PATH + 'fan' + str(num+1) + '_outer_rpm') + +def getHWMonitor(): + string = '' + try: + temp_type = SENSORS_TYPE['temp'] + except Exception: + return string + + for types in temp_type: + val = common.readFile(SENSORS_PATH + types) + val_alert = common.readFile(SENSORS_PATH + types + '_alert') + if val_alert != 'Error': + if int(val_alert, 16) == 1: + alert = 'Warning' + else: + alert = 'Normal' + else: + alert = val_alert + string += '\n' + types + ": " + val + " C" + " ( " + alert + " )" + + return string + +def getVoltage(): + string = '' + nodes = SENSORS_NODES['fan_vol'] + types = SENSORS_TYPE['fan_vol'] + for i in range(0,len(nodes)): + val = common.readFile(SENSORS_PATH + nodes[i]) + alert = getVoltageAlert(i) + string += '\n' + types[i] + ": " + val + " V ( " + alert + " )" + + return string + +def getVoltageAlert(num): + alert = 0 + nodes = SENSORS_NODES['vol_alert'] + for node in nodes: + val = common.readFile(SENSORS_PATH + 'ADC' + str(num+1) + node) + if val != 'Error': + alert += int(val, 16) + else: + return val + + if alert > 0: + result = 'Warning' + else: + result = 'Normal' + + return result + +DEVICE_INIT = {'led': [['set', 'sys_led', 'green'], ['set', 'pwr_led', 'green'], ['set', 'fan_led', 'green'], ['set', 'cpld_allled_ctrl', 'normal'], ['set', 'serial_led_enable', 'enable'], ['set', 'fp_0_led', 'enable'], ['set', 'fp_1_led', 'enable']]} +def deviceInit(): + # Set led + for i in range(0,len(DEVICE_INIT['led'])): + setGetLed(DEVICE_INIT['led'][i]) + + cpld_bus = DEVICE_BUS['cpld'] + # Set QSFP reset to normal + for x in range(SFP_MAX_NUM, TOTAL_PORT_NUM): + if x < CPLDB_SFP_NUM: + bus = cpld_bus[1] + else: + bus = cpld_bus[2] + + path = common.I2C_PREFIX + bus + '/sfp' + str(x+1) + '_reset' + common.writeFile(path, "0") + + # Set QSFP lpmode to high + for x in range(SFP_MAX_NUM, TOTAL_PORT_NUM): + if x < CPLDB_SFP_NUM: + bus = cpld_bus[1] + else: + bus = cpld_bus[2] + + path = common.I2C_PREFIX + bus + '/sfp' + str(x+1) + '_lowpower' + common.writeFile(path, "0") + + return diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/fwupdates.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/fwupdates.py new file mode 100644 index 000000000000..6d7416418c90 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/fwupdates.py @@ -0,0 +1,356 @@ +#!/usr/bin/env python + +######################################################################## +# Clounix +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in +# the platform +# +######################################################################## + +try: + import os + import re +# from .helper import APIHelper + import helper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_QUERY_VERSION_COMMAND = "dmidecode -s bios-version" + + +class Component(): + """Clounix Platform-specific Component class""" + def __init__(self, component_index,component_conf): + self.__index = component_index + self.__conf = component_conf + self.__api_helper = helper.APIHelper() + self.set_fw_state(False) + print("%s install fw" % self.get_name()) + self.auto_updates() + + def set_fw_state(self, state): + self.__fw_state = state + return + + def get_fw_state(self): + return self.__fw_state + + def get_version(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.__conf[self.__index]['version'] + + def auto_updates(self): + if self.get_name() == 'BIOS': + return False + #CPLD main borad is same verson for A/B/C and skip CPLD A/B + if self.get_name() == 'CPLD-A': + return False + if self.get_name() == 'CPLD-B': + return False + + file_ext_dist = {'MCU-MB':'.efm8', 'MCU-FB':'.efm8', 'CPLD-A':'.vme', 'CPLD-B':'.vme','CPLD-C':'.vme','CPLD-D':'.vme','FPGA':'.bin', 'BIOS':'.bin'} + file_name_dist = {'MCU-MB':'mcu_mb', 'MCU-FB':'mcu_fb', 'CPLD-A':'cpld_mb', 'CPLD-B':'cpld_mb','CPLD-C':'cpld_mb','CPLD-D':'cpld_cpu','FPGA':'fpga_mb', 'BIOS':'bios_cpu'} + + version = ''.join(self.get_version()).replace('.', '_') + image_path = '/usr/local/bin/clounix/pegatron_fn8656_{}_v{}{}'.format(file_name_dist[self.get_name()], version, file_ext_dist[self.get_name()]) + #print("fw updates %s.%s.%s.%s.file %d" %(self.get_name(), self.get_firmware_version(), self.get_version(), image_path, os.path.isfile(image_path))) + if not os.path.isfile(image_path): + print("ERROR: File {} doesn't exist or is not a file".format(image_path)) + return False + if not self.check_image_validity(image_path): + return False + + self.set_fw_state(True) + self.__fw_image_path = image_path + + return True + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.__conf[self.__index]['name'] + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.__conf[self.__index]['description'] + + def get_version_path(self): + """ + Retrieves the version path of the component + + Returns: + A string containing the version path of the component + """ + return self.__conf[self.__index]['firmware_version_path'] + + def get_hw_version_path(self): + """ + Retrieves the version path of the component + + Returns: + A string containing the version path of the component + """ + return self.__conf[self.__index]['hw_version_path'] + """ + def get_hw_version(self): + hw_version = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.get_hw_version_path()) + if attr_rv != None: + hw_version = attr_rv + else: + if self.get_name() == 'BIOS': + ret,bios_ver = self.__api_helper.run_command(BIOS_QUERY_VERSION_COMMAND) + if ret: + if bios_ver: + hw_version = re.findall('\d',bios_ver)[0] + return hw_version + """ + + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + firmware_version = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.get_version_path()) + if attr_rv != None: + firmware_version = attr_rv + else: + if self.get_name() == 'BIOS': + ret,bios_ver = self.__api_helper.run_command(BIOS_QUERY_VERSION_COMMAND) + if ret: + if bios_ver: + firmware_version = bios_ver + return firmware_version + + def get_hw_version(self): + return self.get_firmware_version() + + def check_file_validity(self, image_path): + """ + Check installation file validation + + Returns: + bool: True if installation file is valid, False if not + """ + + if not os.path.isfile(image_path): + print("ERROR: File {} doesn't exist or is not a file".format(image_path)) + return False + file_ext_dist = {'MCU-MB':'.efm8', 'MCU-FB':'.efm8', 'CPLD-A':'.vme', 'CPLD-B':'.vme','CPLD-C':'.vme','CPLD-D':'.vme','FPGA':'.bin', 'BIOS':'.bin'} + name_list = os.path.splitext(image_path) + image_ext_name = file_ext_dist[self.get_name()] + if image_ext_name is not None: + if name_list[1] != image_ext_name: + print("ERROR: Extend name of file {} is wrong. Image for {} should have extend name {}".format(image_path, self.get_name(), image_ext_name)) + return False + file_name_dist = {'MCU-MB':'mcu_mb', 'MCU-FB':'mcu_fb', 'CPLD-A':'cpld_mb', 'CPLD-B':'cpld_mb','CPLD-C':'cpld_mb','CPLD-D':'cpld_cpu', 'FPGA':'fpga_mb', 'BIOS':'bios_cpu'} + image_key_name = file_name_dist[self.get_name()] + if image_key_name is not None: + if not image_key_name in image_path: + print("ERROR: File name of file {} is wrong. Image for {} should have key name {}".format(image_path, self.get_name(), image_key_name)) + return False + + return True + + def version_calc_value(self, version): + """ + transfer version string to value, eg 1.2.3.4 tranfer to 1 * 100 + 2 *1 + 3 * 0.01 + 4 * 0.0001 + + Returns: + version value + """ + version_split = version.split('.') + sum = 0 + factor=100 + for val in version_split: + sum += float(val) * factor + factor = factor * 0.01 + return sum + + def check_version_validity(self, image_path): + """ + Check installation version validation + + Returns: + bool: True if installation version is valid, False if not + """ + + run_version = self.get_firmware_version() + + install_version = re.findall(r'v(.+?)\.', image_path) + if install_version: + version = ''.join(install_version).replace('_', '.') + else: + print("please make sure installation version is from released version like as _V0_10.xxx") + return False + + version_val = self.version_calc_value(version) + run_version_val = self.version_calc_value(run_version) + if version_val == run_version_val: + print("installation version %.2f is same as runing version %.2f." % (version_val, run_version_val)) + return False + + return True + + def check_image_validity(self, image_path): + """ + Check installation image validation + + Returns: + bool: True if installation is valid, False if not + """ + + if not self.check_file_validity(image_path): + return False + + if not self.check_version_validity(image_path): + return False + + return True + + def install_firmware(self, img_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + image_path = self.__fw_image_path + if self.get_name() == 'BIOS': + cmd = "/usr/local/bin/install_firmware.sh bios "+ image_path + elif self.get_name() == 'MCU-MB': + cmd = "/usr/local/bin/install_firmware.sh mcu-mb "+ image_path + elif self.get_name() == 'MCU-FB': + cmd = "/usr/local/bin/install_firmware.sh mcu-fb "+ image_path + elif self.get_name() == 'CPLD-A' or self.get_name() == 'CPLD-B' or self.get_name() == 'CPLD-C': + cmd = "/usr/local/bin/install_firmware.sh cpld-mb "+ image_path + elif self.get_name() == 'CPLD-D': + cmd = "/usr/local/bin/install_firmware.sh cpld-cpu "+ image_path + elif self.get_name() == 'FPGA': + cmd = "/usr/local/bin/install_firmware.sh fpga "+ image_path + else: + print(self.get_name() + 'frimware upgrade did not implement') + + os.system(cmd) + print("image install. %s......" % cmd) + return True + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device 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 + """ + model = 'N/A' + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = 'N/A' + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() + + 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 or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False + +class Fwupdates(): + """Clounix Platform-specific Fwupdates class""" + def __init__(self): + self.__api_helper = helper.APIHelper() + chassis_conf = self.__api_helper.get_attr_conf("chassis") + self.__conf = chassis_conf + self._component_list = [] + + self.__num_of_components = len(chassis_conf['components']) + # Initialize COMPONENT + for index in range(0, self.__num_of_components): + component = Component(index,component_conf=chassis_conf['components']) + self._component_list.append(component) + + # check whether firmware should be udpated or not + for index in range(0, self.__num_of_components): + fw_state = self._component_list[index].get_fw_state() + #reboot full system for firmware upgrade + if fw_state : + self._component_list[index].install_firmware("None") + + + # check whether reboot or not when firmware upgrade is done + for index in range(0, self.__num_of_components): + fw_state = self._component_list[index].get_fw_state() + #reboot full system for firmware upgrade + if fw_state : + print("#############reboot system and update firmware") + os.system('sudo reboot') + +def fwupdate(): + + if os.path.isfile("/usr/local/bin/fw_updates_identify"): + return + + Fwupdates() + return +""" +if __name__=='__main__': + fwupdate() +""" diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/helper.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/helper.py new file mode 100644 index 000000000000..eed5d5482954 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/helper.py @@ -0,0 +1,156 @@ +import os +import struct +import subprocess +import json +from mmap import * + +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + +HOST_PLATFORM_JSON = '/usr/share/sonic/device/x86_64-pegatron_fn8656_bnf-r0/platform.json' +PMON_PLATFORM_JSON = '/usr/share/sonic/platform/platform.json' + +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 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 run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + fd.close() + return data.strip() + except IOError: + pass + return None + + def read_one_line_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.readline() + fd.close() + 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)) + fd.close() + except IOError: + return False + return True + + def get_cpld_reg_value(self, getreg_path, register): + cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register) + status, result = self.run_command(cmd) + return result if status else None + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format( + str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def get_attr_conf(self, attr): + """ + Retrieves the json object from json file path + + Returns: + A json object + """ + json_path = '' + if self.is_host() is True: + json_path = HOST_PLATFORM_JSON + else : + json_path = PMON_PLATFORM_JSON + with open(json_path, 'r') as f: + json_data = json.load(f) + + return json_data[attr] diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/main.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/main.py new file mode 100755 index 000000000000..e4029ada9d27 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/pegaProcess/main.py @@ -0,0 +1,610 @@ +#!/usr/bin/env python3 +# +# 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 . + +import common, device +#import fwupdates +import os + +HOST = '' +SOCKET_LIST = [] +SOCKET_MAX_CLIENT = 10 +QUEUES = [] +THREADS = [] +FUNCS = {} + +class GlobalThread(common.threading.Thread): + def __init__(self,threadname, q): + common.threading.Thread.__init__(self,name = threadname) + self.queue = q + + def run(self): + while common.RUN: + message = self.queue.get() + self.onMessage(message) + + def onMessage(self, message): + + """ + Commands: + uninstall : Uninstall platform drivers + """ + if len(message.command) < 1: + result = self.onMessage.__doc__ + else: + if message.command[0] == 'uninstall': + common.RUN = False + doUninstall() + result = 'Success' + else: + result = self.onMessage.__doc__ + if (message.callback is not None): + message.callback(result) + +class messageObject(object): + def __init__(self, command, callback): + super(messageObject, self).__init__() + self.command = command + self.callback = callback + +def callback(sock, result): + sock.sendall(result.encode(encoding='utf-8')) + +def messageHandler(): + server_socket = common.socket.socket(common.socket.AF_INET, common.socket.SOCK_STREAM) + server_socket.setsockopt(common.socket.SOL_SOCKET, common.socket.SO_REUSEADDR, 1) + server_socket.bind((HOST, common.SOCKET_PORT)) + server_socket.listen(SOCKET_MAX_CLIENT) + SOCKET_LIST.append(server_socket) + + while(common.RUN): + ready_to_read,ready_to_write,in_error = common.select.select(SOCKET_LIST,[],[],0) + for sock in ready_to_read: + if sock == server_socket: + sockfd, addr = server_socket.accept() + SOCKET_LIST.append(sockfd) + else: + try: + data = sock.recv(common.SOCKET_RECV_BUFFER).decode(encoding='utf-8') + if data: + cb = common.partial(callback, sock) + cmdlist = data.split() + + if cmdlist[0] not in common.CMD_TYPE: + callback(sock, 'Fail') + continue + + msg = messageObject(cmdlist[1:], cb) + FUNCS[cmdlist[0]].put(msg) + continue + else: + if sock in SOCKET_LIST: + SOCKET_LIST.remove(sock) + except: + raise + continue + common.time.sleep(0.2) + + server_socket.close() + +KERNEL_MODULE = [ +'clounix_sysfs_main', +'i2c_dev', +'i2c-mux', +'i2c-mux-pca9641', +'i2c-mux-pca954x force_deselect_on_exit=1', +'lm75', +'pegatron_fn8656_bnf_cpld loglevel=7 requirement_flag=1', +'pegatron_hwmon_mcu loglevel=7', +'pegatron_fn8656_bnf_psu loglevel=7', +'pegatron_fn8656_bnf_sfp loglevel=7', +'pegatron_fn8656_bnf_watchdog loglevel=7', +'clounix_watchdog'] +#'pegatron_fn8656_bnf_ixgbe'] + +def checkDriver(): + for i in range(0, len(KERNEL_MODULE)): + status, output = common.doBash("lsmod | grep " + KERNEL_MODULE[i]) + if status: + common.doBash("modprobe " + KERNEL_MODULE[i]) + return + +i2c_topology_dict=[ + {'bus': "i2c-0", 'driver' : "pca9641", 'address': "0x71"}, + {'bus': "i2c-1", 'driver' : "fn8656_bnf_cpld", 'address': "0x18"}, + {'bus': "i2c-1", 'driver' : "pca9545", 'address': "0x72"}, + {'bus': "i2c-1", 'driver' : "pca9548", 'address': "0x73"}, + {'bus': "i2c-1", 'driver' : "lm75b", 'address': "0x4a"}, + {'bus': "i2c-2", 'driver' : "fn8656_bnf_psu", 'address': "0x58"}, + {'bus': "i2c-3", 'driver' : "fn8656_bnf_psu", 'address': "0x59"}, + {'bus': "i2c-4", 'driver' : "pega_hwmon_mcu", 'address': "0x70"}, + {'bus': "i2c-6", 'driver' : "fn8656_bnf_cpld", 'address': "0x74"}, + {'bus': "i2c-7", 'driver' : "fn8656_bnf_cpld", 'address': "0x75"}, + {'bus': "i2c-8", 'driver' : "fn8656_bnf_cpld", 'address': "0x76"}, + {'bus': "i2c-9", 'driver' : "24c02", 'address': "0x54"} +] +SOFT_LINK_NODE_TYPE = ['sensor','transceiver','psu','fan','cpld','syseeprom','sysled','watchdog','fpga'] +TRANSCIEVER_PREFIX = '/sys/switch/transceiver/' +PSU_PREFIX = '/sys/switch/psu/' +FAN_PREFIX = '/sys/switch/fan/' +CPLD_PREFIX = '/sys/switch/cpld/' +SYSEEPROM_PREFIX = '/sys/switch/syseeprom/' +SYSLED_PREFIX = '/sys/switch/sysled/' +WATCHDOG_PREFIX = '/sys/switch/watchdog/' +FPGA_PREFIX = '/sys/switch/fpga/' +SENSOR_PREFIX = '/sys/switch/sensor/' + +FPGA_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_fn8656_bnf_sfp/parameters/loglevel', 'dest_node':FPGA_PREFIX+'loglevel'}, + {'src_node':'/sys/module/pegatron_fn8656_bnf_sfp/parameters/fpga_debug', 'dest_node':FPGA_PREFIX+'debug'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/'+'fpga_chip_num', 'dest_node':FPGA_PREFIX+'num'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/'+'fpga_alias', 'dest_node':FPGA_PREFIX+'alias'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/'+'fpga_type', 'dest_node':FPGA_PREFIX+'type'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/'+'fpga_hw_version', 'dest_node':FPGA_PREFIX+'hw_version'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0/'+'fpga_sw_version', 'dest_node':FPGA_PREFIX+'board_version'}, +] +SYSEEPROM_TOP_NODE_DICT = [ + {'src_node':'/sys/module/m24c02/parameters/loglevel', 'dest_node':SYSEEPROM_PREFIX+'loglevel'}, + {'src_node':'/sys/module/m24c02/parameters/debug', 'dest_node':SYSEEPROM_PREFIX+'debug'}, + {'src_node':'/sys/module/m24c02/parameters/bsp_version', 'dest_node':SYSEEPROM_PREFIX+'bsp_version'}, + {'src_node':common.I2C_PREFIX+'9-0054/eeprom', 'dest_node':SYSEEPROM_PREFIX+'eeprom'}, +] +WATCHDOG_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_fn8656_bnf_watchdog/parameters/loglevel', 'dest_node':'/sys/clx/watchdog/'+'loglevel'}, + {'src_node':'/sys/clx/watchdog', 'dest_node':'/sys/switch/watchdog'}, +] +''' +WATCHDOG_TOP_NODE_DICT = [ + {'src_node':'/sys/module/clounix_watchdog/parameters/loglevel', 'dest_node':WATCHDOG_PREFIX+'loglevel'}, + {'src_node':'/sys/module/clounix_watchdog/parameters/watchdog_debug', 'dest_node':WATCHDOG_PREFIX+'debug'}, + {'src_node':'/sys/bus/platform/devices/iTCO_wdt.0.auto/watchdog/watchdog0/identity', 'dest_node':WATCHDOG_PREFIX+'identity'}, + {'src_node':'/sys/bus/platform/devices/iTCO_wdt.0.auto/watchdog/watchdog0/state', 'dest_node':WATCHDOG_PREFIX+'state'}, + {'src_node':'/sys/bus/platform/devices/iTCO_wdt.0.auto/watchdog/watchdog0/timeleft', 'dest_node':WATCHDOG_PREFIX+'timeleft'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1f.0/clounix_ctrl', 'dest_node':WATCHDOG_PREFIX+'enable'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1f.0/clounix_timeout_ctrl', 'dest_node':WATCHDOG_PREFIX+'timeout'}, + {'src_node':'/sys/devices/pci0000:00/0000:00:1f.0/clounix_ping', 'dest_node':WATCHDOG_PREFIX+'reset'}, +] +''' +SYSLED_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_fn8656_bnf_cpld/parameters/loglevel', 'dest_node':SYSLED_PREFIX+'loglevel'}, + {'src_node':common.I2C_PREFIX+'6-0074/debug_sysled', 'dest_node':SYSLED_PREFIX+'debug'}, + {'src_node':common.I2C_PREFIX+'6-0074/sys_led', 'dest_node':SYSLED_PREFIX+'sys_led_status'}, + #not supported{'src_node':common.I2C_PREFIX+'6-0074/', 'dest_node':SYSLED_PREFIX+'bmc_led_status'}, + {'src_node':common.I2C_PREFIX+'6-0074/fan_led', 'dest_node':SYSLED_PREFIX+'fan_led_status'}, + {'src_node':common.I2C_PREFIX+'6-0074/pwr_led', 'dest_node':SYSLED_PREFIX+'psu_led_status'}, + {'src_node':common.I2C_PREFIX+'1-0018/loc_led', 'dest_node':SYSLED_PREFIX+'id_led_status'}, +] + +TRANSCIEVER_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_fn8656_bnf_cpld/parameters/loglevel', 'dest_node':TRANSCIEVER_PREFIX+'loglevel'}, + {'src_node':common.I2C_PREFIX+'6-0074/debug_sfp', 'dest_node':TRANSCIEVER_PREFIX+'debug'}, + {'src_node':common.I2C_PREFIX+'7-0075/sfp_port_num', 'dest_node':TRANSCIEVER_PREFIX+'num'}, + {'src_node':common.I2C_PREFIX+'7-0075/sfp_all_present', 'dest_node':TRANSCIEVER_PREFIX+'present'}, + {'src_node':common.I2C_PREFIX+'7-0075/sfp_all_power_on', 'dest_node':TRANSCIEVER_PREFIX+'power_on'}, +] +TRANSCIEVER_PORT_NODE_DICT = [ + {'src_node' : '/sys/devices/pci0000:00/0000:00:1c.4/0000:0a:00.0{}'+'sfp{}_eeprom', 'dest_node' : TRANSCIEVER_PREFIX+'eth{}/eeprom'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/sfp{}_present', 'dest_node' : TRANSCIEVER_PREFIX+'eth{}/present'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/sfp{}_reset', 'dest_node' : TRANSCIEVER_PREFIX+'eth{}/reset'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/sfp{}_lowpower', 'dest_node' : TRANSCIEVER_PREFIX+'eth{}/lpmode'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/sfp{}_irq_status', 'dest_node' : TRANSCIEVER_PREFIX+'eth{}/interrupt'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/sfp{}_power_on', 'dest_node' : TRANSCIEVER_PREFIX+'eth{}/power_on'}, +] + +FAN_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_hwmon_mcu/parameters/loglevel', 'dest_node':FAN_PREFIX+'loglevel'}, + {'src_node':'/sys/module/pegatron_hwmon_mcu/parameters/debug', 'dest_node':FAN_PREFIX+'debug'}, + {'src_node':common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan_num', 'dest_node':FAN_PREFIX+'num'} +] +FAN_ATTR_NODE_DICT = [ + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_model_name', 'dest_node' : FAN_PREFIX+'fan{}/model_name'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_serial_num', 'dest_node' : FAN_PREFIX+'fan{}/serial_number'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_vendor', 'dest_node' : FAN_PREFIX+'fan{}/vendor'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_part_num', 'dest_node' : FAN_PREFIX+'fan{}/part_number'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_hard_version', 'dest_node' : FAN_PREFIX+'fan{}/hardware_version'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_motor_num', 'dest_node' : FAN_PREFIX+'fan{}/num_motors'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_present', 'dest_node' : FAN_PREFIX+'fan{}/status'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_led_status', 'dest_node' : FAN_PREFIX+'fan{}/led_status'} +] +FAN_MOTOR_NODE_DICT = [ + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_inner_rpm', 'dest_node' : FAN_PREFIX+'fan{}/motor{}/speed'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_speed_tolerance', 'dest_node' : FAN_PREFIX+'fan{}/motor{}/speed_tolerance'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_speed_target', 'dest_node' : FAN_PREFIX+'fan{}/motor{}/speed_target'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan_pwm', 'dest_node' : FAN_PREFIX+'fan{}/motor{}/ratio'}, + {'src_node' : common.I2C_PREFIX+'4-0070/hwmon/hwmon4/fan{}_airflow_dir', 'dest_node' : FAN_PREFIX+'fan{}/motor{}/direction'} +] + +PSU_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_hwmon_mcu/parameters/loglevel', 'dest_node':PSU_PREFIX+'loglevel'}, + {'src_node':'/sys/module/pegatron_hwmon_mcu/parameters/debug', 'dest_node':PSU_PREFIX+'debug'}, + {'src_node':common.I2C_PREFIX+'2-0058/hwmon/hwmon2/psu_num', 'dest_node':PSU_PREFIX+'num'} +] +PSU_ATTR_NODE_DICT = [ + {'src_node' : common.I2C_PREFIX+'{}/manuafacture_model', 'dest_node' : PSU_PREFIX+'psu{}/model_name'}, + {'src_node' : common.I2C_PREFIX+'{}/manuafacture_serial', 'dest_node' : PSU_PREFIX+'psu{}/serial_number'}, + {'src_node' : common.I2C_PREFIX+'{}/manuafacture_id', 'dest_node' : PSU_PREFIX+'psu{}/vendor'}, + {'src_node' : common.I2C_PREFIX+'{}/manuafacture_date', 'dest_node' : PSU_PREFIX+'psu{}/date'}, + {'src_node' : common.I2C_PREFIX+'{}/manuafacture_revision', 'dest_node' : PSU_PREFIX+'psu{}/hardware_version'}, + {'src_node' : common.I2C_PREFIX+'{}/psu_alarm', 'dest_node' : PSU_PREFIX+'psu{}/alarm'}, + {'src_node' : common.I2C_PREFIX+'{}/curr_in_max', 'dest_node' : PSU_PREFIX+'psu{}/alarm_threshold_curr'}, + {'src_node' : common.I2C_PREFIX+'{}/vol_in_max', 'dest_node' : PSU_PREFIX+'psu{}/alarm_threshold_vol'}, + {'src_node' : common.I2C_PREFIX+'{}/manuafacture_part_num', 'dest_node' : PSU_PREFIX+'psu{}/part_number'}, + {'src_node' : common.I2C_PREFIX+'{}/power_out_max', 'dest_node' : PSU_PREFIX+'psu{}/max_output_power'}, + {'src_node' : common.I2C_PREFIX+'{}/curr_in', 'dest_node' : PSU_PREFIX+'psu{}/in_curr'}, + {'src_node' : common.I2C_PREFIX+'{}/vol_in', 'dest_node' : PSU_PREFIX+'psu{}/in_vol'}, + {'src_node' : common.I2C_PREFIX+'{}/power_in', 'dest_node' : PSU_PREFIX+'psu{}/in_power'}, + {'src_node' : common.I2C_PREFIX+'{}/curr_out', 'dest_node' : PSU_PREFIX+'psu{}/out_curr'}, + {'src_node' : common.I2C_PREFIX+'{}/vol_out', 'dest_node' : PSU_PREFIX+'psu{}/out_vol'}, + {'src_node' : common.I2C_PREFIX+'{}/power_out', 'dest_node' : PSU_PREFIX+'psu{}/out_power'}, + {'src_node' : common.I2C_PREFIX+'{}/psu_{}_status', 'dest_node' : PSU_PREFIX+'psu{}/status'}, + {'src_node' : common.I2C_PREFIX+'{}/psu_led_status', 'dest_node' : PSU_PREFIX+'psu{}/led_status'}, + {'src_node' : common.I2C_PREFIX+'{}/psu_type', 'dest_node' : PSU_PREFIX+'psu{}/type'}, + {'src_node' : common.I2C_PREFIX+'{}/sensor_num', 'dest_node' : PSU_PREFIX+'psu{}/num_temp_sensors'}, + {'src_node' : common.I2C_PREFIX+'{}/fan1_speed', 'dest_node' : PSU_PREFIX+'psu{}/fan_speed'}, + {'src_node' : common.I2C_PREFIX+'{}/vol_out_max', 'dest_node' : PSU_PREFIX+'psu{}/max_output_vol'}, + {'src_node' : common.I2C_PREFIX+'{}/vol_out_min', 'dest_node' : PSU_PREFIX+'psu{}/min_output_vol'} +] + +SENSOR_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_hwmon_mcu/parameters/loglevel', 'dest_node':SENSOR_PREFIX+'loglevel'}, + {'src_node':'/sys/module/pegatron_hwmon_mcu/parameters/debug', 'dest_node':SENSOR_PREFIX+'debug'}, +] +PSU_SENSOR_NODE_DICT = [ + {'src_node' : common.I2C_PREFIX+'{}/temp{}_label', 'dest_node' : PSU_PREFIX+'psu{}/temp{}/temp_alias'}, + {'src_node' : common.I2C_PREFIX+'{}/psu_sensor_type', 'dest_node' : PSU_PREFIX+'psu{}/temp{}/temp_type'}, + {'src_node' : common.I2C_PREFIX+'{}/temp{}_max', 'dest_node' : PSU_PREFIX+'psu{}/temp{}/temp_max_hyst'}, + {'src_node' : common.I2C_PREFIX+'{}/temp{}_min', 'dest_node' : PSU_PREFIX+'psu{}/temp{}/temp_min'}, + {'src_node' : common.I2C_PREFIX+'{}/temp{}_crit', 'dest_node' : PSU_PREFIX+'psu{}/temp{}/temp_max'}, + {'src_node' : common.I2C_PREFIX+'{}/temp{}_input', 'dest_node' : PSU_PREFIX+'psu{}/temp{}/temp_input'}, +] + +CPLD_TOP_NODE_DICT = [ + {'src_node':'/sys/module/pegatron_fn8656_bnf_cpld/parameters/loglevel', 'dest_node':CPLD_PREFIX+'loglevel'}, + {'src_node':common.I2C_PREFIX+'6-0074/debug_cpld', 'dest_node':CPLD_PREFIX+'debug'}, + {'src_node':common.I2C_PREFIX+'6-0074/cpld_num', 'dest_node':CPLD_PREFIX+'num'}, + #not supported{'src_node':common.I2C_PREFIX+'', 'dest_node':CPLD_PREFIX+'reboot_cause'}, +] +CPLD_DETAIL_NODE_DICT = [ + {'src_node' : common.I2C_PREFIX+'{}'+'/cpld_alias', 'dest_node' : CPLD_PREFIX+'cpld{}/alias'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/cpld_type', 'dest_node' : CPLD_PREFIX+'cpld{}/type'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/cpld_hw_version', 'dest_node' : CPLD_PREFIX+'cpld{}/hw_version'}, + {'src_node' : common.I2C_PREFIX+'{}'+'/cpld_board_version', 'dest_node' : CPLD_PREFIX+'cpld{}/board_version'} +] +def linkDeviceNode(node_type): + + if node_type == 'sensor': + num = str(device.THERMAL_SENSOR_NUM) + cmd = device.SYSSENSOR_PREFIX + "num_temp_sensors " + num + common.doBash("echo add " + cmd + " > /sys/switch/clounix_cmd") + for node in SENSOR_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + for sensor_index in range(device.THERMAL_SENSOR_NUM): + thermal_info = device.THERMAL_COMBINATION[sensor_index] + for work_index in range(device.NEED_WORK): + src_path = thermal_info[device.PATH_INDEX] + thermal_info[work_index] + dst_path = device.SENSOR_PATH.format(sensor_index) + dst_path = dst_path + device.THERMAL_NODE_COMBINATION[work_index] + if work_index < 3 : + common.doBash("echo " + src_path + " " + dst_path + " > /sys/switch/clounix_cmd") + else : + common.doBash("echo " + "add " + dst_path + " " + thermal_info[work_index] + " > /sys/switch/clounix_cmd") + + elif node_type == 'transceiver': + #transceiver top level + for node in TRANSCIEVER_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + #transceiver port node + for port_num in range(device.SFP_MAX_NUM + 1, device.TOTAL_PORT_NUM + 1): + for node in TRANSCIEVER_PORT_NODE_DICT: + if port_num < device.CPLDB_SFP_NUM + 1: + if node['dest_node'].format(port_num).split('/')[-1] == 'eeprom': + bus = '/' + else: + bus = '7-0075' + else: + if node['dest_node'].format(port_num).split('/')[-1] == 'eeprom': + bus = '/' + else: + bus = '8-0076' + #check whether the link exists + if not os.path.exists(node['dest_node'].format(port_num)) : + common.doBash("echo "+node['src_node'].format(bus,port_num)+' '+node['dest_node'].format(port_num)+" > /sys/switch/clounix_cmd") + elif node_type == 'fan': + for node in FAN_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + for fan_num in range(1, device.FAN_NUM + 1): + for node in FAN_ATTR_NODE_DICT: + if not os.path.exists(node['dest_node'].format(fan_num)) : + common.doBash("echo "+node['src_node'].format(fan_num)+' '+node['dest_node'].format(fan_num)+" > /sys/switch/clounix_cmd") + #fan motor level + for motor_num in range(0, device.MOTOR_NUM_PER_FAN): + for motor_node in FAN_MOTOR_NODE_DICT: + if not os.path.exists(motor_node['dest_node'].format(fan_num,motor_num)) : + common.doBash("echo "+motor_node['src_node'].format(fan_num)+' '+motor_node['dest_node'].format(fan_num,motor_num)+" > /sys/switch/clounix_cmd") + elif node_type == 'cpld': + for node in CPLD_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + cpld_bus = ['1-0018','6-0074','7-0075','8-0076'] + for cpld_num in range(1, device.CPLD_NUM + 1): + for node in CPLD_DETAIL_NODE_DICT: + #check whether the link exists + if not os.path.exists(node['dest_node'].format(cpld_num)) : + common.doBash("echo "+node['src_node'].format(cpld_bus[cpld_num-1])+' '+node['dest_node'].format(cpld_num)+" > /sys/switch/clounix_cmd") + elif node_type == 'psu': + for node in PSU_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + for psu_num in range(1, device.PSU_NUM + 1): + for node in PSU_ATTR_NODE_DICT: + if not os.path.exists(node['dest_node'].format(psu_num)) : + if node['dest_node'].format(psu_num).split('/')[-1] == 'status' : + bus = '6-0074' + common.doBash("echo "+node['src_node'].format(bus,psu_num)+' '+node['dest_node'].format(psu_num)+" > /sys/switch/clounix_cmd") + continue + if psu_num == 1: + bus = '2-0058/hwmon/hwmon2' + elif psu_num == 2: + bus = '3-0059/hwmon/hwmon3' + common.doBash("echo "+node['src_node'].format(bus)+' '+node['dest_node'].format(psu_num)+" > /sys/switch/clounix_cmd") + + #psu temp sensor level + for temp_sensor_num in range(0, device.TEMP_SENSOR_NUM_PER_PSU): + for temp_sensor_node in PSU_SENSOR_NODE_DICT: + if not os.path.exists(temp_sensor_node['dest_node'].format(psu_num,temp_sensor_num)) : + common.doBash("echo "+temp_sensor_node['src_node'].format(bus,temp_sensor_num+1)+' '+temp_sensor_node['dest_node'].format(psu_num,temp_sensor_num)+" > /sys/switch/clounix_cmd") + + elif node_type == 'syseeprom': + for node in SYSEEPROM_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + elif node_type == 'fpga': + for node in FPGA_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + fd = os.open(node['src_node'], os.O_RDONLY) + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + os.close(fd) + + elif node_type == 'watchdog': + for node in WATCHDOG_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + elif node_type == 'sysled': + for node in SYSLED_TOP_NODE_DICT: + #check whether the soft link exists + if not os.path.exists(node['dest_node']) : + common.doBash("echo "+node['src_node']+' '+node['dest_node']+" > /sys/switch/clounix_cmd") + + +def deleteLinkDeviceNode(node_type): + if node_type == 'sensor': + cmd = device.SYSSENSOR_PREFIX + "num_temp_sensors" + common.doBash("echo del " + cmd + " > /sys/swtich/clounix_cmd") + for sensor_index in range(device.THERMAL_SENSOR_NUM): + for work_index in range(device.NEED_WORK): + dst_path = device.SENSOR_PATH.format(sensor_index) + dst_path = dst_path + device.THERMAL_NODE_COMBINATION[work_index] + common.doBash("del " + dst_path + " > /sys/switch/clounix_cmd") + + elif node_type == 'transceiver': + #transceiver + for node in TRANSCIEVER_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + for port_num in range(device.SFP_MAX_NUM + 1, device.TOTAL_PORT_NUM + 1): + for node in TRANSCIEVER_PORT_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node'].format(port_num)) : + #del /sys/switch/transceiver/eth*/* + common.doBash("echo del "+node['dest_node'].format(port_num)+" > /sys/switch/clounix_cmd") + #del /sys/switch/transceiver/eth* + common.doBash("echo del /sys/switch/transceiver/eth{}".format(port_num)+" > /sys/switch/clounix_cmd") + elif node_type == 'fan': + #fan + for node in FAN_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + for fan_num in range(1, device.FAN_NUM + 1): + for node in FAN_ATTR_NODE_DICT: + for motor_num in range(0, device.MOTOR_NUM_PER_FAN): + for motor_node in FAN_MOTOR_NODE_DICT: + #del /sys/switch/fan/fan*/motor*/* + if os.path.exists(motor_node['dest_node'].format(fan_num,motor_num)) : + common.doBash("echo del "+motor_node['dest_node'].format(fan_num,motor_num)+" > /sys/switch/clounix_cmd") + #del /sys/switch/fan/fan*/motor* + if os.path.exists("/sys/switch/fan/fan{}/motor{}".format(fan_num,motor_num)) : + common.doBash("echo del /sys/switch/fan/fan{}/motor{}".format(fan_num,motor_num)+" > /sys/switch/clounix_cmd") + #check whether the link exists + if os.path.exists(node['dest_node'].format(fan_num)) : + #del /sys/switch/fan/fan*/* + common.doBash("echo del "+node['dest_node'].format(fan_num)+" > /sys/switch/clounix_cmd") + #del /sys/switch/fan/fan* + common.doBash("echo del /sys/switch/fan/fan{}".format(fan_num)+" > /sys/switch/clounix_cmd") + elif node_type == 'cpld': + #transceiver + for node in CPLD_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + for cpld_num in range(1, device.CPLD_NUM + 1): + for node in CPLD_DETAIL_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node'].format(cpld_num)) : + #del /sys/switch/cpld/cpld*/* + common.doBash("echo del "+node['dest_node'].format(cpld_num)+" > /sys/switch/clounix_cmd") + #del /sys/switch/cpld/cpld* + common.doBash("echo del /sys/switch/cpld/cpld{}".format(cpld_num)+" > /sys/switch/clounix_cmd") + elif node_type == 'psu': + #psu + for node in PSU_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + for psu_num in range(1, device.PSU_NUM + 1): + for node in PSU_ATTR_NODE_DICT: + for temp_sensor_num in range(0, device.MOTOR_NUM_PER_FAN): + for motor_node in PSU_SENSOR_NODE_DICT: + #del /sys/switch/psu/psu*/temp*/* + if os.path.exists(motor_node['dest_node'].format(psu_num,temp_sensor_num)) : + common.doBash("echo del "+motor_node['dest_node'].format(psu_num,temp_sensor_num)+" > /sys/switch/clounix_cmd") + #del /sys/switch/psu/psu*/temp* + if os.path.exists("/sys/switch/psu/psu{}/temp{}".format(psu_num,temp_sensor_num)) : + common.doBash("echo del /sys/switch/psu/psu{}/temp{}".format(psu_num,temp_sensor_num)+" > /sys/switch/clounix_cmd") + #check whether the link exists + if os.path.exists(node['dest_node'].format(psu_num)) : + #del /sys/switch/psu/psu*/* + common.doBash("echo del "+node['dest_node'].format(psu_num)+" > /sys/switch/clounix_cmd") + #del /sys/switch/psu/psu* + common.doBash("echo del /sys/switch/psu/psu{}".format(psu_num)+" > /sys/switch/clounix_cmd") + + elif node_type == 'syseeprom': + for node in SYSEEPROM_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + elif node_type == 'fpga': + for node in FPGA_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + elif node_type == 'watchdog': + for node in WATCHDOG_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + elif node_type == 'sysled': + for node in SYSLED_TOP_NODE_DICT: + #check whether the link exists + if os.path.exists(node['dest_node']) : + common.doBash("echo del "+node['dest_node']+" > /sys/switch/clounix_cmd") + + + +def doInstall(): + common.doBash("depmod -a") + common.doBash("rmmod hid_cp2112") + common.doBash("modprobe -r iTCO_wdt") + checkDriver() + for o in i2c_topology_dict: + common.doBash("echo " + o['driver'] + " " + o['address'] + " > " + common.I2C_PREFIX + o['bus'] + "/new_device") + + for node_type in SOFT_LINK_NODE_TYPE: + linkDeviceNode(node_type) + return + +def setupThreads(): + global THREADS, QUEUES + + # Queues + # Global + queueGlobal = common.Queue.Queue() + QUEUES.append(queueGlobal) + FUNCS['global'] = queueGlobal + + # Device + queueDevice = common.Queue.Queue() + QUEUES.append(queueDevice) + FUNCS['device'] = queueDevice + + # Threads + # Global + threadGlobal = GlobalThread('Global Handler', queueGlobal) + THREADS.append(threadGlobal) + + # Device + threadDevice = device.DeviceThread('Device Handler', queueDevice) + THREADS.append(threadDevice) + + # Check platform status + threadPlatformStatus = device.PlatformStatusThread('Platform Status Handler', 0.3) + THREADS.append(threadPlatformStatus) + +def functionInit(): + setupThreads() + for thread in THREADS: + thread.start() + return + +def deviceInit(): + msg = messageObject(['init'], None) + FUNCS['device'].put(msg) + return + +def do_platformApiInit(): + print("Platform API Init....") + common.doBash("/usr/local/bin/platform_api_mgnt.sh init") + return + +def do_platformApiInstall(): + print("Platform API Install....") + common.doBash("/usr/local/bin/platform_api_mgnt.sh install") + return + +# Platform uninitialize +def doUninstall(): + for node_type in SOFT_LINK_NODE_TYPE: + deleteLinkDeviceNode(node_type) + for i in range(0, len(KERNEL_MODULE))[::-1]: + common.doBash("modprobe -rq " + KERNEL_MODULE[i]) + for o in i2c_topology_dict: + common.doBash("echo " + o['address'] + " > " + common.I2C_PREFIX + o['bus'] + "/delete_device") + return + +def main(): #start 20200219 + args = common.sys.argv[1:] + + if len(args[0:]) < 1: + common.sys.exit(0) + + if args[0] == 'install': + common.RUN = True + doInstall() + do_platformApiInit() + do_platformApiInstall() + #fwupdates.fwupdate() + functionInit() + deviceInit() + messageHandler() + + + common.sys.exit(0) + +if __name__ == "__main__": + main() diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/scripts/platform_update_reboot_cause b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/scripts/platform_update_reboot_cause new file mode 100755 index 000000000000..6d21055bec0d --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/scripts/platform_update_reboot_cause @@ -0,0 +1,24 @@ +#!/bin/bash +rst_mode=$1 +function sys_cold_rst() +{ + #it is done to write CPLD register also + #CPLD-D 0x9 BIT3 0 + echo -e '\xe' | dd of=/dev/port bs=1 seek=3321 +} + +function sys_warm_rst() +{ + echo -e '\x6' | dd of=/dev/port bs=1 seek=3321 +} + + +case "$rst_mode" in +cold) + sys_cold_rst + ;; +warm) + sys_warm_rst + ;; +esac + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/scripts/sensors b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/scripts/sensors new file mode 100755 index 000000000000..a4121f77d7c4 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/scripts/sensors @@ -0,0 +1,5 @@ +#!/bin/bash +docker exec -i pmon sensors "$@" + +#To probe sensors not part of lm-sensors +pegatron_fn8656_bnf_util.py cmd device sensors diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/service/fn8656_bnf-platform-init.service b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/service/fn8656_bnf-platform-init.service new file mode 100644 index 000000000000..c3ae566740f2 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/service/fn8656_bnf-platform-init.service @@ -0,0 +1,13 @@ +[Unit] +Description=Pegastron fn8656-bnf Platform initialization service +Before=network.target +DefaultDependencies=no + +[Service] +Type=simple +ExecStart=/usr/local/bin/pegaProcess/main.py install +ExecStop=/usr/local/bin/pegatron_fn8656_bnf_util.py uninstall +RemainAfterExit=yes + +[Install] +WantedBy=multi-user.target diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/service/platform_api_mgnt.sh b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/service/platform_api_mgnt.sh new file mode 100755 index 000000000000..8baa6b05035b --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/service/platform_api_mgnt.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +PREV_REBOOT_CAUSE="/host/reboot-cause/" +DEVICE="/usr/share/sonic/device" +PLATFORM=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform) +FILES=$DEVICE/$PLATFORM/api_files + +install() { + # Install sonic-platform package + if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl ]; then + pip install $DEVICE/$PLATFORM/sonic_platform-1.0-py2-none-any.whl + fi + if [ -e $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl ]; then + pip3 install $DEVICE/$PLATFORM/sonic_platform-1.0-py3-none-any.whl + fi +} + +init() { + # mount needed files for sonic-platform package + mkdir -p $FILES + + mkdir -p $FILES/reboot-cause + mount -B $PREV_REBOOT_CAUSE $FILES/reboot-cause +} + +deinit() { + # deinit sonic-platform package + umount -f $PREV_REBOOT_CAUSE $FILES/reboot-cause >/dev/null 2>/dev/null +} + +uninstall() { + # Uninstall sonic-platform package + pip uninstall -y sonic-platform >/dev/null 2>/dev/null +} + +case "$1" in +install | uninstall | init | deinit) + $1 + ;; +*) + echo "Usage: $0 {install|uninstall|init|deinit}" + exit 1 + ;; +esac diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/setup.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/setup.py new file mode 100755 index 000000000000..6334310ae18d --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/setup.py @@ -0,0 +1,15 @@ +#!/usr/bin/env python + +import os +#import sys +from setuptools import setup +os.listdir + +setup( + name='sonic_platform', + version='1.0', + description='Module to initialize Pegatron FN8656-BNF platforms', + + packages=['sonic_platform'], +) + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/__init__.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/__init__.py new file mode 100755 index 000000000000..4bfefa0fb636 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/__init__.py @@ -0,0 +1,3 @@ +__all__ = ["platform", "chassis"] +from sonic_platform import * + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/chassis.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/chassis.py new file mode 100755 index 000000000000..b16d363afcd6 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/chassis.py @@ -0,0 +1,508 @@ +#!/usr/bin/env python +# +# Clounix +# Name: chassis.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + import sys + import time + from sonic_platform_base.chassis_base import ChassisBase + from sonic_platform.eeprom import Eeprom + from sonic_platform.fan import Fan + from sonic_platform.fan_drawer import FanDrawer + from sonic_platform.psu import Psu + from sonic_platform.qsfp import QSfp + from sonic_platform.thermal import Thermal + from sonic_platform.component import Component + from sonic_platform.watchdog import Watchdog + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +SFP_STATUS_INSERTED = '1' +SFP_STATUS_REMOVED = '0' + +# FAN status definition, shall be aligned with the definition in get_fan_change_event() of ChassisBase +FAN_STATUS_REMOVED = '0' +FAN_STATUS_INSERTED = '1' + +# PSU status definition, shall be aligned with the definition in get_change_event() of ChassisBase +PSU_STATUS_REMOVED = '0' +PSU_STATUS_INSERTED = '1' + +REBOOT_CAUSE_FILE = "/host/reboot-cause/reboot-cause.txt" +THERMAL_OVERLOAD_POSITION_FILE = "/host/reboot-cause/platform/thermal_overload_position" +ADDITIONAL_FAULT_CAUSE_FILE = "/host/reboot-cause/platform/additional_fault_cause" + +class Chassis(ChassisBase): + _voltage_list = [] + + def __init__(self): + self.__api_helper = APIHelper() + chassis_conf = self.__api_helper.get_attr_conf("chassis") + self.__conf = chassis_conf + + self.__num_of_psus = len(chassis_conf['psus']) + self.__num_of_sfps = len(chassis_conf['sfps']) + self.__num_of_thermals = len(chassis_conf['thermals']) + self.__num_of_components = len(chassis_conf['components']) + self.__num_of_fans = len(chassis_conf['fans']) + self.__num_of_fan_drawers = len(chassis_conf['fan_drawers']) + + self.__start_of_qsfp = 0 + self.__attr_led_path_prefix = '/sys/switch/sysled/' + ChassisBase.__init__(self) + self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU = "Thermal Overload:CPU" + self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC = "Thermal Overload:ASIC" + self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER = "Thermal Overload:Other" + self.REBOOT_CAUSE_WATCHDOG = "Watchdog" + self.REBOOT_CAUSE_COLD_RESET = "CPU Cold Reset" + self.REBOOT_CAUSE_WARM_RESET = "CPU Warm Reset" + self.REBOOT_CAUSE_PSU_SHUTDOWN = "PSU Shutdown" + + # Initialize EEPROM + self._eeprom = Eeprom() + + # Initialize CHASSIS FAN + fan_conf=self.__conf['fans'] + for x in range(0, self.__num_of_fans): + fan_conf[x].update({'container':'chassis'}) + fan_conf[x].update({'container_index': self.__index}) + fan = Fan(x, fan_conf) + self._fan_list.append(fan) + + # Initialize CHASSIS FAN DRWAER + for drawer_index in range(0, self.__num_of_fan_drawers): + fandrawer_conf=chassis_conf['fan_drawers'] + fan_drawer = FanDrawer(drawer_index,fandrawer_conf) + self._fan_drawer_list.append(fan_drawer) + + + # Initialize PSU + for index in range(0, self.__num_of_psus): + psu_conf=chassis_conf['psus'] + psu = Psu(index,psu_conf) + self._psu_list.append(psu) + + # Initialize SFP + for index in range(0, self.__num_of_sfps): + qsfp_conf=chassis_conf['sfps'] + sfp = QSfp(index,qsfp_conf) + self._sfp_list.append(sfp) + + # Initialize CHASSIS THERMAL + thermal_conf=self.__conf['thermals'] + for x in range(0, self.__num_of_thermals): + thermal_conf[x].update({'container':'chassis'}) + thermal_conf[x].update({'container_index':0}) + thermal = Thermal(x,thermal_conf) + self._thermal_list.append(thermal) + + # Initialize COMPONENT + for index in range(0, self.__num_of_components): + component_conf=chassis_conf['components'] + component = Component(index,component_conf) + self._component_list.append(component) + + # Initialize WATCHDOG + watchdog_conf=chassis_conf['watchdog'] + self._watchdog = Watchdog(watchdog_conf) + +############################################## +# Device methods +############################################## + def get_thermal_manager(self): + from .thermal_manager import ThermalManager + return ThermalManager + + def get_name(self): + """ + Retrieves the name of the chassis + Returns: + string: The name of the chassis + """ + return self.__conf['name'] + + def get_presence(self): + """ + Retrieves the presence of the chassis + Returns: + bool: True if chassis is present, False if not + """ + return True + + def get_model(self): + """ + Retrieves the model number (or part number) of the chassis + Returns: + string: Model/part number of chassis + """ + return self._eeprom.part_number_str() + + def get_serial(self): + """ + Retrieves the serial number of the chassis + Returns: + string: Serial number of chassis + """ + return self._eeprom.serial_number_str() + + def get_status(self): + """ + Retrieves the operational status of the chassis + Returns: + bool: A boolean value, True if chassis is operating properly + False if not + """ + return True + +############################################## +# Chassis methods +############################################## + + def get_position_in_parent(self): + """ + Retrieves 1-based relative physical position in parent device. + Returns: + integer: The 1-based relative physical position in parent + device or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + 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 + """ + ret_val = False + if color == "green": + led_value = 1 + elif color == "red": + led_value = 3 + elif color == "blink_green": + led_value = 4 + else: + return False + ret_val = self.__api_helper.write_txt_file(self.__attr_led_path_prefix + 'sys_led_status',led_value) + + return ret_val + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + color = "off" + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_led_path_prefix + 'sys_led_status') + if (attr_rv != None): + if (int(attr_rv, 16) == 0x1) : + color = "green" + elif (int(attr_rv, 16) == 0x4): + color = "blink_green" + elif (int(attr_rv, 16) == 0x0): + color = "off" + else: + color = "red" + + return color + + def get_sfp(self, index): + """ + Retrieves sfp represented by (0-based) index + + Args: + index: An integer, the index (0-based) of the sfp to retrieve. + The index should be the sequence of a physical port in a chassis, + starting from 0. + For example, 0 for Ethernet0, 1 for Ethernet4 and so on. + + Returns: + An object dervied from SfpBase representing the specified sfp + """ + sfp = None + + try: + # The index will start from 0 + sfp = self._sfp_list[index] + except IndexError: + sys.stderr.write("SFP index {} out of range (0-{})\n".format( + index, len(self._sfp_list))) + return sfp + + def get_eeprom(self): + """ + Retreives eeprom device on this chassis + + Returns: + An object derived from WatchdogBase representing the hardware + eeprom device + """ + return self._eeprom + + def get_all_voltages(self): + """ + Retrieves all voltages available on this chassis + + Returns: + A list of objects derived from VoltageBase representing all voltages + available on this chassis + """ + return self._voltage_list + + def get_base_mac(self): + """ + Retrieves the base MAC address for the chassis + + Returns: + A string containing the MAC address in the format + 'XX:XX:XX:XX:XX:XX' + """ + return self._eeprom.base_mac_address() + + def get_serial_number(self): + """ + Retrieves the hardware serial number for the chassis + + Returns: + A string containing the hardware serial number for this chassis. + """ + return self._eeprom.serial_number_str() + + def get_system_eeprom_info(self): + """ + Retrieves the full content of system EEPROM information for the chassis + + Returns: + A dictionary where keys are the type code defined in + OCP ONIE TlvInfo EEPROM format and values are their corresponding + values. + Ex. { '0x21':'AG9064', '0x22':'V1.0', '0x23':'AG9064-0109867821', + '0x24':'001c0f000fcd0a', '0x25':'02/03/2018 16:22:00', + '0x26':'01', '0x27':'REV01', '0x28':'AG9064-C2358-16G'} + """ + return self._eeprom.system_eeprom_info() + + def get_reboot_cause(self): + """ + Retrieves the cause of the previous reboot + Returns: + A tuple (string, string) where the first element is a string + containing the cause of the previous reboot. This string must be + one of the predefined strings in this class. If the first string + is "REBOOT_CAUSE_HARDWARE_OTHER", the second string can be used + to pass a description of the reboot cause. + """ + reboot_cause = self.REBOOT_CAUSE_NON_HARDWARE + thermal_overload_pos = 'None' + addational_fault_cause = 'None' + hw_reboot_cause = 'Unknown' + + #reservered for hardware reboot cause + if hw_reboot_cause != 'Unknown': + reboot_cause = self.REBOOT_CAUSE_HARDWARE_OTHER + + #software reboot cause + sw_reboot_cause = self.__api_helper.read_one_line_file(REBOOT_CAUSE_FILE) or "Unknown" + description = sw_reboot_cause + + #check power down reboot-cause + REBOOT_CAUSE_PWR_DOWN_PATH='/sys/devices/pci0000:00/0000:00:1f.3/i2c-0/i2c-1/i2c-4/4-0070/hwmon/hwmon4/pwr_down' + REBOOT_CAUSE_CPLD_PATH='/sys/devices/pci0000:00/0000:00:1f.3/i2c-0/i2c-1/1-0018/reboot_cause' + reboot_cause_pwr_down = 0 + reboot_cause_cpld = 0 + if os.path.isfile(REBOOT_CAUSE_PWR_DOWN_PATH): + attr_rv = self.__api_helper.read_one_line_file(REBOOT_CAUSE_PWR_DOWN_PATH) + reboot_cause_pwr_down = int(attr_rv, 16) + + #check watchdog/cold reboot + if os.path.isfile(REBOOT_CAUSE_CPLD_PATH): + attr_rv = self.__api_helper.read_one_line_file(REBOOT_CAUSE_CPLD_PATH) + reboot_cause_cpld = int(attr_rv, 16) + + #thermal policy reboot cause + if os.path.isfile(THERMAL_OVERLOAD_POSITION_FILE): + thermal_overload_pos = self.__api_helper.read_one_line_file(THERMAL_OVERLOAD_POSITION_FILE) + + if os.path.isfile(ADDITIONAL_FAULT_CAUSE_FILE): + addational_fault_cause = self.__api_helper.read_one_line_file(ADDITIONAL_FAULT_CAUSE_FILE) + + if (reboot_cause_pwr_down & 0x1): + reboot_cause = self.REBOOT_CAUSE_PSU_SHUTDOWN + elif (reboot_cause_cpld & 0x2): + reboot_cause = self.REBOOT_CAUSE_WATCHDOG + elif (reboot_cause_cpld & 0x4): + reboot_cause = self.REBOOT_CAUSE_COLD_RESET + elif (reboot_cause_cpld & 0x8): + reboot_cause = self.REBOOT_CAUSE_WARM_RESET + elif "CPU" in thermal_overload_pos: + reboot_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_CPU + description = thermal_overload_pos + os.remove(THERMAL_OVERLOAD_POSITION_FILE) + elif "NPU" in thermal_overload_pos: + reboot_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_ASIC + description = thermal_overload_pos + os.remove(THERMAL_OVERLOAD_POSITION_FILE) + elif thermal_overload_pos is not 'None': + reboot_cause = self.REBOOT_CAUSE_THERMAL_OVERLOAD_OTHER + description = thermal_overload_pos + os.remove(THERMAL_OVERLOAD_POSITION_FILE) + + if addational_fault_cause is not 'None': + description = ' '.join([description, addational_fault_cause]) + os.remove(ADDITIONAL_FAULT_CAUSE_FILE) + + prev_reboot_cause = (reboot_cause, description) + return prev_reboot_cause + + + + @property + def _get_presence_bitmap(self): + return self._sfp_list[1].get_all_presence() + + @property + def _get_fan_status_bit_map(self): + bit_map = 0 + for index in range(0,self.get_num_fan_drawers()): + bit_map |= int(self.get_fan_drawer(index).get_fan(0).get_presence()) << index + return bit_map + @property + def _get_psu_status_bit_map(self): + bit_map = 0 + for index in range(0,self.get_num_psus()): + bit_map |= int(self.get_psu(index).get_presence()) << index + return bit_map + + + data = {'sfp_present':0,'fan_status':0,'psu_status':0} + def get_transceiver_change_event(self, timeout=1000): + port_dict = {} + + if timeout == 0: + cd_ms = sys.maxsize + else: + cd_ms = timeout + + #poll per second + while cd_ms > 0: + reg_value = self._get_presence_bitmap + changed_ports = self.data['present'] ^ reg_value + if changed_ports != 0: + break + time.sleep(1) + cd_ms = cd_ms - 1000 + + if changed_ports != 0: + for port in range(0, self.__num_of_sfps): + # Mask off the bit corresponding to our port + mask = (1 << (port - 0)) + if changed_ports & mask: + if (reg_value & mask) == 0: + port_dict[port] = SFP_STATUS_REMOVED + else: + port_dict[port] = SFP_STATUS_INSERTED + + # Update cache + self.data['present'] = reg_value + return True, port_dict + else: + return True, {} + + def get_fan_change_event(self, timeout=1000): + fan_dict = {} + + if timeout == 0: + cd_ms = sys.maxsize + else: + cd_ms = timeout + + #poll per second + while cd_ms > 0: + reg_value = self._get_fan_status_bit_map + changed_fans = self.data['fan_status'] ^ reg_value + if changed_fans != 0: + break + time.sleep(1) + cd_ms = cd_ms - 1000 + + if changed_fans != 0: + for fan in range(0,self.get_num_fan_drawers()): + # Mask off the bit corresponding to our fan + mask = (1 << (fan - 0)) + if changed_fans & mask: + if (reg_value & mask) == 0: + fan_dict[fan] = PSU_STATUS_REMOVED + else: + fan_dict[fan] = PSU_STATUS_INSERTED + # Update cache + self.data['fan_status'] = reg_value + return {True: fan_dict} + else: + return {False: {}} + + def get_psu_change_event(self, timeout=1000): + psu_dict = {} + + if timeout == 0: + cd_ms = sys.maxsize + else: + cd_ms = timeout + + #poll per second + while cd_ms > 0: + reg_value = self._get_psu_status_bit_map + changed_psus = self.data['psu_status'] ^ reg_value + if changed_psus != 0: + break + time.sleep(1) + cd_ms = cd_ms - 1000 + + if changed_psus != 0: + for psu in range(0, self.get_num_psus()): + # Mask off the bit corresponding to our psu + mask = (1 << (psu - 0)) + if changed_psus & mask: + if (reg_value & mask) == 0: + psu_dict[psu] = FAN_STATUS_REMOVED + else: + psu_dict[psu] = FAN_STATUS_INSERTED + # Update cache + self.data['psu_status'] = reg_value + return {True: psu_dict} + else: + return {False:{}} + + def get_change_event(self, timeout=0): + res_dict = { + 'component': {}, + 'fan': {}, + 'module': {}, + 'psu': {}, + 'sfp': {}, + 'thermal': {}, + } + ''' get transceiver change event ''' + res_dict['sfp'].clear() + status, res_dict['sfp'] = self.get_transceiver_change_event(timeout) + return status, res_dict diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/component.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/component.py new file mode 100755 index 000000000000..5ed5de881cf5 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/component.py @@ -0,0 +1,272 @@ +#!/usr/bin/env python + +######################################################################## +# Clounix +# +# Module contains an implementation of SONiC Platform Base API and +# provides the Components' (e.g., BIOS, CPLD, FPGA, etc.) available in +# the platform +# +######################################################################## + +try: + import os + import re + from sonic_platform_base.component_base import ComponentBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +BIOS_QUERY_VERSION_COMMAND = "dmidecode -s bios-version" + + +class Component(ComponentBase): + """Clounix Platform-specific Component class""" + def __init__(self, component_index,component_conf): + self.__index = component_index + self.__conf = component_conf + self.__api_helper = APIHelper() + + def get_name(self): + """ + Retrieves the name of the component + + Returns: + A string containing the name of the component + """ + return self.__conf[self.__index]['name'] + + def get_description(self): + """ + Retrieves the description of the component + + Returns: + A string containing the description of the component + """ + return self.__conf[self.__index]['description'] + + def get_version_path(self): + """ + Retrieves the version path of the component + + Returns: + A string containing the version path of the component + """ + return self.__conf[self.__index]['firmware_version_path'] + + def get_hw_version_path(self): + """ + Retrieves the version path of the component + + Returns: + A string containing the version path of the component + """ + return self.__conf[self.__index]['hw_version_path'] + """ + def get_hw_version(self): + hw_version = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.get_hw_version_path()) + if attr_rv != None: + hw_version = attr_rv + else: + if self.get_name() == 'BIOS': + ret,bios_ver = self.__api_helper.run_command(BIOS_QUERY_VERSION_COMMAND) + if ret: + if bios_ver: + hw_version = re.findall('\d',bios_ver)[0] + return hw_version + """ + + + def get_firmware_version(self): + """ + Retrieves the firmware version of the component + + Returns: + A string containing the firmware version of the component + """ + firmware_version = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.get_version_path()) + if attr_rv != None: + firmware_version = attr_rv + else: + if self.get_name() == 'BIOS': + ret,bios_ver = self.__api_helper.run_command(BIOS_QUERY_VERSION_COMMAND) + if ret: + if bios_ver: + firmware_version = bios_ver + return firmware_version + + def get_hw_version(self): + return self.get_firmware_version() + + def check_file_validity(self, image_path): + """ + Check installation file validation + + Returns: + bool: True if installation file is valid, False if not + """ + + if not os.path.isfile(image_path): + print("ERROR: File {} doesn't exist or is not a file".format(image_path)) + return False + file_ext_dist = {'MCU-MB':'.efm8', 'MCU-FB':'.efm8', 'CPLD-A':'.vme', 'CPLD-B':'.vme','CPLD-C':'.vme','CPLD-D':'.vme','FPGA':'.bin', 'BIOS':'.bin'} + name_list = os.path.splitext(image_path) + image_ext_name = file_ext_dist[self.get_name()] + if image_ext_name is not None: + if name_list[1] != image_ext_name: + print("ERROR: Extend name of file {} is wrong. Image for {} should have extend name {}".format(image_path, self.get_name(), image_ext_name)) + return False + file_name_dist = {'MCU-MB':'mcu_mb', 'MCU-FB':'mcu_fb', 'CPLD-A':'cpld_mb', 'CPLD-B':'cpld_mb','CPLD-C':'cpld_mb','CPLD-D':'cpld_cpu', 'FPGA':'fpga_mb', 'BIOS':'bios_cpu'} + image_key_name = file_name_dist[self.get_name()] + if image_key_name is not None: + if not image_key_name in image_path: + print("ERROR: File name of file {} is wrong. Image for {} should have key name {}".format(image_path, self.get_name(), image_key_name)) + return False + + return True + + def version_calc_value(self, version): + """ + transfer version string to value, eg 1.2.3.4 tranfer to 1 * 100 + 2 *1 + 3 * 0.01 + 4 * 0.0001 + + Returns: + version value + """ + version_split = version.split('.') + sum = 0 + factor=100 + for val in version_split: + sum += float(val) * factor + factor = factor * 0.01 + return sum + + def check_version_validity(self, image_path): + """ + Check installation version validation + + Returns: + bool: True if installation version is valid, False if not + """ + + run_version = self.get_firmware_version() + + install_version = re.findall(r'v(.+?)\.', image_path) + if install_version: + version = ''.join(install_version).replace('_', '.') + else: + print("please make sure installation version is from released version like as _V0_10.xxx") + return False + + version_val = self.version_calc_value(version) + run_version_val = self.version_calc_value(run_version) + if version_val == run_version_val: + print("skip installation version %.2f for runing version %.2f." % (version_val, run_version_val)) + return False + + return True + + def check_image_validity(self, image_path): + """ + Check installation image validation + + Returns: + bool: True if installation is valid, False if not + """ + + if not self.check_file_validity(image_path): + return False + + if not self.check_version_validity(image_path): + return False + + return True + + def install_firmware(self, image_path): + """ + Installs firmware to the component + + Args: + image_path: A string, path to firmware image + + Returns: + A boolean, True if install was successful, False if not + """ + if not self.check_image_validity(image_path): + return False + + if self.get_name() == 'BIOS': + cmd = "/usr/local/bin/install_firmware.sh bios "+ image_path + elif self.get_name() == 'MCU-MB': + cmd = "/usr/local/bin/install_firmware.sh mcu-mb "+ image_path + elif self.get_name() == 'MCU-FB': + cmd = "/usr/local/bin/install_firmware.sh mcu-fb "+ image_path + elif self.get_name() == 'CPLD-A' or self.get_name() == 'CPLD-B' or self.get_name() == 'CPLD-C': + cmd = "/usr/local/bin/install_firmware.sh cpld-mb "+ image_path + elif self.get_name() == 'CPLD-D': + cmd = "/usr/local/bin/install_firmware.sh cpld-cpu "+ image_path + elif self.get_name() == 'FPGA': + cmd = "/usr/local/bin/install_firmware.sh fpga "+ image_path + else: + print(self.get_name() + 'frimware upgrade did not implement') + + os.system(cmd) + #start service + os.system("/usr/local/bin/install_firmware_ext.sh start") + return True + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device 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 + """ + model = 'N/A' + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = 'N/A' + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self.get_presence() + + 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 or -1 if cannot determine the position + """ + return -1 + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return False diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/eeprom.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/eeprom.py new file mode 100755 index 000000000000..f7f744b02974 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/eeprom.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# +# Name: eeprom.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_eeprom import eeprom_tlvinfo + import binascii +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Eeprom(eeprom_tlvinfo.TlvInfoDecoder): + + def __init__(self): + self.__eeprom_path = "/sys/class/i2c-adapter/i2c-9/9-0054/eeprom" + super(Eeprom, self).__init__(self.__eeprom_path, 0, '', True) + self.__eeprom_tlv_dict = dict() + try: + self.__eeprom_data = self.read_eeprom() + except: + self.__eeprom_data = "N/A" + raise RuntimeError("Eeprom is not Programmed") + else: + eeprom = self.__eeprom_data + + if not self.is_valid_tlvinfo_header(eeprom): + return + + total_length = ((eeprom[9]) << 8) | (eeprom[10]) + tlv_index = self._TLV_INFO_HDR_LEN + tlv_end = self._TLV_INFO_HDR_LEN + total_length + + while (tlv_index + 2) < len(eeprom) and tlv_index < tlv_end: + if not self.is_valid_tlv(eeprom[tlv_index:]): + break + + tlv = eeprom[tlv_index:tlv_index + 2 + + (eeprom[tlv_index + 1])] + code = "0x%02X" % ((tlv[0])) + + if (tlv[0]) == self._TLV_CODE_VENDOR_EXT: + value = str(((tlv[2]) << 24) | ((tlv[3]) << 16) | + ((tlv[4]) << 8) | (tlv[5])) + value += str(tlv[6:6 + (tlv[1])]) + else: + name, value = self.decoder(None, tlv) + + self.__eeprom_tlv_dict[code] = value + if (eeprom[tlv_index]) == self._TLV_CODE_CRC_32: + break + + tlv_index += (eeprom[tlv_index+1]) + 2 + + def serial_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERIAL_NUMBER) + if not is_valid: + return "N/A" + return results[2] + + def base_mac_address(self): + (is_valid, t) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_MAC_BASE) + if not is_valid or t[1] != 6: + return super(eeprom_tlvinfo.TlvInfoDecoder, self).switchaddrstr(self.__eeprom_data) + + return ":".join([binascii.b2a_hex(T) for T in t[2]]) + + def modelstr(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PRODUCT_NAME) + if not is_valid: + return "N/A" + + return results[2] + + def part_number_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_PART_NUMBER) + if not is_valid: + return "N/A" + + return results[2] + + def serial_tag_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_SERVICE_TAG) + if not is_valid: + return "N/A" + + return results[2] + + def revision_str(self): + (is_valid, results) = self.get_tlv_field( + self.__eeprom_data, self._TLV_CODE_DEVICE_VERSION) + if not is_valid: + return "N/A" + + return results[2] + + def system_eeprom_info(self): + """ + Returns a dictionary, where keys are the type code defined in + ONIE EEPROM format and values are their corresponding values + found in the system EEPROM. + """ + return self.__eeprom_tlv_dict + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/fan.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/fan.py new file mode 100755 index 000000000000..71a4cc638a5e --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/fan.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python +# +# Name: fan.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + from sonic_platform_base.fan_base import FanBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Fan(FanBase): + + def __init__(self, index,fan_conf): + self.__index = index + self.__conf = fan_conf + self.__api_helper = APIHelper() + self.__attr_path_prefix = '' + self.__is_psu_fan = False + FanBase.__init__(self) + + if fan_conf[self.__index]['container'] == 'psu': + self.__attr_path_prefix = '/sys/switch/psu/psu{}/'.format(fan_conf[self.__index]['container_index'] + 1) + self.__is_psu_fan = True + elif fan_conf[self.__index]['container'] == 'fan_drawer': + self.__attr_path_prefix = '/sys/switch/fan/fan{}/'.format(self.__index+1) + else: + #chassis fan to be done + self.__attr_path_prefix = '/sys/switch/fan/fan{}/'.format(self.__index+1) + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'status') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if (attr_rv): + presence = True + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'model_name') + if (attr_rv != None): + model = attr_rv + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'serial_number') + if (attr_rv != None): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'status') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if (attr_rv == 0x1): + status = True + return status + + 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 or -1 if cannot determine the position + """ + return self.__index + 1 + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_vendor(self): + vendor = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'vendor') + if (attr_rv != None): + vendor = attr_rv + return vendor + + def get_part_number(self): + part_num = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'part_number') + if (attr_rv != None): + part_num = attr_rv + return part_num + + def get_hw_version(self): + hw_version = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'hardware_version') + if (attr_rv != None): + hw_version = attr_rv + return hw_version + +############################################## +# FAN methods +############################################## + + def get_direction(self): + """ + Retrieves the direction of fan + + Returns: + A string, either FAN_DIRECTION_INTAKE or FAN_DIRECTION_EXHAUST + depending on fan direction + """ + direction = self.FAN_DIRECTION_EXHAUST + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'direction') + if (attr_rv != None): + attr_rv = int(attr_rv) + if attr_rv == 0: + direction = self.FAN_DIRECTION_EXHAUST + else: + direction = self.FAN_DIRECTION_INTAKE + + 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 : + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'fan_speed') + else: + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'motor0/speed') + + if (attr_rv != None): + attr_rv = int(attr_rv) + if (attr_rv >= 0): + speed = attr_rv + + return speed + + def get_ratio(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) + """ + ratio = 0 + if self.__is_psu_fan : + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'fan_speed') + else: + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'motor0/ratio') + + if (attr_rv != None): + attr_rv = int(attr_rv) + if (attr_rv >= 0): + ratio = attr_rv + + return ratio + + def get_target_speed(self): + """ + Retrieves the target (expected) speed of the fan + + Returns: + An integer, the percentage of full fan speed, in the range 0 (off) + to 100 (full speed) + """ + return self.get_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 + """ + return 100 + + 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 + """ + raise NotImplementedError + + 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 + """ + ret_val = False + if color == self.STATUS_LED_COLOR_GREEN: + led_value = 1 + elif color == self.STATUS_LED_COLOR_RED: + led_value = 3 + else: + return False + ret_val = self.__api_helper.write_txt_file(self.__attr_path_prefix + 'led_status',led_value) + + return ret_val + + def get_status_led(self): + """ + Gets the state of the fan status LED + + Returns: + A string, one of the predefined STATUS_LED_COLOR_* strings above + """ + color = self.STATUS_LED_COLOR_OFF + if self.get_presence() is False : + return color + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'led_status') + if (attr_rv != None): + if (int(attr_rv, 16) == 0x1 or int(attr_rv, 16) == 0x4) : + color = self.STATUS_LED_COLOR_GREEN + elif (int(attr_rv, 16) == 0x3 or int(attr_rv, 16) == 0x6) : + color = self.STATUS_LED_COLOR_RED + + if self.__is_psu_fan : + if self.get_status() is False: + color = self.STATUS_LED_COLOR_RED + + return color + + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/fan_drawer.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/fan_drawer.py new file mode 100644 index 000000000000..c6c711941511 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/fan_drawer.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python + +############################################################################# +# Clounix +# +# Module contains an implementation of SONiC Platform Base API and +# provides the fan status which are available in the platform +# +############################################################################# + +try: + from sonic_platform_base.fan_drawer_base import FanDrawerBase + from sonic_platform.fan import Fan +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class FanDrawer(FanDrawerBase): + + def __init__(self, index,fandrawer_conf): + self.__conf = fandrawer_conf + self.__num_of_fans = len(self.__conf[index]['fans']) + self.__index = index + self._fan_list = [] + FanDrawerBase.__init__(self) + + # Initialize FAN_DRAWER FAN + fan_conf=self.__conf[self.__index]['fans'] + for x in range(0, self.__num_of_fans): + fan_conf[x].update({'container':'fan_drawer'}) + fan_conf[x].update({'container_index': self.__index}) + fan = Fan(x, fan_conf) + self._fan_list.append(fan) + + 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 + """ + return self._fan_list[0].set_status_led(color) + + 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 + """ + return self._fan_list[0].get_status_led() + + def get_name(self): + """ + Retrieves the name of the device + Returns: + string: The name of the device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the FAN + Returns: + bool: True if FAN is present, False if not + """ + return self._fan_list[0].get_presence() + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return self._fan_list[0].get_model() + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return self._fan_list[0].get_serial() + + def get_status(self): + """ + Retrieves the operational status of the device + Returns: + A boolean value, True if device is operating properly, False if not + """ + return self._fan_list[0].get_status() + + 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 or -1 if cannot determine the position + """ + return self.__index + 1 + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_vendor(self): + return self._fan_list[0].get_vendor() + + + def get_part_number(self): + return self._fan_list[0].get_part_number() + + def get_hw_version(self): + return self._fan_list[0].get_hw_version() diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/helper.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/helper.py new file mode 100644 index 000000000000..eed5d5482954 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/helper.py @@ -0,0 +1,156 @@ +import os +import struct +import subprocess +import json +from mmap import * + +from sonic_py_common import device_info + +HOST_CHK_CMD = "docker > /dev/null 2>&1" +EMPTY_STRING = "" + +HOST_PLATFORM_JSON = '/usr/share/sonic/device/x86_64-pegatron_fn8656_bnf-r0/platform.json' +PMON_PLATFORM_JSON = '/usr/share/sonic/platform/platform.json' + +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 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 run_command(self, cmd): + status = True + result = "" + try: + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + except Exception: + status = False + return status, result + + def run_interactive_command(self, cmd): + try: + os.system(cmd) + except Exception: + return False + return True + + def read_txt_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.read() + fd.close() + return data.strip() + except IOError: + pass + return None + + def read_one_line_file(self, file_path): + try: + with open(file_path, 'r') as fd: + data = fd.readline() + fd.close() + 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)) + fd.close() + except IOError: + return False + return True + + def get_cpld_reg_value(self, getreg_path, register): + cmd = "echo {1} > {0}; cat {0}".format(getreg_path, register) + status, result = self.run_command(cmd) + return result if status else None + + def ipmi_raw(self, netfn, cmd): + status = True + result = "" + try: + cmd = "ipmitool raw {} {}".format(str(netfn), str(cmd)) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_fru_id(self, id, key=None): + status = True + result = "" + try: + cmd = "ipmitool fru print {}".format(str( + id)) if not key else "ipmitool fru print {0} | grep '{1}' ".format(str(id), str(key)) + + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def ipmi_set_ss_thres(self, id, threshold_key, value): + status = True + result = "" + try: + cmd = "ipmitool sensor thresh '{}' {} {}".format( + str(id), str(threshold_key), str(value)) + p = subprocess.Popen( + cmd, shell=True, universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + raw_data, err = p.communicate() + if err == '': + result = raw_data.strip() + else: + status = False + except Exception: + status = False + return status, result + + def get_attr_conf(self, attr): + """ + Retrieves the json object from json file path + + Returns: + A json object + """ + json_path = '' + if self.is_host() is True: + json_path = HOST_PLATFORM_JSON + else : + json_path = PMON_PLATFORM_JSON + with open(json_path, 'r') as f: + json_data = json.load(f) + + return json_data[attr] diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/platform.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/platform.py new file mode 100755 index 000000000000..7d6bda4502de --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/platform.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# +# Name: platform.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + + +try: + from sonic_platform_base.platform_base import PlatformBase + from sonic_platform.chassis import Chassis +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + + +class Platform(PlatformBase): + + def __init__(self): + PlatformBase.__init__(self) + self._chassis = Chassis() diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/psu.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/psu.py new file mode 100755 index 000000000000..fde2da8f8707 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/psu.py @@ -0,0 +1,391 @@ +#!/usr/bin/env python +# +# Name: psu.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + #import os + from sonic_platform_base.psu_base import PsuBase + from sonic_platform.fan import Fan + from sonic_platform.thermal import Thermal + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +class Psu(PsuBase): + + def __init__(self, index,psu_conf): + self.__num_of_fans = len(psu_conf[index]['fans']) + self.__num_of_thermals = len(psu_conf[index]['thermals']) + self.__index = index + self.__conf = psu_conf + self.__api_helper = APIHelper() + self.__attr_path_prefix = '/sys/switch/psu/psu{}/'.format(self.__index + 1) + + self._fan_list = [] + self._thermal_list = [] + PsuBase.__init__(self) + # Initialize PSU FAN + fan_conf=self.__conf[self.__index]['fans'] + for x in range(0, self.__num_of_fans): + fan_conf[x].update({'container':'psu'}) + fan_conf[x].update({'container_index': self.__index}) + fan = Fan(x, fan_conf) + self._fan_list.append(fan) + + # Initialize PSU THERMAL + thermal_conf=self.__conf[self.__index]['thermals'] + for x in range(0, self.__num_of_thermals): + thermal_conf[x].update({'container':'psu'}) + thermal_conf[x].update({'container_index': self.__index}) + thermal = Thermal(x,thermal_conf) + self._thermal_list.append(thermal) + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'status') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if (attr_rv): + presence = True + return presence + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + model = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'model_name') + if (attr_rv != None): + model = attr_rv + + return model + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + serial = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'serial_number') + if (attr_rv != None): + serial = attr_rv + + return serial + + def get_status(self): + """ + Retrieves the operational status of the device + + Returns: + A boolean value, True if device is operating properly, False if not + """ + status = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'status') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if(attr_rv == 0x1): + status = True + return status + + 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 or -1 if cannot determine the position + """ + return self.__index + 1 + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + + def get_date(self): + date = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'date') + if (attr_rv != None): + date = attr_rv + return date + + def get_vendor(self): + vendor = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'vendor') + if (attr_rv != None): + vendor = attr_rv + return vendor + + def get_hw_version(self): + hw_version = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'hardware_version') + if (attr_rv != None): + hw_version = attr_rv + return hw_version + + def get_alarm(self): + alarm = 'Exception: ' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'alarm') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if(attr_rv == 0x0): + alarm = 'Normal' + return alarm + elif alarm & 0x01: + alarm += ' Temperature' + elif alarm & 0x02: + alarm += ' Fan' + elif alarm & 0x04: + alarm += ' Voltage' + + return alarm + + def get_alarm_threshold_curr(self): + alarm_threshold_curr = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'alarm_threshold_curr') + if (attr_rv != None): + alarm_threshold_curr = attr_rv + return alarm_threshold_curr + + def get_alarm_threshold_vol(self): + alarm_threshold_vol = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'alarm_threshold_vol') + if (attr_rv != None): + alarm_threshold_vol = attr_rv + return alarm_threshold_vol + + def get_part_number(self): + part_number = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'part_number') + if (attr_rv != None): + part_number = attr_rv + return part_number + + def get_in_current(self): + in_curr = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'in_curr') + if (attr_rv != None): + in_curr = attr_rv + return in_curr + def get_in_voltage(self): + in_vol = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'in_vol') + if (attr_rv != None): + in_vol = attr_rv + return in_vol + def get_in_power(self): + in_power = 'N/A' + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'in_power') + if (attr_rv != None): + in_power = attr_rv + return in_power + +############################################## +# PSU methods +############################################## + + def get_voltage(self): + """ + Retrieves current PSU voltage output + + Returns: + A float number, the output voltage in volts, + e.g. 12.1 + """ + voltage_out = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'out_vol') + if (attr_rv != None): + voltage_out = float(attr_rv) + + return voltage_out + + def get_current(self): + """ + Retrieves present electric current supplied by PSU + + Returns: + A float number, the electric current in amperes, e.g 15.4 + """ + current_out = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'out_curr') + if (attr_rv != None): + current_out = float(attr_rv) + + return current_out + + def get_power(self): + """ + Retrieves current energy supplied by PSU + + Returns: + A float number, the power in watts, e.g. 302.6 + """ + power_out = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'out_power') + if (attr_rv != None): + power_out = float(attr_rv) + + return power_out + + def get_powergood_status(self): + """ + Retrieves the powergood status of PSU + + Returns: + A boolean, True if PSU has stablized its output voltages and passed all + its internal self-tests, False if not. + """ + return self.get_status() + + def 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 + + Returns: + bool: True if status LED state is set successfully, False if not + """ + raise NotImplementedError + + 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 + """ + color = "off" + + if self.get_presence() is False : + return color + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'led_status') + if (attr_rv != None): + if (int(attr_rv, 16) == 0x1 or int(attr_rv, 16) == 0x4) : + color = "green" + elif (int(attr_rv, 16) == 0x3 or int(attr_rv, 16) == 0x6) : + color = "red" + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'status') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if(attr_rv == 0x2): + color = "red" + return color + + 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 + """ + voltage_high_threshold = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'max_output_vol') + if (attr_rv != None): + voltage_high_threshold = float(attr_rv) + + return voltage_high_threshold + + 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 + """ + voltage_low_threshold = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'min_output_vol') + if (attr_rv != None): + voltage_low_threshold = float(attr_rv) + + return voltage_low_threshold + + def get_maximum_supplied_power(self): + """ + Retrieves the maximum supplied power by PSU + + Returns: + A float number, the maximum power output in Watts. + e.g. 1200.1 + """ + max_power_out = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'max_output_power') + if (attr_rv != None): + max_power_out = float(attr_rv) + + return max_power_out + + 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 + """ + if self.get_presence(): + return self.get_thermal(0).get_high_threshold() + else: + return 0.0 + + 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 + """ + if self.get_presence(): + return self.get_thermal(0).get_temperature() + else: + return 0.0 + + + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp.py new file mode 100755 index 000000000000..d0dc5b27239f --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp.py @@ -0,0 +1,612 @@ +#!/usr/bin/env python +# +# Name: qsfp.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +import os +#import time +#from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + # from sonic_platform_base.sonic_sfp.sfputilhelper import SfpUtilHelper + from .helper import APIHelper + from sonic_platform.qsfp_8436 import QSfp_SFF8436 + from sonic_platform.qsfp_cmis import QSfp_CMIS +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + + +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 + +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18', # QSFP-DD Double Density 8X Pluggable Transceiver + '1b' # QSFP-DD Double Density 8X Pluggable Transceiver +] +CMIS_TYPE_CODE_LIST = [ + '18', # QSFP-DD Double Density 8X Pluggable Transceiver + '1b' # DSFP Dual Small Form Factor Pluggable Transceiver +] + + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +TRANSCEIVER_PATH = '/sys/switch/transceiver/' + +class QSfp(SfpBase): + + port_start = 0 + port_end = 55 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + def __init__(self, index,qsfp_conf): + self.__index = index + self.__conf = qsfp_conf + self.__api_helper = APIHelper() + + self.__attr_path_prefix = '/sys/switch/transceiver/eth{}/'.format(self.__index+1) + + self.__presence_attr = None + self.__eeprom_path = None + + if self.__index in range(0, self.port_end + 1): + self.__eeprom_path = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'eeprom' + self.__presence_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'present' + self.__reset_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'reset' + self.__lpmode_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'lpmode' + SfpBase.__init__(self) + self._detect_sfp_type(QSFP_DD_TYPE) + self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer', + 'model', 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui', 'application_advertisement'] + self.qsfp_8436 = QSfp_SFF8436(index,qsfp_conf) + self.qsfp_cmis = QSfp_CMIS(index,qsfp_conf) + self.is_cmis = False + + def _detect_sfp_type(self, sfp_type): + sfp_type = QSFP_DD_TYPE + self.is_cmis = False + + if not self.get_presence(): + self.sfp_type = sfp_type + return + + eeprom_raw = [] + + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + #self.sfp_type = QSFP_TYPE + self.sfp_type = QSFP_DD_TYPE #xcvrd.py unable to set SI settings when sfp_type is QSFP + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + if eeprom_raw[0] in CMIS_TYPE_CODE_LIST : + self.is_cmis = True + else: + self.sfp_type = sfp_type + + + def __is_host(self): + return os.system("docker > /dev/null 2>&1") == 0 + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_eeprom_path = self.__eeprom_path + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + raw_len = len(raw) + for n in range(0, raw_len): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except BaseException: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def read_eeprom(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_read_bytes = [] + eeprom_raw = [] + raw = [] + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_eeprom_path = self.__eeprom_path + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + raw_len = len(raw) + eeprom_read_bytes = bytearray(raw) + for n in range(0, raw_len): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_read_bytes + + def write_eeprom(self, offset, num_bytes, write_buffer): + try: + with open(self.__eeprom_path, mode='r+b', buffering=0) as f: + f.seek(offset) + f.write(write_buffer[0:num_bytes]) + f.close() + except (OSError, IOError): + return False + return True + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'present') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + presence = True + return presence + + def get_all_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + + presence_bit = 0 + attr_rv = self.__api_helper.read_one_line_file(TRANSCEIVER_PATH + 'present') + if (attr_rv != None): + presence_bit = int(attr_rv, 16) + return presence_bit + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("model", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("serial", "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 self.get_presence() and not self.get_reset_status() + + 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 or -1 if cannot determine the position + """ + return self.__index + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True +############################################## +# SFP methods +############################################## + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + mominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + self._detect_sfp_type(self.sfp_type) + if self.is_cmis == True: + return self.qsfp_cmis.get_transceiver_info() + else: + return self.qsfp_8436.get_transceiver_info() + + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_transceiver_bulk_status() + else: + return self.qsfp_8436.get_transceiver_bulk_status() + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_transceiver_threshold_info() + else: + return self.qsfp_8436.get_transceiver_threshold_info() + def get_reset_status(self): + """ + Retrieves the reset status of SFP + + Returns: + A Boolean, True if reset enabled, False if disabled + """ + reset_status = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'reset') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + reset_status = True + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (loss-of-signal) status of SFP + + Returns: + A list of boolean values, representing the RX LOS status + of each available channel, value is True if SFP channel + has RX LOS, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_rx_los() + else: + return self.qsfp_8436.get_rx_los() + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A list of boolean values, representing the TX fault status + of each available channel, value is True if SFP channel + has TX fault, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_tx_fault() + else: + return self.qsfp_8436.get_tx_fault() + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_tx_disable() + else: + return self.qsfp_8436.get_tx_disable() + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_tx_disable_channel() + else: + return self.qsfp_8436.get_tx_disable_channel() + + 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.is_cmis == True: + return self.qsfp_cmis.get_lpmode() + else: + return self.qsfp_8436.get_lpmode() + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + An integer number of current temperature in Celsius + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_temperature() + else: + return self.qsfp_8436.get_temperature() + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + An integer number of supply voltage in mV + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_voltage() + else: + return self.qsfp_8436.get_voltage() + + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_tx_bias() + else: + return self.qsfp_8436.get_tx_bias() + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_rx_power() + else: + return self.qsfp_8436.get_rx_power() + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + if self.is_cmis == True: + return self.qsfp_cmis.get_tx_power() + else: + return self.qsfp_8436.get_tx_power() + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + if self.is_cmis == True: + return self.qsfp_cmis.reset() + else: + return self.qsfp_8436.reset() + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if self.is_cmis == True: + return self.qsfp_cmis.tx_disable() + else: + return self.qsfp_8436.tx_disable() + + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + + Returns: + A boolean, True if successful, False if not + """ + if self.is_cmis == True: + return self.qsfp_cmis.tx_disable_channel() + else: + return self.qsfp_8436.tx_disable_channel() + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + if self.is_cmis == True: + return self.qsfp_cmis.set_lpmode() + else: + return self.qsfp_8436.set_lpmode() + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + return True + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp_8436.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp_8436.py new file mode 100755 index 000000000000..299d766166ca --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp_8436.py @@ -0,0 +1,1079 @@ +#!/usr/bin/env python +# +# Name: qsfp.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + import logging + from ctypes import create_string_buffer + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8436 import sff8436Dom + from sonic_platform_base.sonic_sfp.sff8436 import sff8436InterfaceId + from sonic_platform_base.sonic_sfp.sff8024 import ext_specification_compliance + #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") + +INFO_OFFSET = 128 +THRE_OFFSET = 384 #128*3 +DOM_OFFSET = 0 + +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_SPECIFICATION_ETH_COMPLIANCE_OFFSET = 3 +XCVR_SPECIFICATION_ETH_COMPLIANCE_WIDTH = 1 +XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + +# Offset for values in QSFP eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNEL_THRESHOLD_OFFSET = 176 +QSFP_CHANNEL_THRESHOLD_WIDTH = 16 + +QSFP_REG_VALUE_ENABLE = "0x1" +QSFP_REG_VALUE_DISABLE = "0x0" +TRANSCEIVER_PATH = '/sys/switch/transceiver/' + +class QSfp_SFF8436(SfpBase): + + + def __init__(self, index,qsfp_conf): + self.__index = index + self.__conf = qsfp_conf + self.__api_helper = APIHelper() + + self.__attr_path_prefix = '/sys/switch/transceiver/eth{}/'.format(self.__index+1) + self.__port_end = 55 + + self.__presence_attr = None + self.__eeprom_path = None + if self.__index in range(0, self.__port_end + 1): + self.__eeprom_path = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'eeprom' + self.__presence_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'present' + self.__reset_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'reset' + self.__lpmode_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'lpmode' + + SfpBase.__init__(self) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def __set_attr_value(self, attr_path, value): + + try: + with open(attr_path, 'r+') as reg_file: + reg_file.write(value) + except IOError as e: + logging.error("Error: unable to open file: '%s'" % str(e)) + return False + + return True + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_eeprom_path = self.__eeprom_path + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + raw_len = len(raw) + for n in range(0, raw_len): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except BaseException: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __write_eeprom_specific_bytes(self, offset, buffer): + sysfs_eeprom_path = self.__eeprom_path + + try: + with open(sysfs_eeprom_path, "r+b") as sysfsfile_eeprom: + sysfsfile_eeprom.seek(offset) + sysfsfile_eeprom.write(buffer[0]) + except IOError as e: + logging.error("Error: unable to open file: '%s'" % str(e)) + return False + + return True + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'present') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + presence = True + return presence + + def get_all_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + + presence_bit = 0 + attr_rv = self.__api_helper.read_one_line_file(TRANSCEIVER_PATH + 'present') + if (attr_rv != None): + presence_bit = int(attr_rv, 16) + return presence_bit + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("model", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("serial", "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 self.get_presence() and not self.get_reset_status() + + 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 or -1 if cannot determine the position + """ + return self.__index + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True +############################################## +# SFP methods +############################################## + def is_copper(self): + ETHERNET_10_40G_COMPLIANCE = { + 1: "40G Active Cable (XLPPI)", + 2: "40GBASE-LR4", + 4: "40GBASE-SR4", + 8: "40GBASE-CR4", + 16: "10GBASE-SR", + 32: "10GBASE-LR", + 64: "10GBASE-LRM", + 128: "Extended", + } + eth_compliance_raw = self.__read_eeprom_specific_bytes(INFO_OFFSET + XCVR_SPECIFICATION_ETH_COMPLIANCE_OFFSET, XCVR_SPECIFICATION_ETH_COMPLIANCE_WIDTH) + try: + eth_compliance = ETHERNET_10_40G_COMPLIANCE[int(eth_compliance_raw[0],16)] + except Exception: + logging.error("cannot specify ethernet10_40G compliance") + return None + ext_spec_compliance_raw = self.__read_eeprom_specific_bytes(INFO_OFFSET + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + ext_spec_compliance = ext_specification_compliance[(ext_spec_compliance_raw[0])] + + if eth_compliance is None or ext_spec_compliance is None: + return None + + return eth_compliance == "40GBASE-CR4" or \ + "CR" in ext_spec_compliance or \ + "ACC" in ext_spec_compliance or \ + "Copper" in ext_spec_compliance + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardwarerev |1*255VCHAR |hardware version of SFP + serialnum |1*255VCHAR |serial number of the SFP + manufacturename |1*255VCHAR |SFP vendor name + modelname |1*255VCHAR |SFP model name + Connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + mominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + transceiver_info_dict_keys = ['type', 'hardware_rev', + 'serialnum', 'manufacturename', + 'modelname', 'Connector', + 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', + 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'vendor_date', + 'vendor_oui'] + + qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', 'Length Cable Assembly(m)') + + qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', 'Fibre Channel transmission media', + 'Fibre Channel Speed') + + sfpi_obj = sff8436InterfaceId() + if not self.get_presence() or not sfpi_obj: + return {} + + offset = INFO_OFFSET + + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes((offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_QSFP) + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + + sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_QSFP) + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + + sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + + sfp_vendor_date_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + + transceiver_info_dict = dict.fromkeys(transceiver_info_dict_keys, 'N/A') + + if sfp_interface_bulk_data: + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['vendor_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' + + transceiver_info_dict['cable_type'] = "Unknown" + transceiver_info_dict['cable_length'] = "Unknown" + for key in qsfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + compliance_code_dict = dict() + for key in qsfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + sfp_ext_specification_compliance_raw = self.__read_eeprom_specific_bytes(offset + XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET, XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH) + if sfp_ext_specification_compliance_raw is not None: + sfp_ext_specification_compliance_data = sfpi_obj.parse_ext_specification_compliance(sfp_ext_specification_compliance_raw[0 : 1], 0) + if sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] != "Unspecified": + compliance_code_dict['Extended Specification compliance'] = sfp_ext_specification_compliance_data['data']['Extended Specification compliance']['value'] + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['Nominal Bit Rate(100Mbs)']['value']) + + if self.is_copper(): + transceiver_info_dict['specification_compliance'] = "{'media_interface':'DAC'}" + else: + transceiver_info_dict['specification_compliance'] = "{'media_interface':'AOC'}" + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + transceiver_dom_info_dict_keys = ['temperature', 'voltage', + 'rx1power', 'rx2power', + 'rx3power', 'rx4power', + 'rx5power', 'rx6power', + 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', + 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', + 'tx3power', 'tx4power', + 'tx5power', 'tx6power', + 'tx7power', 'tx8power' + ] + + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + + if not self.get_presence() or not sfpi_obj or not sfpd_obj: + return {} + + transceiver_dom_info_dict = dict.fromkeys(transceiver_dom_info_dict_keys, 'N/A') + offset = DOM_OFFSET + offset_xcvr = INFO_OFFSET + + # QSFP capability byte parse, through this byte can know whether it support tx_power or not. + # TODO: in the future when decided to migrate to support SFF-8636 instead of SFF-8436, + # need to add more code for determining the capability and version compliance + # in SFF-8636 dom capability definitions evolving with the versions. + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes((offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + else: + return None + + dom_temperature_raw = self.__read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes((offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + # The tx_power monitoring is only available on QSFP which compliant with SFF-8636 + # and claimed that it support tx_power with one indicator bit. + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_channel_monitor_data['data']['TX1Power']['value'] + transceiver_dom_info_dict['tx2power'] = dom_channel_monitor_data['data']['TX2Power']['value'] + transceiver_dom_info_dict['tx3power'] = dom_channel_monitor_data['data']['TX3Power']['value'] + transceiver_dom_info_dict['tx4power'] = dom_channel_monitor_data['data']['TX4Power']['value'] + + if dom_channel_monitor_raw: + transceiver_dom_info_dict['rx1power'] = dom_channel_monitor_data['data']['RX1Power']['value'] + transceiver_dom_info_dict['rx2power'] = dom_channel_monitor_data['data']['RX2Power']['value'] + transceiver_dom_info_dict['rx3power'] = dom_channel_monitor_data['data']['RX3Power']['value'] + transceiver_dom_info_dict['rx4power'] = dom_channel_monitor_data['data']['RX4Power']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_channel_monitor_data['data']['TX1Bias']['value'] + transceiver_dom_info_dict['tx2bias'] = dom_channel_monitor_data['data']['TX2Bias']['value'] + transceiver_dom_info_dict['tx3bias'] = dom_channel_monitor_data['data']['TX3Bias']['value'] + transceiver_dom_info_dict['tx4bias'] = dom_channel_monitor_data['data']['TX4Bias']['value'] + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self.__convert_string_to_num(transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + sfpd_obj = sff8436Dom() + if not self.get_presence() or not sfpd_obj: + return {} + + transceiver_dom_threshold_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + offset = THRE_OFFSET + + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + QSFP_MODULE_THRESHOLD_OFFSET), QSFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw: + module_threshold_values = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + module_threshold_data = module_threshold_values.get('data') + if module_threshold_data: + transceiver_dom_threshold_dict['temphighalarm'] = module_threshold_data['TempHighAlarm']['value'] + transceiver_dom_threshold_dict['templowalarm'] = module_threshold_data['TempLowAlarm']['value'] + transceiver_dom_threshold_dict['temphighwarning'] = module_threshold_data['TempHighWarning']['value'] + transceiver_dom_threshold_dict['templowwarning'] = module_threshold_data['TempLowWarning']['value'] + transceiver_dom_threshold_dict['vcchighalarm'] = module_threshold_data['VccHighAlarm']['value'] + transceiver_dom_threshold_dict['vcclowalarm'] = module_threshold_data['VccLowAlarm']['value'] + transceiver_dom_threshold_dict['vcchighwarning'] = module_threshold_data['VccHighWarning']['value'] + transceiver_dom_threshold_dict['vcclowwarning'] = module_threshold_data['VccLowWarning']['value'] + + dom_channel_thres_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNEL_THRESHOLD_OFFSET), QSFP_CHANNEL_THRESHOLD_WIDTH) + channel_threshold_values = sfpd_obj.parse_channel_threshold_values(dom_channel_thres_raw, 0) + channel_threshold_data = channel_threshold_values.get('data') + if channel_threshold_data: + transceiver_dom_threshold_dict['rxpowerhighalarm'] = channel_threshold_data['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerlowalarm'] = channel_threshold_data['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_dict['rxpowerhighwarning'] = channel_threshold_data['RxPowerHighWarning']['value'] + transceiver_dom_threshold_dict['rxpowerlowwarning'] = channel_threshold_data['RxPowerLowWarning']['value'] + transceiver_dom_threshold_dict['txpowerhighalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowalarm'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerhighwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txpowerlowwarning'] = "0.0dBm" + transceiver_dom_threshold_dict['txbiashighalarm'] = channel_threshold_data['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_dict['txbiaslowalarm'] = channel_threshold_data['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_dict['txbiashighwarning'] = channel_threshold_data['TxBiasHighWarning']['value'] + transceiver_dom_threshold_dict['txbiaslowwarning'] = channel_threshold_data['TxBiasLowWarning']['value'] + + for key in transceiver_dom_threshold_dict: + transceiver_dom_threshold_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_dict[key]) + + return transceiver_dom_threshold_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + + Returns: + A Boolean, True if reset enabled, False if disabled + """ + reset_status = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'reset') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + reset_status = True + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + rx_los_list = [] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(QSFP_CHANNL_RX_LOS_STATUS_OFFSET, QSFP_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 16) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + tx_fault_list = [] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes(QSFP_CHANNL_TX_FAULT_STATUS_OFFSET, QSFP_CHANNL_TX_FAULT_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + tx_fault_data = int(dom_channel_monitor_raw[0], 16) + tx_fault_list.append(tx_fault_data & 0x01 != 0) + tx_fault_list.append(tx_fault_data & 0x02 != 0) + tx_fault_list.append(tx_fault_data & 0x04 != 0) + tx_fault_list.append(tx_fault_data & 0x08 != 0) + + return tx_fault_list + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + tx_disable = False + tx_disable_list = [] + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_disable + + dom_control_raw = self.__read_eeprom_specific_bytes(QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + tx_disable_list.append('On' == dom_control_data['data']['TX1Disable']['value']) + tx_disable_list.append('On' == dom_control_data['data']['TX2Disable']['value']) + tx_disable_list.append('On' == dom_control_data['data']['TX3Disable']['value']) + tx_disable_list.append('On' == dom_control_data['data']['TX4Disable']['value']) + tx_disable = tx_disable_list[0] or tx_disable_list[1] or tx_disable_list[2] or tx_disable_list[3] + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + tx_disable_channel = 0 + tx_disable_list = [] + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return tx_disable_channel + + dom_control_raw = self.__read_eeprom_specific_bytes(QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + tx_disable_list.append('On' == dom_control_data['data']['TX1Disable']['value']) + tx_disable_list.append('On' == dom_control_data['data']['TX2Disable']['value']) + tx_disable_list.append('On' == dom_control_data['data']['TX3Disable']['value']) + tx_disable_list.append('On' == dom_control_data['data']['TX4Disable']['value']) + + for i in range(len(tx_disable_list)): + if tx_disable_list[i]: + tx_disable_channel |= 1 << i + + return tx_disable_channel + + 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 + """ + lpmode = False + attr_path = self.__lpmode_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv,16) == 1): + lpmode = True + + return lpmode + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + power_override = False + + sfpd_obj = sff8436Dom() + if sfpd_obj is None: + return power_override + + dom_control_raw = self.__read_eeprom_specific_bytes(QSFP_CONTROL_OFFSET, QSFP_CONTROL_WIDTH) + if dom_control_raw is not None: + dom_control_data = sfpd_obj.parse_control_bytes(dom_control_raw, 0) + power_override = ('On' == dom_control_data['data']['PowerOverride']['value']) + + return power_override + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + An integer number of current temperature in Celsius + """ + temp = "N/A" + sfpd_obj = sff8436Dom() + offset = DOM_OFFSET + + if not self.get_presence() or not sfpd_obj: + return temp + + dom_temperature_raw = self.__read_eeprom_specific_bytes((offset + QSFP_TEMPE_OFFSET), QSFP_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self.__convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + + return temp + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + An integer number of supply voltage in mV + """ + voltage = "N/A" + sfpd_obj = sff8436Dom() + offset = DOM_OFFSET + + if not self.get_presence() or not sfpd_obj: + return voltage + + dom_voltage_raw = self.__read_eeprom_specific_bytes((offset + QSFP_VOLT_OFFSET), QSFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self.__convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + + return voltage + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + offset = DOM_OFFSET + offset_xcvr = INFO_OFFSET + + if not self.get_presence() or not sfpd_obj: + return [] + + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes((offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + else: + return None + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes((offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + + + if dom_channel_monitor_raw is not None: + tx_bias_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['TX4Bias']['value'])) + + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + offset = DOM_OFFSET + offset_xcvr = INFO_OFFSET + + if not self.get_presence() or not sfpd_obj: + return [] + + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes((offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + else: + return None + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes((offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + + + if dom_channel_monitor_raw is not None: + rx_power_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value'])) + rx_power_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value'])) + rx_power_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value'])) + rx_power_list.append(self.__convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value'])) + + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + tx_power_list = [] + sfpd_obj = sff8436Dom() + sfpi_obj = sff8436InterfaceId() + offset = DOM_OFFSET + offset_xcvr = INFO_OFFSET + + if not self.get_presence() or not sfpd_obj: + return [] + + qsfp_dom_capability_raw = self.__read_eeprom_specific_bytes((offset_xcvr + XCVR_DOM_CAPABILITY_OFFSET), XCVR_DOM_CAPABILITY_WIDTH) + if qsfp_dom_capability_raw is not None: + qspf_dom_capability_data = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + else: + return None + + qsfp_dom_rev_raw = self.__read_eeprom_specific_bytes((offset + QSFP_DOM_REV_OFFSET), QSFP_DOM_REV_WIDTH) + if qsfp_dom_rev_raw is not None: + qsfp_dom_rev_data = sfpd_obj.parse_sfp_dom_rev(qsfp_dom_rev_raw, 0) + qsfp_dom_rev = qsfp_dom_rev_data['data']['dom_rev']['value'] + + dom_channel_monitor_data = {} + dom_channel_monitor_raw = None + qsfp_tx_power_support = qspf_dom_capability_data['data']['Tx_power_support']['value'] + if (qsfp_dom_rev[0:8] != 'SFF-8636' or (qsfp_dom_rev[0:8] == 'SFF-8636' and qsfp_tx_power_support != 'on')): + pass + + else: + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + QSFP_CHANNL_MON_OFFSET), QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH) + if dom_channel_monitor_raw is not None: + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params_with_tx_power(dom_channel_monitor_raw, 0) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value'])) + tx_power_list.append(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value'])) + + return tx_power_list + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + + try: + reg_file = open(self.__reset_attr, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + + try: + reg_file = open(self.__reset_attr, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + tx_disable_ctl = 0xf if tx_disable else 0x0 + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + + return self.__write_eeprom_specific_bytes(QSFP_CONTROL_OFFSET, buffer) + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + + Returns: + A boolean, True if successful, False if not + """ + channel_state = self.get_tx_disable_channel() + if disable: + tx_disable_ctl = channel_state | channel + else: + tx_disable_ctl = channel_state & (~channel & 0xf) + + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + + return self.__write_eeprom_specific_bytes(QSFP_CONTROL_OFFSET, buffer) + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + try: + reg_file = open(self.__lpmode_attr, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + #reg_value = int(reg_file.readline().rstrip()) + + if lpmode is True: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + power_override_bit = 0 + if power_override: + power_override_bit |= 1 << 0 + + power_set_bit = 0 + if power_set: + power_set_bit |= 1 << 1 + + buffer = create_string_buffer(1) + buffer[0] = chr(power_override_bit | power_set_bit) + + return self.__write_eeprom_specific_bytes(QSFP_POWEROVERRIDE_OFFSET, buffer) diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp_cmis.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp_cmis.py new file mode 100755 index 000000000000..9644b8a51d71 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/qsfp_cmis.py @@ -0,0 +1,1782 @@ +#!/usr/bin/env python +# +# Name: qsfp.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +import os +import time +import logging +import struct +import datetime +from ctypes import create_string_buffer + +try: + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_InterfaceId + from sonic_platform_base.sonic_sfp.qsfp_dd import qsfp_dd_Dom + from .helper import APIHelper +except ImportError as e: + raise ImportError (str(e) + "- required module not found") + +# definitions of the offset and width for values in XCVR info eeprom +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_QSFP = 20 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_TYPE_OFFSET = 0 +XCVR_TYPE_WIDTH = 1 +XCVR_EXT_TYPE_OFFSET = 1 +XCVR_EXT_TYPE_WIDTH = 1 +XCVR_CONNECTOR_OFFSET = 2 +XCVR_CONNECTOR_WIDTH = 1 +XCVR_COMPLIANCE_CODE_OFFSET = 3 +XCVR_COMPLIANCE_CODE_WIDTH = 8 +XCVR_ENCODING_OFFSET = 11 +XCVR_ENCODING_WIDTH = 1 +XCVR_NBR_OFFSET = 12 +XCVR_NBR_WIDTH = 1 +XCVR_EXT_RATE_SEL_OFFSET = 13 +XCVR_EXT_RATE_SEL_WIDTH = 1 +XCVR_CABLE_LENGTH_OFFSET = 14 +XCVR_CABLE_LENGTH_WIDTH_QSFP = 5 +XCVR_CABLE_LENGTH_WIDTH_SFP = 6 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_OSFP = 2 +XCVR_HW_REV_WIDTH_QSFP = 2 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_EXT_SPECIFICATION_COMPLIANCE_OFFSET = 64 +XCVR_EXT_SPECIFICATION_COMPLIANCE_WIDTH = 1 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 2 + +# definitions of the offset and width for values in XCVR_QSFP_DD info eeprom +XCVR_EXT_TYPE_OFFSET_QSFP_DD = 72 +XCVR_EXT_TYPE_WIDTH_QSFP_DD = 2 +XCVR_CONNECTOR_OFFSET_QSFP_DD = 75 +XCVR_CONNECTOR_WIDTH_QSFP_DD = 1 +XCVR_CABLE_LENGTH_OFFSET_QSFP_DD = 74 +XCVR_CABLE_LENGTH_WIDTH_QSFP_DD = 1 +XCVR_HW_REV_OFFSET_QSFP_DD = 36 +XCVR_HW_REV_WIDTH_QSFP_DD = 2 +XCVR_VENDOR_DATE_OFFSET_QSFP_DD = 54 +XCVR_VENDOR_DATE_WIDTH_QSFP_DD = 8 +XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD = 2 +XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD = 1 +XCVR_MEDIA_TYPE_OFFSET_QSFP_DD = 85 +XCVR_MEDIA_TYPE_WIDTH_QSFP_DD = 1 +XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD = 86 +XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD = 32 +XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD = 351 +XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD = 28 + +# to improve performance we retrieve all eeprom data via a single ethtool command +# in function get_transceiver_info and get_transceiver_bulk_status +# XCVR_INTERFACE_DATA_SIZE stands for the max size to be read +# this variable is only used by get_transceiver_info. +# please be noted that each time some new value added to the function +# we should make sure that it falls into the area +# [XCVR_INTERFACE_DATA_START, XCVR_INTERFACE_DATA_SIZE] or +# adjust XCVR_INTERFACE_MAX_SIZE to contain the new data +# It's same for [QSFP_DOM_BULK_DATA_START, QSFP_DOM_BULK_DATA_SIZE] and +# [SFP_DOM_BULK_DATA_START, SFP_DOM_BULK_DATA_SIZE] which are used by +# get_transceiver_bulk_status +XCVR_INTERFACE_DATA_START = 0 +XCVR_INTERFACE_DATA_SIZE = 92 +SFP_MODULE_ADDRA2_OFFSET = 256 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 56 + +QSFP_DOM_BULK_DATA_START = 22 +QSFP_DOM_BULK_DATA_SIZE = 36 +SFP_DOM_BULK_DATA_START = 96 +SFP_DOM_BULK_DATA_SIZE = 10 + +QSFP_DD_DOM_BULK_DATA_START = 14 +QSFP_DD_DOM_BULK_DATA_SIZE = 4 + +# definitions of the offset for values in OSFP info eeprom +OSFP_TYPE_OFFSET = 0 +OSFP_VENDOR_NAME_OFFSET = 129 +OSFP_VENDOR_PN_OFFSET = 148 +OSFP_HW_REV_OFFSET = 164 +OSFP_VENDOR_SN_OFFSET = 166 + +# definitions of the offset for values in QSFP_DD info eeprom +QSFP_DD_TYPE_OFFSET = 0 +QSFP_DD_VENDOR_NAME_OFFSET = 1 +QSFP_DD_VENDOR_PN_OFFSET = 20 +QSFP_DD_VENDOR_SN_OFFSET = 38 +QSFP_DD_VENDOR_OUI_OFFSET = 17 + +#definitions of the offset and width for values in DOM info eeprom +QSFP_DOM_REV_OFFSET = 1 +QSFP_DOM_REV_WIDTH = 1 +QSFP_TEMPE_OFFSET = 22 +QSFP_TEMPE_WIDTH = 2 +QSFP_VOLT_OFFSET = 26 +QSFP_VOLT_WIDTH = 2 +QSFP_VERSION_COMPLIANCE_OFFSET = 1 +QSFP_VERSION_COMPLIANCE_WIDTH = 2 +QSFP_CHANNL_MON_OFFSET = 34 +QSFP_CHANNL_MON_WIDTH = 16 +QSFP_CHANNL_MON_WITH_TX_POWER_WIDTH = 24 +QSFP_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_CHANNL_RX_LOS_STATUS_OFFSET = 3 +QSFP_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_CHANNL_TX_FAULT_STATUS_OFFSET = 4 +QSFP_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_CONTROL_OFFSET = 86 +QSFP_CONTROL_WIDTH = 8 +QSFP_MODULE_MONITOR_OFFSET = 0 +QSFP_MODULE_MONITOR_WIDTH = 9 +QSFP_POWEROVERRIDE_OFFSET = 93 +QSFP_POWEROVERRIDE_WIDTH = 1 +QSFP_POWEROVERRIDE_BIT = 0 +QSFP_POWERSET_BIT = 1 +QSFP_OPTION_VALUE_OFFSET = 192 +QSFP_OPTION_VALUE_WIDTH = 4 + +QSFP_MODULE_THRESHOLD_OFFSET = 128 +QSFP_MODULE_THRESHOLD_WIDTH = 24 +QSFP_CHANNL_THRESHOLD_OFFSET = 176 +QSFP_CHANNL_THRESHOLD_WIDTH = 24 + +CMIS_LOWER_PAGE_START = 0 +CMIS_LOWER_PAGE_REVISION_COMPLIANCE_OFFSET = 1 +CMIS_LOWER_PAGE_FLAT_MEM = 2 +CMIS_LOWER_PAGE_MODULE_STATE_OFFSET = 3 + +CMIS_UPPER_PAGE01_START = 128 +CMIS_UPPER_PAGE01_TX_DISABLE_IMPLEMENTED = 155 + + +CMIS_UPPER_PAGE02_START = 384 +CMIS_UPPER_PAGE10_START = 2048 +CMIS_UPPER_PAGE10_DATA_PATH_DEINIT_OFFSET = 128 +CMIS_UPPER_PAGE10_TX_DISABLE_OFFSET = 130 +CMIS_UPPER_PAGE10_STAGED0_APPLY_DATA_PATH_INIT_OFFSET = 143 +CMIS_UPPER_PAGE10_STAGED0_APSEL_CONTROL_OFFSET = 145 + +CMIS_UPPER_PAGE11_START = 2176 +CMIS_UPPER_PAGE11_DATA_PATH_STATE_OFFSET = 128 +CMIS_UPPER_PAGE11_CONFIG_ERROR_CODE_OFFSET = 202 + +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 + + +SFP_CHANNL_STATUS_OFFSET = 110 +SFP_CHANNL_STATUS_WIDTH = 1 + +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +QSFP_DD_TEMPE_OFFSET = 14 +QSFP_DD_TEMPE_WIDTH = 2 +QSFP_DD_VOLT_OFFSET = 16 +QSFP_DD_VOLT_WIDTH = 2 +QSFP_DD_TX_BIAS_OFFSET = 170 +QSFP_DD_TX_BIAS_WIDTH = 16 +QSFP_DD_RX_POWER_OFFSET = 186 +QSFP_DD_RX_POWER_WIDTH = 16 +QSFP_DD_TX_POWER_OFFSET = 26 +QSFP_DD_TX_POWER_WIDTH = 16 +QSFP_DD_CHANNL_MON_OFFSET = 154 +QSFP_DD_CHANNL_MON_WIDTH = 48 +QSFP_DD_CHANNL_DISABLE_STATUS_OFFSET = 86 +QSFP_DD_CHANNL_DISABLE_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET = 19 +QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH = 1 +QSFP_DD_CHANNL_TX_FAULT_STATUS_OFFSET = 7 +QSFP_DD_CHANNL_TX_FAULT_STATUS_WIDTH = 1 +QSFP_DD_MODULE_THRESHOLD_OFFSET = 128 +QSFP_DD_MODULE_THRESHOLD_WIDTH = 72 +QSFP_DD_CHANNL_STATUS_OFFSET = 26 +QSFP_DD_CHANNL_STATUS_WIDTH = 1 +DOM_OFFSET = 0 +# identifier value of xSFP module which is in the first byte of the EEPROM +# if the identifier value falls into SFP_TYPE_CODE_LIST the module is treated as a SFP module and parsed according to 8472 +# for QSFP_TYPE_CODE_LIST the module is treated as a QSFP module and parsed according to 8436/8636 +# Originally the type (SFP/QSFP) of each module is determined according to the SKU dictionary +# where the type of each FP port is defined. The content of EEPROM is parsed according to its type. +# However, sometimes the SFP module can be fit in an adapter and then pluged into a QSFP port. +# In this case the EEPROM content is in format of SFP but parsed as QSFP, causing failure. +# To resolve that issue the type field of the xSFP module is also fetched so that we can know exectly what type the +# module is. Currently only the following types are recognized as SFP/QSFP module. +# Meanwhile, if the a module's identifier value can't be recognized, it will be parsed according to the SKU dictionary. +# This is because in the future it's possible that some new identifier value which is not regonized but backward compatible +# with the current format and by doing so it can be parsed as much as possible. +SFP_TYPE_CODE_LIST = [ + '03' # SFP/SFP+/SFP28 +] +QSFP_TYPE_CODE_LIST = [ + '0d', # QSFP+ or later + '11' # QSFP28 or later +] +QSFP_DD_TYPE_CODE_LIST = [ + '18' # QSFP-DD Double Density 8X Pluggable Transceiver + '1b' # QSFP-DD Double Density 8X Pluggable Transceiver +] + +qsfp_cable_length_tup = ('Length(km)', 'Length OM3(2m)', + 'Length OM2(m)', 'Length OM1(m)', + 'Length Cable Assembly(m)') + +sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + +sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes','FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia','FibreChannelSpeed') + +qsfp_compliance_code_tup = ('10/40G Ethernet Compliance Code', 'SONET Compliance codes', + 'SAS/SATA compliance codes', 'Gigabit Ethernet Compliant codes', + 'Fibre Channel link length/Transmitter Technology', + 'Fibre Channel transmission media', 'Fibre Channel Speed') + +SFP_TYPE = "SFP" +QSFP_TYPE = "QSFP" +OSFP_TYPE = "OSFP" +QSFP_DD_TYPE = "QSFP_DD" + +TRANSCEIVER_PATH = '/sys/switch/transceiver/' + +MODULE_STATE = { + 1: 'ModuleLowPwr', + 2: 'ModulePwrUp', + 3: 'ModuleReady', + 4: 'ModulePwrDn', + 5: 'ModuleFault' +} +DATAPATH_STATE = { + 1: 'DataPathDeactivated', + 2: 'DataPathInit', + 3: 'DataPathDeinit', + 4: 'DataPathActivated', + 5: 'DataPathTxTurnOn', + 6: 'DataPathTxTurnOff', + 7: 'DataPathInitialized', +} +CONFIG_STATUS = { + 0: 'ConfigUndefined', + 1: 'ConfigSuccess', + 2: 'ConfigRejected', + 3: 'ConfigRejectedInvalidAppSel', + 4: 'ConfigRejectedInvalidDataPath', + 5: 'ConfigRejectedInvalidSI', + 6: 'ConfigRejectedLaneInUse', + 7: 'ConfigRejectedPartialDataPath', + 12: 'ConfigInProgress', +} + +CMIS_STATE_UNKNOWN = 'UNKNOWN' +CMIS_STATE_INSERTED = 'INSERTED' +CMIS_STATE_DP_DEINIT = 'DP_DEINIT' +CMIS_STATE_AP_CONF = 'AP_CONFIGURED' +CMIS_STATE_DP_INIT = 'DP_INIT' +CMIS_STATE_DP_TXON = 'DP_TXON' +CMIS_STATE_READY = 'READY' +CMIS_STATE_REMOVED = 'REMOVED' +CMIS_STATE_FAILED = 'FAILED' + +CMIS_MAX_RETRIES = 3 +CMIS_DEF_EXPIRED = 1 # seconds, default expiration time +class QSfp_CMIS(SfpBase): + + port_start = 0 + port_end = 55 + NUM_CHANNELS = 8 + + dom_supported = True + dom_temp_supported = True + dom_volt_supported = True + dom_rx_power_supported = True + dom_tx_power_supported = True + dom_tx_disable_supported = True + calibration = 1 + + def __init__(self, index,qsfp_conf): + self.__index = index + self.__conf = qsfp_conf + self.__api_helper = APIHelper() + + self.__attr_path_prefix = '/sys/switch/transceiver/eth{}/'.format(self.__index+1) + + self.__platform = "x86_64-pegatron_fn8656-bnf-r0" + self.__hwsku = "fn8656-bnf" + + self.__presence_attr = None + self.__eeprom_path = None + + if self.__index in range(0, self.port_end + 1): + self.__eeprom_path = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'eeprom' + self.__presence_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'present' + self.__reset_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'reset' + self.__lpmode_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'lpmode' + SfpBase.__init__(self) + + self.cmis_state = CMIS_STATE_UNKNOWN + self.cmis_retries = 0 + self.cmis_expired = None + + self._detect_sfp_type(QSFP_DD_TYPE) + self.info_dict_keys = ['type', 'hardware_rev', 'serial', 'manufacturer', + 'model', 'connector', 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', 'cable_length', + 'nominal_bit_rate', 'specification_compliance', 'vendor_date', 'vendor_oui', 'application_advertisement'] + + def _detect_sfp_type(self, sfp_type): + sfp_type = QSFP_DD_TYPE + + if not self.get_presence(): + self.sfp_type = sfp_type + return + + eeprom_raw = [] + + eeprom_raw = self._read_eeprom_specific_bytes( + XCVR_TYPE_OFFSET, XCVR_TYPE_WIDTH) + if eeprom_raw: + if eeprom_raw[0] in SFP_TYPE_CODE_LIST: + self.sfp_type = SFP_TYPE + elif eeprom_raw[0] in QSFP_TYPE_CODE_LIST: + self.sfp_type = QSFP_TYPE + elif eeprom_raw[0] in QSFP_DD_TYPE_CODE_LIST: + self.sfp_type = QSFP_DD_TYPE + else: + self.sfp_type = sfp_type + else: + self.sfp_type = sfp_type + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def __is_host(self): + return os.system("docker > /dev/null 2>&1") == 0 + + def __get_path_to_port_config_file(self): + host_platform_root_path = '/usr/share/sonic/device' + docker_hwsku_path = '/usr/share/sonic/hwsku' + + host_platform_path = "/".join([host_platform_root_path, self.__platform]) + hwsku_path = "/".join([host_platform_path, self.__hwsku]) if self.__is_host() else docker_hwsku_path + + return "/".join([hwsku_path, "port_config.ini"]) + + def _read_eeprom_specific_bytes(self, offset, num_bytes): + """ + read register from qsfp eeprom + + Args: + offset: + Integer, lower page : 0 - 127,upper page: page*128 + upper offset + num_bytes: + Interger + Returns: + a character list + """ + sysfsfile_eeprom = None + eeprom_raw = [] + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_eeprom_path = self.__eeprom_path + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + raw_len = len(raw) + for n in range(0, raw_len): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except BaseException: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def _write_eeprom_specific_bytes(self, offset, data): + """ + write one byte to qsfp eeprom + + Args: + offset: + Integer, lower page : 0 - 127,upper page: page*128 + upper offset + data: + Interger + + Returns: + Boolean, true if success otherwise false + """ + sysfs_eeprom_path = self.__eeprom_path + + buffer = create_string_buffer(1) + buffer[0] = struct.pack('B',data) + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode='rb+', buffering=0) + sysfsfile_eeprom.seek(offset) + sysfsfile_eeprom.write(buffer[0]) + sysfsfile_eeprom.close() + except OSError as e: + print(" %s" % str(e), True) + return False + return True + + def read_eeprom(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_read_bytes = [] + eeprom_raw = [] + raw = [] + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_eeprom_path = self.__eeprom_path + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + raw_len = len(raw) + eeprom_read_bytes = bytearray(raw) + for n in range(0, raw_len): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except Exception: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_read_bytes + + def write_eeprom(self, offset, num_bytes, write_buffer): + try: + with open(self.__eeprom_path, mode='r+b', buffering=0) as f: + f.seek(offset) + f.write(write_buffer[0:num_bytes]) + f.close() + except (OSError, IOError): + return False + return True + + def _convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + + def _dom_capability_detect(self): + if not self.get_presence(): + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_tx_power_supported = False + self.calibration = 0 + return + + sfpi_obj = qsfp_dd_InterfaceId() + if sfpi_obj is None: + self.dom_supported = False + + offset = 0 + # two types of QSFP-DD cable types supported: Copper and Optical. + qsfp_dom_capability_raw = self._read_eeprom_specific_bytes((offset + XCVR_DOM_CAPABILITY_OFFSET_QSFP_DD), XCVR_DOM_CAPABILITY_WIDTH_QSFP_DD) + if qsfp_dom_capability_raw is not None: + self.dom_temp_supported = True + self.dom_volt_supported = True + dom_capability = sfpi_obj.parse_dom_capability(qsfp_dom_capability_raw, 0) + if dom_capability['data']['Flat_MEM']['value'] == 'Off': + self.dom_supported = True + self.second_application_list = True + self.dom_rx_power_supported = True + self.dom_tx_power_supported = True + self.dom_tx_bias_power_supported = True + self.dom_thresholds_supported = True + self.dom_rx_tx_power_bias_supported = True + else: + self.dom_supported = False + self.second_application_list = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + else: + self.dom_supported = False + self.dom_temp_supported = False + self.dom_volt_supported = False + self.dom_rx_power_supported = False + self.dom_tx_power_supported = False + self.dom_tx_bias_power_supported = False + self.dom_thresholds_supported = False + self.dom_rx_tx_power_bias_supported = False + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + presence = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'present') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + presence = True + return presence + + def get_all_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + + presence_bit = 0 + attr_rv = self.__api_helper.read_one_line_file(TRANSCEIVER_PATH + 'present') + if (attr_rv != None): + presence_bit = int(attr_rv, 16) + return presence_bit + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("model", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("serial", "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 self.get_presence() and not self.get_reset_status() + + 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 or -1 if cannot determine the position + """ + return self.__index + + def is_replaceable(self): + """ + Indicate whether Chassis is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True +############################################## +# SFP methods +############################################## + + def get_transceiver_type(self,origin_transceiver_type): + transceiver_type = origin_transceiver_type + if transceiver_type != 'Unknown': + return transceiver_type + + type_of_transceiver = { + '00': 'Unknown or unspecified', + '01': 'GBIC', + '02': 'Module/connector soldered to motherboard', + '03': 'SFP/SFP+/SFP28', + '04': '300 pin XBI', + '05': 'XENPAK', + '06': 'XFP', + '07': 'XFF', + '08': 'XFP-E', + '09': 'XPAK', + '0a': 'X2', + '0b': 'DWDM-SFP/SFP+', + '0c': 'QSFP', + '0d': 'QSFP+ or later', + '0e': 'CXP or later', + '0f': 'Shielded Mini Multilane HD 4X', + '10': 'Shielded Mini Multilane HD 8X', + '11': 'QSFP28 or later', + '12': 'CXP2 (aka CXP28) or later', + '13': 'CDFP (Style 1/Style2)', + '14': 'Shielded Mini Multilane HD 4X Fanout Cable', + '15': 'Shielded Mini Multilane HD 8X Fanout Cable', + '16': 'CDFP (Style 3)', + '17': 'microQSFP', + '18': 'QSFP-DD Double Density 8X Pluggable Transceiver', + '19': 'OSFP 8X Pluggable Transceiver', + '1a': 'SFP-DD Double Density 2X Pluggable Transceiver', + '1b': 'DSFP Dual Small Form Factor Pluggable Transceiver', + '1c': 'x4 MiniLink/OcuLink', + '1d': 'x8 MiniLink', + '1e': 'QSFP+ or later with CMIS' + } + + offset = 128 + sfp_type_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + transceiver_type = type_of_transceiver.get(sfp_type_raw[0]) + return transceiver_type + + def get_transceiver_type_abbr_name(self,origin_transceiver_type): + transceiver_type_abbr_name = origin_transceiver_type + if transceiver_type_abbr_name != 'Unknown': + return transceiver_type_abbr_name + + type_abbrv_name = { + '00': 'Unknown', + '01': 'GBIC', + '02': 'Soldered', + '03': 'SFP', + '04': 'XBI300', + '05': 'XENPAK', + '06': 'XFP', + '07': 'XFF', + '08': 'XFP-E', + '09': 'XPAK', + '0a': 'X2', + '0b': 'DWDM-SFP', + '0c': 'QSFP', + '0d': 'QSFP+', + '0e': 'CXP', + '0f': 'HD4X', + '10': 'HD8X', + '11': 'QSFP28', + '12': 'CXP2', + '13': 'CDFP-1/2', + '14': 'HD4X-Fanout', + '15': 'HD8X-Fanout', + '16': 'CDFP-3', + '17': 'MicroQSFP', + '18': 'QSFP-DD', + '19': 'OSFP-8X', + '1a': 'SFP-DD', + '1b': 'DSFP', + '1c': 'Link-x4', + '1d': 'Link-x8', + '1e': 'QSFP+C' + } + offset = 128 + sfp_type_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + transceiver_type_abbr_name = type_abbrv_name.get(sfp_type_raw[0]) + return transceiver_type_abbr_name + + + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serial |1*255VCHAR |serial number of the SFP + manufacturer |1*255VCHAR |SFP vendor name + model |1*255VCHAR |SFP model name + connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + mominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + transceiver_info_dict = {} + transceiver_info_dict = dict.fromkeys(self.info_dict_keys, 'N/A') + transceiver_info_dict['specification_compliance'] = '{}' + + if not self.get_presence(): + return transceiver_info_dict + + self._detect_sfp_type(self.sfp_type) + self._dom_capability_detect() + + sfpi_obj = qsfp_dd_InterfaceId() + if not sfpi_obj: + return None + + offset = 128 + sfp_type_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TYPE_OFFSET), XCVR_TYPE_WIDTH) + sfp_type_data = sfpi_obj.parse_sfp_type(sfp_type_raw, 0) + sfp_type_abbrv_name = sfpi_obj.parse_sfp_type_abbrv_name(sfp_type_raw, 0) + + sfp_vendor_name_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + + sfp_vendor_pn_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + + sfp_vendor_rev_raw = self._read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET_QSFP_DD), XCVR_HW_REV_WIDTH_QSFP_DD) + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + + sfp_vendor_oui_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + + sfp_vendor_date_raw = self._read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET_QSFP_DD), XCVR_VENDOR_DATE_WIDTH_QSFP_DD) + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + + sfp_connector_raw = self._read_eeprom_specific_bytes((offset + XCVR_CONNECTOR_OFFSET_QSFP_DD), XCVR_CONNECTOR_WIDTH_QSFP_DD) + sfp_connector_data = sfpi_obj.parse_connector(sfp_connector_raw, 0) + + sfp_ext_identifier_raw = self._read_eeprom_specific_bytes((offset + XCVR_EXT_TYPE_OFFSET_QSFP_DD), XCVR_EXT_TYPE_WIDTH_QSFP_DD) + sfp_ext_identifier_data = sfpi_obj.parse_ext_iden(sfp_ext_identifier_raw, 0) + + sfp_cable_len_raw = self._read_eeprom_specific_bytes((offset + XCVR_CABLE_LENGTH_OFFSET_QSFP_DD), XCVR_CABLE_LENGTH_WIDTH_QSFP_DD) + sfp_cable_len_data = sfpi_obj.parse_cable_len(sfp_cable_len_raw, 0) + + sfp_media_type_raw = self._read_eeprom_specific_bytes(XCVR_MEDIA_TYPE_OFFSET_QSFP_DD, XCVR_MEDIA_TYPE_WIDTH_QSFP_DD) + if sfp_media_type_raw is not None: + sfp_media_type_dict = sfpi_obj.parse_media_type(sfp_media_type_raw, 0) + if sfp_media_type_dict is None: + return None + + host_media_list = "" + sfp_application_type_first_list = self._read_eeprom_specific_bytes((XCVR_FIRST_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_FIRST_APPLICATION_LIST_WIDTH_QSFP_DD) + if self.second_application_list: + possible_application_count = 15 + sfp_application_type_second_list = self._read_eeprom_specific_bytes((XCVR_SECOND_APPLICATION_LIST_OFFSET_QSFP_DD), XCVR_SECOND_APPLICATION_LIST_WIDTH_QSFP_DD) + if sfp_application_type_first_list is not None and sfp_application_type_second_list is not None: + sfp_application_type_list = sfp_application_type_first_list + sfp_application_type_second_list + else: + return None + else: + possible_application_count = 8 + if sfp_application_type_first_list is not None: + sfp_application_type_list = sfp_application_type_first_list + else: + return None + + for i in range(0, possible_application_count): + if sfp_application_type_list[i * 4] == 'ff': + break + host_electrical, media_interface = sfpi_obj.parse_application(sfp_media_type_dict, sfp_application_type_list[i * 4], sfp_application_type_list[i * 4 + 1]) + host_media_list = host_media_list + host_electrical + ' - ' + media_interface + '\n\t\t\t\t ' + else: + return None + + transceiver_info_dict['manufacturer'] = str(sfp_vendor_name_data['data']['Vendor Name']['value']) + transceiver_info_dict['model'] = str(sfp_vendor_pn_data['data']['Vendor PN']['value']) + transceiver_info_dict['hardware_rev'] = str(sfp_vendor_rev_data['data']['Vendor Rev']['value']) + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] + transceiver_info_dict['vendor_oui'] = str(sfp_vendor_oui_data['data']['Vendor OUI']['value']) + transceiver_info_dict['vendor_date'] = str(sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value']) + transceiver_info_dict['connector'] = str(sfp_connector_data['data']['Connector']['value']) + transceiver_info_dict['encoding'] = "Not supported for CMIS cables" + transceiver_info_dict['ext_identifier'] = str(sfp_ext_identifier_data['data']['Extended Identifier']['value']) + transceiver_info_dict['ext_rateselect_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['specification_compliance'] = "Not supported for CMIS cables" + transceiver_info_dict['cable_type'] = "Length Cable Assembly(m)" + transceiver_info_dict['cable_length'] = str(sfp_cable_len_data['data']['Length Cable Assembly(m)']['value']) + transceiver_info_dict['nominal_bit_rate'] = "Not supported for CMIS cables" + transceiver_info_dict['application_advertisement'] = host_media_list + transceiver_info_dict['type'] = self.get_transceiver_type(str(sfp_type_data['data']['type']['value'])) + transceiver_info_dict['type_abbrv_name'] = self.get_transceiver_type_abbr_name(str(sfp_type_abbrv_name['data']['type_abbrv_name']['value'])) + + #media_settings.json only match media_type + if sfp_media_type_raw[0] == '03': + transceiver_info_dict['specification_compliance'] = "{'media_interface':'DAC'}" + if transceiver_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver": + transceiver_info_dict['specification_compliance'] = "media_interface: DAC" + elif sfp_media_type_raw[0] == '04' or sfp_media_type_raw[0] == '01' or sfp_media_type_raw[0] == '02': + transceiver_info_dict['specification_compliance'] = "{'media_interface':'AOC'}" + if transceiver_info_dict['type'] == "QSFP-DD Double Density 8X Pluggable Transceiver": + transceiver_info_dict['specification_compliance'] = "media_interface: AOC" + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + transceiver_dom_info_dict = {} + + dom_info_dict_keys = ['temperature', 'voltage', + 'rx1power', 'rx2power', + 'rx3power', 'rx4power', + 'rx5power', 'rx6power', + 'rx7power', 'rx8power', + 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', + 'tx5bias', 'tx6bias', + 'tx7bias', 'tx8bias', + 'tx1power', 'tx2power', + 'tx3power', 'tx4power', + 'tx5power', 'tx6power', + 'tx7power', 'tx8power' + ] + transceiver_dom_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + + if not self.get_presence(): + return {} + + self._dom_capability_detect() + + offset = 0 + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_info_dict + + dom_data_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_DOM_BULK_DATA_START), QSFP_DD_DOM_BULK_DATA_SIZE) + if dom_data_raw is None: + return transceiver_dom_info_dict + + if self.dom_temp_supported: + start = QSFP_DD_TEMPE_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_TEMPE_WIDTH + dom_temperature_data = sfpd_obj.parse_temperature(dom_data_raw[start : end], 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + if temp is not None: + transceiver_dom_info_dict['temperature'] = temp + + if self.dom_volt_supported: + start = QSFP_DD_VOLT_OFFSET - QSFP_DD_DOM_BULK_DATA_START + end = start + QSFP_DD_VOLT_WIDTH + dom_voltage_data = sfpd_obj.parse_voltage(dom_data_raw[start : end], 0) + volt = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + if volt is not None: + transceiver_dom_info_dict['voltage'] = volt + + if self.dom_rx_tx_power_bias_supported: + # page 11h + offset = CMIS_UPPER_PAGE11_START + dom_data_raw = self._read_eeprom_specific_bytes(offset + QSFP_DD_CHANNL_MON_OFFSET, QSFP_DD_CHANNL_MON_WIDTH) + if dom_data_raw is None: + return transceiver_dom_info_dict + dom_channel_monitor_data = sfpd_obj.parse_channel_monitor_params(dom_data_raw, 0) + + if self.dom_tx_power_supported: + transceiver_dom_info_dict['tx1power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX1Power']['value'])) + transceiver_dom_info_dict['tx2power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX2Power']['value'])) + transceiver_dom_info_dict['tx3power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX3Power']['value'])) + transceiver_dom_info_dict['tx4power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX4Power']['value'])) + transceiver_dom_info_dict['tx5power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX5Power']['value'])) + transceiver_dom_info_dict['tx6power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX6Power']['value'])) + transceiver_dom_info_dict['tx7power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX7Power']['value'])) + transceiver_dom_info_dict['tx8power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['TX8Power']['value'])) + + if self.dom_rx_power_supported: + transceiver_dom_info_dict['rx1power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX1Power']['value'])) + transceiver_dom_info_dict['rx2power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX2Power']['value'])) + transceiver_dom_info_dict['rx3power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX3Power']['value'])) + transceiver_dom_info_dict['rx4power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX4Power']['value'])) + transceiver_dom_info_dict['rx5power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX5Power']['value'])) + transceiver_dom_info_dict['rx6power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX6Power']['value'])) + transceiver_dom_info_dict['rx7power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX7Power']['value'])) + transceiver_dom_info_dict['rx8power'] = str(self._convert_string_to_num(dom_channel_monitor_data['data']['RX8Power']['value'])) + + if self.dom_tx_bias_power_supported: + transceiver_dom_info_dict['tx1bias'] = str(dom_channel_monitor_data['data']['TX1Bias']['value']) + transceiver_dom_info_dict['tx2bias'] = str(dom_channel_monitor_data['data']['TX2Bias']['value']) + transceiver_dom_info_dict['tx3bias'] = str(dom_channel_monitor_data['data']['TX3Bias']['value']) + transceiver_dom_info_dict['tx4bias'] = str(dom_channel_monitor_data['data']['TX4Bias']['value']) + transceiver_dom_info_dict['tx5bias'] = str(dom_channel_monitor_data['data']['TX5Bias']['value']) + transceiver_dom_info_dict['tx6bias'] = str(dom_channel_monitor_data['data']['TX6Bias']['value']) + transceiver_dom_info_dict['tx7bias'] = str(dom_channel_monitor_data['data']['TX7Bias']['value']) + transceiver_dom_info_dict['tx8bias'] = str(dom_channel_monitor_data['data']['TX8Bias']['value']) + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict = {} + + dom_info_dict_keys = ['temphighalarm', 'temphighwarning', + 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', + 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', + 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', + 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', + 'txbiaslowalarm', 'txbiaslowwarning' + ] + transceiver_dom_threshold_info_dict = dict.fromkeys(dom_info_dict_keys, 'N/A') + if not self.get_presence(): + return {} + + if not self.dom_supported: + return transceiver_dom_threshold_info_dict + + if not self.dom_thresholds_supported: + return transceiver_dom_threshold_info_dict + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return transceiver_dom_threshold_info_dict + + # page 02 + offset = CMIS_UPPER_PAGE02_START + dom_module_threshold_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_MODULE_THRESHOLD_OFFSET), QSFP_DD_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is None: + return transceiver_dom_threshold_info_dict + + dom_module_threshold_data = sfpd_obj.parse_module_threshold_values(dom_module_threshold_raw, 0) + + # Threshold Data + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VccHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VccHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VccLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VccLowWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RxPowerLowWarning']['value'] + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['TxBiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['TxBiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['TxBiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['TxBiasLowWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TxPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TxPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TxPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TxPowerLowWarning']['value'] + + + return transceiver_dom_threshold_info_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + + Returns: + A Boolean, True if reset enabled, False if disabled + """ + reset_status = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'reset') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + reset_status = True + return reset_status + + def get_rx_los(self): + """ + Retrieves the RX LOS (loss-of-signal) status of SFP + + Returns: + A list of boolean values, representing the RX LOS status + of each available channel, value is True if SFP channel + has RX LOS, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + if not self.dom_supported: + return None + + rx_los_list = [] + + if self.dom_rx_tx_power_bias_supported: + offset = 512 + dom_channel_monitor_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_CHANNL_RX_LOS_STATUS_OFFSET), QSFP_DD_CHANNL_RX_LOS_STATUS_WIDTH) + if dom_channel_monitor_raw is not None: + rx_los_data = int(dom_channel_monitor_raw[0], 8) + rx_los_list.append(rx_los_data & 0x01 != 0) + rx_los_list.append(rx_los_data & 0x02 != 0) + rx_los_list.append(rx_los_data & 0x04 != 0) + rx_los_list.append(rx_los_data & 0x08 != 0) + rx_los_list.append(rx_los_data & 0x10 != 0) + rx_los_list.append(rx_los_data & 0x20 != 0) + rx_los_list.append(rx_los_data & 0x40 != 0) + rx_los_list.append(rx_los_data & 0x80 != 0) + + return rx_los_list + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A list of boolean values, representing the TX fault status + of each available channel, value is True if SFP channel + has TX fault, False if not. + E.g., for a tranceiver with four channels: [False, False, True, False] + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + if not self.dom_supported: + return None + + return None + + 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 + """ + lpmode = False + attr_path = self.__lpmode_attr + + attr_rv = self.__get_attr_value(attr_path) + if (attr_rv != 'ERR'): + if (int(attr_rv,16) == 1): + lpmode = True + + return lpmode + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + return None + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + An integer number of current temperature in Celsius + """ + offset = 0 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_temp_supported: + dom_temperature_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TEMPE_OFFSET), QSFP_DD_TEMPE_WIDTH) + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + temp = self._convert_string_to_num(dom_temperature_data['data']['Temperature']['value']) + return temp + return None + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + An integer number of supply voltage in mV + """ + offset = 128 + + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_volt_supported: + dom_voltage_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_VOLT_OFFSET), QSFP_DD_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + voltage = self._convert_string_to_num(dom_voltage_data['data']['Vcc']['value']) + return voltage + return None + + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + tx_bias_list = [] + # page 11h + if self.dom_rx_tx_power_bias_supported: + offset = CMIS_UPPER_PAGE11_START + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_tx_bias_power_supported: + dom_tx_bias_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_TX_BIAS_OFFSET), QSFP_DD_TX_BIAS_WIDTH) + if dom_tx_bias_raw is not None: + dom_tx_bias_data = sfpd_obj.parse_dom_tx_bias(dom_tx_bias_raw, 0) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX1Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX2Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX3Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX4Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX5Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX6Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX7Bias']['value'])) + tx_bias_list.append(self._convert_string_to_num(dom_tx_bias_data['data']['TX8Bias']['value'])) + return tx_bias_list + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + rx_power_list = [] + # page 11 + if self.dom_rx_tx_power_bias_supported: + offset = CMIS_UPPER_PAGE11_START + sfpd_obj = qsfp_dd_Dom() + if sfpd_obj is None: + return None + + if self.dom_rx_power_supported: + dom_rx_power_raw = self._read_eeprom_specific_bytes((offset + QSFP_DD_RX_POWER_OFFSET), QSFP_DD_RX_POWER_WIDTH) + if dom_rx_power_raw is not None: + dom_rx_power_data = sfpd_obj.parse_dom_rx_power(dom_rx_power_raw, 0) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX1Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX2Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX3Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX4Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX5Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX6Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX7Power']['value'])) + rx_power_list.append(self._convert_string_to_num(dom_rx_power_data['data']['RX8Power']['value'])) + return rx_power_list + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + return None + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + + try: + reg_file = open(self.__reset_attr, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 1 + reg_file.write(hex(reg_value)) + reg_file.close() + + # Sleep 2 second to allow it to settle + time.sleep(2) + + try: + reg_file = open(self.__reset_attr, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + reg_value = 0 + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def is_mem_flat(self): + offset = CMIS_LOWER_PAGE_START + CMIS_LOWER_PAGE_FLAT_MEM + data = self._read_eeprom_specific_bytes(offset, 1) + is_flat_memory = (int(data[0],16) & 0xff) >> 7 + return is_flat_memory + + def get_tx_disable_support(self): + offset = CMIS_UPPER_PAGE01_START + CMIS_UPPER_PAGE01_TX_DISABLE_IMPLEMENTED + data = self._read_eeprom_specific_bytes(offset, 1) + tx_disable_implemented = ((int(data[0],16) & 0xff) & (0x1 << 1)) >> 1 + return not self.is_mem_flat() and tx_disable_implemented + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A Boolean List + """ + tx_disable_support = self.get_tx_disable_support() + if tx_disable_support is None: + return None + if not tx_disable_support: + return ["N/A" for _ in range(self.NUM_CHANNELS)] + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_TX_DISABLE_OFFSET + tx_disable = self._read_eeprom_specific_bytes(offset, 1) + + return [bool(int(tx_disable[0],16) & (1 << i)) for i in range(self.NUM_CHANNELS)] + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + + Returns: + A hex of 8 bits (bit 0 to bit 7 as channel 0 to channel 7) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + tx_disable_support = self.get_tx_disable_support() + if tx_disable_support is None: + return None + if not tx_disable_support: + return 'N/A' + + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_TX_DISABLE_OFFSET + tx_disable = self._read_eeprom_specific_bytes(offset, 1) + return int(tx_disable[0],16) + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + if not self.get_presence(): + return False + + if self.dom_tx_disable_supported: + channel_mask = 0xff + if tx_disable: + return self.tx_disable_channel(channel_mask, True) + else: + return self.tx_disable_channel(channel_mask, False) + else: + return False + + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + + Returns: + A boolean, True if successful, False if not + """ + channel_state = self.get_tx_disable_channel() + if channel_state is None or channel_state == 'N/A': + return False + + for i in range(self.NUM_CHANNELS): + mask = (1 << i) + if not (channel & mask): + continue + if disable: + channel_state |= mask + else: + channel_state &= ~mask + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_TX_DISABLE_OFFSET + + return self._write_eeprom_specific_bytes(offset, channel_state) + + def set_datapath_deinit(self, channel): + """ + Put the CMIS datapath into the de-initialized state + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + offset = CMIS_LOWER_PAGE_START + CMIS_LOWER_PAGE_REVISION_COMPLIANCE_OFFSET + cmis_major = self._read_eeprom_specific_bytes(offset, 1) + + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_DATA_PATH_DEINIT_OFFSET + data = self._read_eeprom_specific_bytes(offset, 1) + deinit_value = int(data[0],16) + for lane in range(self.NUM_CHANNELS): + if ((1 << lane) & channel) == 0: + continue + if int(cmis_major[0],16) >= 4: # CMIS v4 onwards + deinit_value |= (1 << lane) + else: # CMIS v3 + deinit_value &= ~(1 << lane) + + return self._write_eeprom_specific_bytes(offset,deinit_value) + + def set_datapath_init(self, channel): + """ + Put the CMIS datapath into the de-initialized state + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + + Returns: + Boolean, true if success otherwise false + """ + offset = CMIS_LOWER_PAGE_START + CMIS_LOWER_PAGE_REVISION_COMPLIANCE_OFFSET + cmis_major = self._read_eeprom_specific_bytes(offset, 1) + + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_DATA_PATH_DEINIT_OFFSET + data = self._read_eeprom_specific_bytes(offset, 1) + deinit_value = int(data[0],16) + for lane in range(self.NUM_CHANNELS): + if ((1 << lane) & channel) == 0: + continue + if int(cmis_major[0],16) >= 4: # CMIS v4 onwards + deinit_value &= ~(1 << lane) + else: # CMIS v3 + deinit_value |= (1 << lane) + + return self._write_eeprom_specific_bytes(offset,deinit_value) + + def get_module_state(self): + """ + get the module state + + Args: + Returns: + string in dict MODULE_STATE + """ + offset = CMIS_LOWER_PAGE_START + CMIS_LOWER_PAGE_MODULE_STATE_OFFSET + data = self._read_eeprom_specific_bytes(offset, 1) + state = (int(data[0],16) & 0xe) >> 1 + return MODULE_STATE[state] + + def test_module_state(self, states): + """ + Check if the CMIS module is in the specified state + + Args: + states: + List, a string list of states + + Returns: + Boolean, true if it's in the specified state, otherwise false + """ + return self.get_module_state() in states + + def get_datapath_state(self,channel): + """ + get the channel datapath state + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + Returns: + string in dict DATAPATH_STATE + """ + state = '' + for lane in range(self.NUM_CHANNELS): + if ((1 << lane) & channel) == 0: + continue + offset = CMIS_UPPER_PAGE11_START + CMIS_UPPER_PAGE11_DATA_PATH_STATE_OFFSET + (lane//2) + data = self._read_eeprom_specific_bytes(offset, 1) + tmp_data = int(data[0],16) + if tmp_data % 2: + state = tmp_data >> 4 + else: + state = tmp_data & 0xf + return DATAPATH_STATE[state] + + def test_datapath_state(self, channel, states): + """ + Check if the CMIS datapath states are in the specified state + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + states: + List, a string list of states + + Returns: + Boolean, true if all lanes are in the specified state, otherwise false + """ + return self.get_datapath_state(channel) in states + + def set_application(self, channel, appl_code): + """ + Update the selected application code to the specified lanes on the host side + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + appl_code: + Integer, the desired application code + + Returns: + Boolean, true if success otherwise false + """ + # Update the application selection + lane_first = -1 + for lane in range(self.NUM_CHANNELS): + if ((1 << lane) & channel) == 0: + continue + if lane_first < 0: + lane_first = lane + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_STAGED0_APSEL_CONTROL_OFFSET + lane + data = (appl_code << 4) | (lane_first << 1) + self._write_eeprom_specific_bytes(offset, data) + + offset = CMIS_UPPER_PAGE10_START + CMIS_UPPER_PAGE10_STAGED0_APPLY_DATA_PATH_INIT_OFFSET + #data = (appl_code << 4) | (lane_first << 1) + # Apply DataPathInit + return self._write_eeprom_specific_bytes(offset, channel) + + def get_config_datapath_hostlane_status(self,channel): + """ + return configuration command execution result status for + the datapath of each host lane + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + Returns: + string in dict CONFIG_STATUS + """ + state = '' + for lane in range(self.NUM_CHANNELS): + if ((1 << lane) & channel) == 0: + continue + offset = CMIS_UPPER_PAGE11_START + CMIS_UPPER_PAGE11_CONFIG_ERROR_CODE_OFFSET + (lane//2) + data = self._read_eeprom_specific_bytes(offset, 1) + tmp_data = int(data[0],16) + if tmp_data % 2: + state = tmp_data >> 4 + else: + state = tmp_data & 0xf + return CONFIG_STATUS[state] + + def test_config_error(self, channel, states): + """ + Check if the CMIS configuration states are in the specified state + + Args: + channel: + Integer, a bitmask of the lanes on the host side + e.g. 0x5 for lane 0 and lane 2. + states: + List, a string list of states + + Returns: + Boolean, true if all lanes are in the specified state, otherwise false + """ + return self.get_config_datapath_hostlane_status(channel) in states + + def reset_cmis_init(self,retries): + self.cmis_state = CMIS_STATE_INSERTED + self.cmis_retries = retries + self.cmis_expired = None # No expiration + + def init_sequence(self): + host_lanes = 0xff + retries = self.cmis_retries + expired = self.cmis_expired + now = datetime.datetime.now() + self.cmis_state = CMIS_STATE_INSERTED + + while self.cmis_state is not CMIS_STATE_READY: + # CMIS state transitions + if self.cmis_state == CMIS_STATE_INSERTED: + """ + appl = self.get_cmis_application_desired( host_lanes, host_speed) + if appl < 1: + logging.errorr("port {}: no suitable app for the port".format(self.__index)) + self.cmis_state = CMIS_STATE_FAILED + continue + + has_update = self.is_cmis_application_update_required(host_lanes, host_speed) + if not has_update: + # No application updates + logging.error("port {}: READY".format(self.__index)) + self.cmis_state = CMIS_STATE_READY + continue + """ + # D.2.2 Software Deinitialization + self.set_datapath_deinit(host_lanes) + self.set_lpmode(True) + if not self.test_module_state(['ModuleReady', 'ModuleLowPwr']): + logging.error("port {}: unable to enter low-power mode".format(self.__index)) + self.cmis_retries = retries + 1 + continue + + # D.1.3 Software Configuration and Initialization + if not self.tx_disable_channel(host_lanes, True): + logging.error("port {}: unable to turn off tx power".format(self.__index)) + self.cmis_retries = retries + 1 + continue + self.set_lpmode(False) + + # TODO: Use fine grained time when the CMIS memory map is available + self.cmis_expired = now + datetime.timedelta(seconds=CMIS_DEF_EXPIRED) + self.cmis_state = CMIS_STATE_DP_DEINIT + elif self.cmis_state == CMIS_STATE_DP_DEINIT: + if not self.test_module_state(['ModuleReady']): + if (expired is not None) and (expired <= now): + logging.error("port {}: timeout for 'ModuleReady'".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + if not self.test_datapath_state(host_lanes, ['DataPathDeinit', 'DataPathDeactivated']): + if (expired is not None) and (expired <= now): + logging.error("port {}: timeout for 'DataPathDeinit'".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + + """ + # D.1.3 Software Configuration and Initialization + appl = self.get_cmis_application_desired(host_lanes, host_speed) + if appl < 1: + logging.error("port {}: no suitable app for the port".format(self.__index)) + self.cmis_state = CMIS_STATE_FAILED + continue + if not self.set_application(host_lanes, appl): + """ + if not self.set_application(host_lanes, 1): + logging.error("{}: unable to set application".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + + # TODO: Use fine grained time when the CMIS memory map is available + self.cmis_expired = now + datetime.timedelta(seconds=CMIS_DEF_EXPIRED) + self.cmis_state = CMIS_STATE_AP_CONF + elif self.cmis_state == CMIS_STATE_AP_CONF: + if not self.test_config_error(host_lanes, ['ConfigSuccess']): + if (expired is not None) and (expired <= now): + logging.error("port {}: timeout for 'ConfigSuccess'".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + + # D.1.3 Software Configuration and Initialization + self.set_datapath_init(host_lanes) + + # TODO: Use fine grained time when the CMIS memory map is available + self.cmis_expired = now + datetime.timedelta(seconds=CMIS_DEF_EXPIRED) + self.cmis_state = CMIS_STATE_DP_INIT + elif self.cmis_state == CMIS_STATE_DP_INIT: + if not self.test_datapath_state(host_lanes, ['DataPathInitialized']): + if (expired is not None) and (expired <= now): + logging.error("port {}: timeout for 'DataPathInitialized'".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + + # D.1.3 Software Configuration and Initialization + if not self.tx_disable_channel(host_lanes, False): + logging.error("port {}: unable to turn on tx power".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + + # TODO: Use fine grained timeout when the CMIS memory map is available + self.cmis_expired = now + datetime.timedelta(seconds=CMIS_DEF_EXPIRED) + self.cmis_state = CMIS_STATE_DP_TXON + elif self.cmis_state == CMIS_STATE_DP_TXON: + if not self.test_datapath_state(host_lanes, ['DataPathActivated']): + if (expired is not None) and (expired <= now): + logging.error("port {}: timeout for 'DataPathActivated'".format(self.__index)) + self.reset_cmis_init(retries + 1) + continue + logging.error("port {}: READY".format(self.__index)) + self.cmis_state = CMIS_STATE_READY + return self.cmis_state + + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + try: + reg_file = open(self.__lpmode_attr, "r+") + except IOError as e: + print("Error: unable to open file: %s" % str(e)) + return False + + #reg_value = int(reg_file.readline().rstrip(),16) + + if lpmode is True: + reg_value = 1 + else: + reg_value = 0 + + reg_file.write(hex(reg_value)) + reg_file.close() + + return True + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + return True + diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/sfp.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/sfp.py new file mode 100755 index 000000000000..1fef3a759e2e --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/sfp.py @@ -0,0 +1,790 @@ +#!/usr/bin/env python +# +# Name: sfp.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + #import sys + from sonic_platform_base.sfp_base import SfpBase + from sonic_platform_base.sonic_sfp.sff8472 import sff8472Dom + from sonic_platform_base.sonic_sfp.sff8472 import sff8472InterfaceId + from sonic_platform_base.sonic_sfp.sff8472 import sffbase + 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") + +INFO_OFFSET = 0 +DOM_OFFSET = 256 + +XCVR_INTFACE_BULK_OFFSET = 0 +XCVR_INTFACE_BULK_WIDTH_SFP = 21 +XCVR_VENDOR_NAME_OFFSET = 20 +XCVR_VENDOR_NAME_WIDTH = 16 +XCVR_VENDOR_OUI_OFFSET = 37 +XCVR_VENDOR_OUI_WIDTH = 3 +XCVR_VENDOR_PN_OFFSET = 40 +XCVR_VENDOR_PN_WIDTH = 16 +XCVR_HW_REV_OFFSET = 56 +XCVR_HW_REV_WIDTH_SFP = 4 +XCVR_VENDOR_SN_OFFSET = 68 +XCVR_VENDOR_SN_WIDTH = 16 +XCVR_VENDOR_DATE_OFFSET = 84 +XCVR_VENDOR_DATE_WIDTH = 8 +XCVR_DOM_CAPABILITY_OFFSET = 92 +XCVR_DOM_CAPABILITY_WIDTH = 1 + +# Offset for values in SFP eeprom +SFP_TEMPE_OFFSET = 96 +SFP_TEMPE_WIDTH = 2 +SFP_VOLT_OFFSET = 98 +SFP_VOLT_WIDTH = 2 +SFP_CHANNL_MON_OFFSET = 100 +SFP_CHANNL_MON_WIDTH = 6 +SFP_MODULE_THRESHOLD_OFFSET = 0 +SFP_MODULE_THRESHOLD_WIDTH = 40 +SFP_CHANNL_THRESHOLD_OFFSET = 112 +SFP_CHANNL_THRESHOLD_WIDTH = 2 +SFP_STATUS_CONTROL_OFFSET = 110 +SFP_STATUS_CONTROL_WIDTH = 1 +SFP_TX_DISABLE_HARD_BIT = 7 +SFP_TX_DISABLE_SOFT_BIT = 6 + +TRANSCEIVER_PATH = '/sys/switch/transceiver/' + +class Sfp(SfpBase): + + port_start = 0 + port_end = 55 + + cplda_sfp_num = 0 + cpldb_sfp_num = 28 + cpldc_sfp_num = 28 + __port_to_i2c_mapping = {} + def __init__(self, index): + self.__index = index + + self.__platform = "x86_64-pegatron_fn8656-bnf-r0" + self.__hwsku = "fn8656-bnf" + self.__attr_path_prefix = '/sys/switch/transceiver/eth{}/'.format(self.__index+1) + + self.__api_helper = APIHelper() + self.__presence_attr = None + self.__eeprom_path = None + + if self.__index in range(0, self.port_end + 1): + self.__eeprom_path = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'eeprom' + self.__presence_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'present' + self.__reset_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'reset' + self.__lpmode_attr = TRANSCEIVER_PATH+'eth{}/'.format(self.__index+1)+'lpmode' + + SfpBase.__init__(self) + + def __get_attr_value(self, attr_path): + + retval = 'ERR' + if (not os.path.isfile(attr_path)): + return retval + + try: + with open(attr_path, 'r') as fd: + retval = fd.read() + except Exception as error: + logging.error("Unable to open ", attr_path, " file !") + + retval = retval.rstrip(' \t\n\r') + return retval + + def __is_host(self): + return os.system("docker > /dev/null 2>&1") == 0 + + def __get_path_to_port_config_file(self): + host_platform_root_path = '/usr/share/sonic/device' + docker_hwsku_path = '/usr/share/sonic/hwsku' + + host_platform_path = "/".join([host_platform_root_path, self.__platform]) + hwsku_path = "/".join([host_platform_path, self.__hwsku]) if self.__is_host() else docker_hwsku_path + + return "/".join([hwsku_path, "port_config.ini"]) + + def __read_eeprom_specific_bytes(self, offset, num_bytes): + sysfsfile_eeprom = None + eeprom_raw = [] + + for i in range(0, num_bytes): + eeprom_raw.append("0x00") + + sysfs_eeprom_path = self.__eeprom_path + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="rb", buffering=0) + sysfsfile_eeprom.seek(offset) + raw = sysfsfile_eeprom.read(num_bytes) + raw_len = len(raw) + for n in range(0, raw_len): + eeprom_raw[n] = hex(raw[n])[2:].zfill(2) + except BaseException: + pass + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + + return eeprom_raw + + def __convert_string_to_num(self, value_str): + if "-inf" in value_str: + return 'N/A' + elif "Unknown" in value_str: + return 'N/A' + elif 'dBm' in value_str: + t_str = value_str.rstrip('dBm') + return float(t_str) + elif 'mA' in value_str: + t_str = value_str.rstrip('mA') + return float(t_str) + elif 'C' in value_str: + t_str = value_str.rstrip('C') + return float(t_str) + elif 'Volts' in value_str: + t_str = value_str.rstrip('Volts') + return float(t_str) + else: + return 'N/A' + +############################################## +# Device methods +############################################## + + def get_name(self): + """ + Retrieves the name of the device + + Returns: + string: The name of the device + """ + name = None + + 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 + """ + presence = False + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'present') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + if ((attr_rv & 0x1) == 1): + presence = True + return presence + + def get_all_presence(self): + """ + Retrieves the presence of the device + + Returns: + bool: True if device is present, False if not + """ + + attr_rv = self.__api_helper.read_one_line_file(TRANSCEIVER_PATH + 'present') + if (attr_rv != None): + attr_rv = int(attr_rv, 16) + return attr_rv + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + + Returns: + string: Model/part number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("modelname", "N/A") + + def get_serial(self): + """ + Retrieves the serial number of the device + + Returns: + string: Serial number of device + """ + transceiver_info_dict = self.get_transceiver_info() + return transceiver_info_dict.get("serialnum", "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 self.get_presence() and not self.get_reset_status() + + 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 or -1 if cannot determine the position + """ + return self.__index + + def is_replaceable(self): + """ + Indicate whether Fan is replaceable. + Returns: + bool: True if it is replaceable. + """ + return True + +############################################## +# SFP methods +############################################## + + def get_transceiver_info(self): + """ + Retrieves transceiver info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + type |1*255VCHAR |type of SFP + hardware_rev |1*255VCHAR |hardware version of SFP + serialnum |1*255VCHAR |serial number of the SFP + manufacturename |1*255VCHAR |SFP vendor name + modelname |1*255VCHAR |SFP model name + Connector |1*255VCHAR |connector information + encoding |1*255VCHAR |encoding information + ext_identifier |1*255VCHAR |extend identifier + ext_rateselect_compliance |1*255VCHAR |extended rateSelect compliance + cable_length |INT |cable length in m + mominal_bit_rate |INT |nominal bit rate by 100Mbs + specification_compliance |1*255VCHAR |specification compliance + vendor_date |1*255VCHAR |vendor date + vendor_oui |1*255VCHAR |vendor OUI + ======================================================================== + """ + + transceiver_info_dict_keys = ['type', 'hardware_rev', + 'serial', 'manufacturer', + 'model', 'connector', + 'encoding', 'ext_identifier', + 'ext_rateselect_compliance', 'cable_type', + 'cable_length', 'nominal_bit_rate', + 'specification_compliance', 'vendor_date', + 'vendor_oui'] + + sfp_cable_length_tup = ('LengthSMFkm-UnitsOfKm', 'LengthSMF(UnitsOf100m)', + 'Length50um(UnitsOf10m)', 'Length62.5um(UnitsOfm)', + 'LengthCable(UnitsOfm)', 'LengthOM3(UnitsOf10m)') + + sfp_compliance_code_tup = ('10GEthernetComplianceCode', 'InfinibandComplianceCode', + 'ESCONComplianceCodes', 'SONETComplianceCodes', + 'EthernetComplianceCodes', 'FibreChannelLinkLength', + 'FibreChannelTechnology', 'SFP+CableTechnology', + 'FibreChannelTransmissionMedia', 'FibreChannelSpeed') + + sfpi_obj = sff8472InterfaceId() + if not self.get_presence() or not sfpi_obj: + return {} + + offset = INFO_OFFSET + + sfp_interface_bulk_raw = self.__read_eeprom_specific_bytes((offset + XCVR_INTFACE_BULK_OFFSET), XCVR_INTFACE_BULK_WIDTH_SFP) + sfp_interface_bulk_data = sfpi_obj.parse_sfp_info_bulk(sfp_interface_bulk_raw, 0) + + sfp_vendor_name_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_NAME_OFFSET), XCVR_VENDOR_NAME_WIDTH) + sfp_vendor_name_data = sfpi_obj.parse_vendor_name(sfp_vendor_name_raw, 0) + + sfp_vendor_pn_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_PN_OFFSET), XCVR_VENDOR_PN_WIDTH) + sfp_vendor_pn_data = sfpi_obj.parse_vendor_pn(sfp_vendor_pn_raw, 0) + + sfp_vendor_rev_raw = self.__read_eeprom_specific_bytes((offset + XCVR_HW_REV_OFFSET), XCVR_HW_REV_WIDTH_SFP) + sfp_vendor_rev_data = sfpi_obj.parse_vendor_rev(sfp_vendor_rev_raw, 0) + + sfp_vendor_sn_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_SN_OFFSET), XCVR_VENDOR_SN_WIDTH) + sfp_vendor_sn_data = sfpi_obj.parse_vendor_sn(sfp_vendor_sn_raw, 0) + + sfp_vendor_oui_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_OUI_OFFSET), XCVR_VENDOR_OUI_WIDTH) + if sfp_vendor_oui_raw is not None: + sfp_vendor_oui_data = sfpi_obj.parse_vendor_oui(sfp_vendor_oui_raw, 0) + + sfp_vendor_date_raw = self.__read_eeprom_specific_bytes((offset + XCVR_VENDOR_DATE_OFFSET), XCVR_VENDOR_DATE_WIDTH) + sfp_vendor_date_data = sfpi_obj.parse_vendor_date(sfp_vendor_date_raw, 0) + + transceiver_info_dict = dict.fromkeys(transceiver_info_dict_keys, 'N/A') + + if sfp_interface_bulk_data: + transceiver_info_dict['type'] = sfp_interface_bulk_data['data']['type']['value'] + transceiver_info_dict['connector'] = sfp_interface_bulk_data['data']['Connector']['value'] + transceiver_info_dict['encoding'] = sfp_interface_bulk_data['data']['EncodingCodes']['value'] + transceiver_info_dict['ext_identifier'] = sfp_interface_bulk_data['data']['Extended Identifier']['value'] + transceiver_info_dict['ext_rateselect_compliance'] = sfp_interface_bulk_data['data']['RateIdentifier']['value'] + transceiver_info_dict['type_abbrv_name'] = sfp_interface_bulk_data['data']['type_abbrv_name']['value'] + transceiver_info_dict['nominal_bit_rate'] = str(sfp_interface_bulk_data['data']['NominalSignallingRate(UnitsOf100Mbd)']['value']) + + transceiver_info_dict['manufacturer'] = sfp_vendor_name_data['data']['Vendor Name']['value'] if sfp_vendor_name_data else 'N/A' + transceiver_info_dict['model'] = sfp_vendor_pn_data['data']['Vendor PN']['value'] if sfp_vendor_pn_data else 'N/A' + transceiver_info_dict['hardware_rev'] = sfp_vendor_rev_data['data']['Vendor Rev']['value'] if sfp_vendor_rev_data else 'N/A' + transceiver_info_dict['serial'] = sfp_vendor_sn_data['data']['Vendor SN']['value'] if sfp_vendor_sn_data else 'N/A' + transceiver_info_dict['vendor_oui'] = sfp_vendor_oui_data['data']['Vendor OUI']['value'] if sfp_vendor_oui_data else 'N/A' + transceiver_info_dict['vendor_date'] = sfp_vendor_date_data['data']['VendorDataCode(YYYY-MM-DD Lot)']['value'] if sfp_vendor_date_data else 'N/A' + + transceiver_info_dict['cable_type'] = "Unknown" + transceiver_info_dict['cable_length'] = "Unknown" + for key in sfp_cable_length_tup: + if key in sfp_interface_bulk_data['data']: + transceiver_info_dict['cable_type'] = key + transceiver_info_dict['cable_length'] = str(sfp_interface_bulk_data['data'][key]['value']) + + compliance_code_dict = dict() + for key in sfp_compliance_code_tup: + if key in sfp_interface_bulk_data['data']['Specification compliance']['value']: + compliance_code_dict[key] = sfp_interface_bulk_data['data']['Specification compliance']['value'][key]['value'] + + transceiver_info_dict['specification_compliance'] = str(compliance_code_dict) + + return transceiver_info_dict + + def get_transceiver_bulk_status(self): + """ + Retrieves transceiver bulk status of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + rx_los |BOOLEAN |RX loss-of-signal status, True if has RX los, False if not. + tx_fault |BOOLEAN |TX fault status, True if has TX fault, False if not. + reset_status |BOOLEAN |reset status, True if SFP in reset, False if not. + lp_mode |BOOLEAN |low power mode status, True in lp mode, False if not. + tx_disable |BOOLEAN |TX disable status, True TX disabled, False if not. + tx_disabled_channel |HEX |disabled TX channels in hex, bits 0 to 3 represent channel 0 + | |to channel 3. + temperature |INT |module temperature in Celsius + voltage |INT |supply voltage in mV + txbias |INT |TX Bias Current in mA, n is the channel number, + | |for example, tx2bias stands for tx bias of channel 2. + rxpower |INT |received optical power in mW, n is the channel number, + | |for example, rx2power stands for rx power of channel 2. + txpower |INT |TX output power in mW, n is the channel number, + | |for example, tx2power stands for tx power of channel 2. + ======================================================================== + """ + transceiver_dom_info_dict_keys = ['rx_los', 'tx_fault', + 'reset_status', 'power_lpmode', + 'tx_disable', 'tx_disable_channel', + 'temperature', 'voltage', + 'rx1power', 'rx2power', + 'rx3power', 'rx4power', + 'tx1bias', 'tx2bias', + 'tx3bias', 'tx4bias', + 'tx1power', 'tx2power', + 'tx3power', 'tx4power'] + + sfpd_obj = sff8472Dom() + if not self.get_presence() or not sfpd_obj: + return {} + + sysfsfile_eeprom = None + #eeprom_raw = [] + bdata='' + sysfsfile_eeprom = open(self.__eeprom_path, mode="rb", buffering=0) + bdata = sysfsfile_eeprom.read() + if len(bdata) <= 256: + sysfsfile_eeprom.close() + return None + sysfsfile_eeprom.close() + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_info_dict = dict.fromkeys(transceiver_dom_info_dict_keys, 'N/A') + + dom_temperature_raw = self.__read_eeprom_specific_bytes((offset + SFP_TEMPE_OFFSET), SFP_TEMPE_WIDTH) + + if dom_temperature_raw is not None: + dom_temperature_data = sfpd_obj.parse_temperature(dom_temperature_raw, 0) + transceiver_dom_info_dict['temperature'] = dom_temperature_data['data']['Temperature']['value'] + + dom_voltage_raw = self.__read_eeprom_specific_bytes((offset + SFP_VOLT_OFFSET), SFP_VOLT_WIDTH) + if dom_voltage_raw is not None: + dom_voltage_data = sfpd_obj.parse_voltage(dom_voltage_raw, 0) + transceiver_dom_info_dict['voltage'] = dom_voltage_data['data']['Vcc']['value'] + + dom_channel_monitor_raw = self.__read_eeprom_specific_bytes((offset + SFP_CHANNL_MON_OFFSET), SFP_CHANNL_MON_WIDTH) + if dom_channel_monitor_raw is not None: + dom_voltage_data = sfpd_obj.parse_channel_monitor_params(dom_channel_monitor_raw, 0) + transceiver_dom_info_dict['tx1power'] = dom_voltage_data['data']['TXPower']['value'] + transceiver_dom_info_dict['rx1power'] = dom_voltage_data['data']['RXPower']['value'] + transceiver_dom_info_dict['tx1bias'] = dom_voltage_data['data']['TXBias']['value'] + + for key in transceiver_dom_info_dict: + transceiver_dom_info_dict[key] = self.__convert_string_to_num(transceiver_dom_info_dict[key]) + + transceiver_dom_info_dict['reset_status'] = self.get_reset_status() + transceiver_dom_info_dict['rx_los'] = self.get_rx_los() + transceiver_dom_info_dict['tx_fault'] = self.get_tx_fault() + transceiver_dom_info_dict['tx_disable'] = self.get_tx_disable() + transceiver_dom_info_dict['tx_disable_channel'] = self.get_tx_disable_channel() + transceiver_dom_info_dict['lp_mode'] = self.get_lpmode() + + return transceiver_dom_info_dict + + def get_transceiver_threshold_info(self): + """ + Retrieves transceiver threshold info of this SFP + + Returns: + A dict which contains following keys/values : + ======================================================================== + keys |Value Format |Information + ---------------------------|---------------|---------------------------- + temphighalarm |FLOAT |High Alarm Threshold value of temperature in Celsius. + templowalarm |FLOAT |Low Alarm Threshold value of temperature in Celsius. + temphighwarning |FLOAT |High Warning Threshold value of temperature in Celsius. + templowwarning |FLOAT |Low Warning Threshold value of temperature in Celsius. + vcchighalarm |FLOAT |High Alarm Threshold value of supply voltage in mV. + vcclowalarm |FLOAT |Low Alarm Threshold value of supply voltage in mV. + vcchighwarning |FLOAT |High Warning Threshold value of supply voltage in mV. + vcclowwarning |FLOAT |Low Warning Threshold value of supply voltage in mV. + rxpowerhighalarm |FLOAT |High Alarm Threshold value of received power in dBm. + rxpowerlowalarm |FLOAT |Low Alarm Threshold value of received power in dBm. + rxpowerhighwarning |FLOAT |High Warning Threshold value of received power in dBm. + rxpowerlowwarning |FLOAT |Low Warning Threshold value of received power in dBm. + txpowerhighalarm |FLOAT |High Alarm Threshold value of transmit power in dBm. + txpowerlowalarm |FLOAT |Low Alarm Threshold value of transmit power in dBm. + txpowerhighwarning |FLOAT |High Warning Threshold value of transmit power in dBm. + txpowerlowwarning |FLOAT |Low Warning Threshold value of transmit power in dBm. + txbiashighalarm |FLOAT |High Alarm Threshold value of tx Bias Current in mA. + txbiaslowalarm |FLOAT |Low Alarm Threshold value of tx Bias Current in mA. + txbiashighwarning |FLOAT |High Warning Threshold value of tx Bias Current in mA. + txbiaslowwarning |FLOAT |Low Warning Threshold value of tx Bias Current in mA. + ======================================================================== + """ + transceiver_dom_threshold_info_dict_keys = ['temphighalarm', 'temphighwarning', 'templowalarm', 'templowwarning', + 'vcchighalarm', 'vcchighwarning', 'vcclowalarm', 'vcclowwarning', + 'rxpowerhighalarm', 'rxpowerhighwarning', 'rxpowerlowalarm', 'rxpowerlowwarning', + 'txpowerhighalarm', 'txpowerhighwarning', 'txpowerlowalarm', 'txpowerlowwarning', + 'txbiashighalarm', 'txbiashighwarning', 'txbiaslowalarm', 'txbiaslowwarning'] + + sfpd_obj = sff8472Dom() + + if not self.get_presence() and not sfpd_obj: + return {} + + sysfsfile_eeprom = None + #eeprom_raw = [] + bdata='' + sysfsfile_eeprom = open(self.__eeprom_path, mode="rb", buffering=0) + bdata = sysfsfile_eeprom.read() + if len(bdata) <= 256: + sysfsfile_eeprom.close() + return None + sysfsfile_eeprom.close() + + eeprom_ifraw = self.__read_eeprom_specific_bytes(0, DOM_OFFSET) + sfpi_obj = sff8472InterfaceId(eeprom_ifraw) + cal_type = sfpi_obj.get_calibration_type() + sfpd_obj._calibration_type = cal_type + + offset = DOM_OFFSET + transceiver_dom_threshold_info_dict = dict.fromkeys(transceiver_dom_threshold_info_dict_keys, 'N/A') + dom_module_threshold_raw = self.__read_eeprom_specific_bytes((offset + SFP_MODULE_THRESHOLD_OFFSET), SFP_MODULE_THRESHOLD_WIDTH) + if dom_module_threshold_raw is not None: + dom_module_threshold_data = sfpd_obj.parse_alarm_warning_threshold(dom_module_threshold_raw, 0) + + transceiver_dom_threshold_info_dict['temphighalarm'] = dom_module_threshold_data['data']['TempHighAlarm']['value'] + transceiver_dom_threshold_info_dict['templowalarm'] = dom_module_threshold_data['data']['TempLowAlarm']['value'] + transceiver_dom_threshold_info_dict['temphighwarning'] = dom_module_threshold_data['data']['TempHighWarning']['value'] + transceiver_dom_threshold_info_dict['templowwarning'] = dom_module_threshold_data['data']['TempLowWarning']['value'] + + transceiver_dom_threshold_info_dict['vcchighalarm'] = dom_module_threshold_data['data']['VoltageHighAlarm']['value'] + transceiver_dom_threshold_info_dict['vcclowalarm'] = dom_module_threshold_data['data']['VoltageLowAlarm']['value'] + transceiver_dom_threshold_info_dict['vcchighwarning'] = dom_module_threshold_data['data']['VoltageHighWarning']['value'] + transceiver_dom_threshold_info_dict['vcclowwarning'] = dom_module_threshold_data['data']['VoltageLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txbiashighalarm'] = dom_module_threshold_data['data']['BiasHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiaslowalarm'] = dom_module_threshold_data['data']['BiasLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txbiashighwarning'] = dom_module_threshold_data['data']['BiasHighWarning']['value'] + transceiver_dom_threshold_info_dict['txbiaslowwarning'] = dom_module_threshold_data['data']['BiasLowWarning']['value'] + + transceiver_dom_threshold_info_dict['txpowerhighalarm'] = dom_module_threshold_data['data']['TXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerlowalarm'] = dom_module_threshold_data['data']['TXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['txpowerhighwarning'] = dom_module_threshold_data['data']['TXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['txpowerlowwarning'] = dom_module_threshold_data['data']['TXPowerLowWarning']['value'] + + transceiver_dom_threshold_info_dict['rxpowerhighalarm'] = dom_module_threshold_data['data']['RXPowerHighAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowalarm'] = dom_module_threshold_data['data']['RXPowerLowAlarm']['value'] + transceiver_dom_threshold_info_dict['rxpowerhighwarning'] = dom_module_threshold_data['data']['RXPowerHighWarning']['value'] + transceiver_dom_threshold_info_dict['rxpowerlowwarning'] = dom_module_threshold_data['data']['RXPowerLowWarning']['value'] + + for key in transceiver_dom_threshold_info_dict: + transceiver_dom_threshold_info_dict[key] = self.__convert_string_to_num(transceiver_dom_threshold_info_dict[key]) + + return transceiver_dom_threshold_info_dict + + def get_reset_status(self): + """ + Retrieves the reset status of SFP + + Returns: + A Boolean, True if reset enabled, False if disabled + """ + # SFP doesn't support this feature + return False + + def get_rx_los(self): + """ + Retrieves the RX LOS (lost-of-signal) status of SFP + + Returns: + A Boolean, True if SFP has RX LOS, False if not. + Note : RX LOS status is latched until a call to get_rx_los or a reset. + """ + rx_los = False + status_control_raw = self.__read_eeprom_specific_bytes(SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + rx_los = (sffbase().test_bit(data, 1) != 0) + + return rx_los + + def get_tx_fault(self): + """ + Retrieves the TX fault status of SFP + + Returns: + A Boolean, True if SFP has TX fault, False if not + Note : TX fault status is lached until a call to get_tx_fault or a reset. + """ + tx_fault = False + status_control_raw = self.__read_eeprom_specific_bytes(SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + tx_fault = (sffbase().test_bit(data, 2) != 0) + + return tx_fault + + def get_tx_disable(self): + """ + Retrieves the tx_disable status of this SFP + + Returns: + A Boolean, True if tx_disable is enabled, False if disabled + """ + tx_disable = False + #tx_fault = False + status_control_raw = self.__read_eeprom_specific_bytes(SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw: + data = int(status_control_raw[0], 16) + tx_disable_hard = (sffbase().test_bit(data, SFP_TX_DISABLE_HARD_BIT) != 0) + tx_disable_soft = (sffbase().test_bit(data, SFP_TX_DISABLE_SOFT_BIT) != 0) + tx_disable = tx_disable_hard | tx_disable_soft + + return tx_disable + + def get_tx_disable_channel(self): + """ + Retrieves the TX disabled channels in this SFP + + Returns: + A hex of 4 bits (bit 0 to bit 3 as channel 0 to channel 3) to represent + TX channels which have been disabled in this SFP. + As an example, a returned value of 0x5 indicates that channel 0 + and channel 2 have been disabled. + """ + # SFP doesn't support this feature + return 0 + + 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 + """ + # SFP doesn't support this feature + return False + + def get_power_override(self): + """ + Retrieves the power-override status of this SFP + + Returns: + A Boolean, True if power-override is enabled, False if disabled + """ + # SFP doesn't support this feature + return False + + def get_temperature(self): + """ + Retrieves the temperature of this SFP + + Returns: + An integer number of current temperature in Celsius + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + return transceiver_dom_info_dict.get("temperature", "N/A") + + + def get_voltage(self): + """ + Retrieves the supply voltage of this SFP + + Returns: + An integer number of supply voltage in mV + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + return transceiver_dom_info_dict.get("voltage", "N/A") + + def get_tx_bias(self): + """ + Retrieves the TX bias current of this SFP + + Returns: + A list of four integer numbers, representing TX bias in mA + for channel 0 to channel 4. + Ex. ['110.09', '111.12', '108.21', '112.09'] + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + tx1_bs = transceiver_dom_info_dict.get("tx1bias", "N/A") + return [tx1_bs, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] + + def get_rx_power(self): + """ + Retrieves the received optical power for this SFP + + Returns: + A list of four integer numbers, representing received optical + power in mW for channel 0 to channel 4. + Ex. ['1.77', '1.71', '1.68', '1.70'] + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + rx1_pw = transceiver_dom_info_dict.get("rx1power", "N/A") + return [rx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] + + def get_tx_power(self): + """ + Retrieves the TX power of this SFP + + Returns: + A list of four integer numbers, representing TX power in mW + for channel 0 to channel 4. + Ex. ['1.86', '1.86', '1.86', '1.86'] + """ + transceiver_dom_info_dict = self.get_transceiver_bulk_status() + tx1_pw = transceiver_dom_info_dict.get("tx1power", "N/A") + return [tx1_pw, "N/A", "N/A", "N/A"] if transceiver_dom_info_dict else [] + + def reset(self): + """ + Reset SFP and return all user module settings to their default srate. + + Returns: + A boolean, True if successful, False if not + """ + # SFP doesn't support this feature + return False + + def tx_disable(self, tx_disable): + """ + Disable SFP TX for all channels + + Args: + tx_disable : A Boolean, True to enable tx_disable mode, False to disable + tx_disable mode. + + Returns: + A boolean, True if tx_disable is set successfully, False if not + """ + sysfs_eeprom_path = self.__eeprom_path + status_control_raw = self.__read_eeprom_specific_bytes(SFP_STATUS_CONTROL_OFFSET, SFP_STATUS_CONTROL_WIDTH) + if status_control_raw is not None: + # Set bit 6 for Soft TX Disable Select + # 01000000 = 64 and 10111111 = 191 + tx_disable_bit = 64 if tx_disable else 191 + status_control = int(status_control_raw[0], 16) + tx_disable_ctl = (status_control | tx_disable_bit) if tx_disable else (status_control & tx_disable_bit) + try: + sysfsfile_eeprom = open(sysfs_eeprom_path, mode="r+b", buffering=0) + buffer = create_string_buffer(1) + buffer[0] = chr(tx_disable_ctl) + # Write to eeprom + sysfsfile_eeprom.seek(SFP_STATUS_CONTROL_OFFSET) + sysfsfile_eeprom.write(buffer[0]) + except Exception: + return False + finally: + if sysfsfile_eeprom: + sysfsfile_eeprom.close() + time.sleep(0.01) + return True + return False + + def tx_disable_channel(self, channel, disable): + """ + Sets the tx_disable for specified SFP channels + + Args: + channel : A hex of 4 bits (bit 0 to bit 3) which represent channel 0 to 3, + e.g. 0x5 for channel 0 and channel 2. + disable : A boolean, True to disable TX channels specified in channel, + False to enable + + Returns: + A boolean, True if successful, False if not + """ + # SFP doesn't support this feature + return False + + def set_lpmode(self, lpmode): + """ + Sets the lpmode (low power mode) of SFP + + Args: + lpmode: A Boolean, True to enable lpmode, False to disable it + Note : lpmode can be overridden by set_power_override + + Returns: + A boolean, True if lpmode is set successfully, False if not + """ + # SFP doesn't support this feature + return False + + def set_power_override(self, power_override, power_set): + """ + Sets SFP power level using power_override and power_set + + Args: + power_override : + A Boolean, True to override set_lpmode and use power_set + to control SFP power, False to disable SFP power control + through power_override/power_set and use set_lpmode + to control SFP power. + power_set : + Only valid when power_override is True. + A Boolean, True to set SFP to low power mode, False to set + SFP to high power mode. + + Returns: + A boolean, True if power-override and power_set are set successfully, + False if not + """ + # SFP doesn't support this feature + return False diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal.py new file mode 100755 index 000000000000..0f15fb91817f --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python +# +# Name: thermal.py, version: 1.0 +# +# Description: Module contains the definitions of SONiC platform APIs +# + +try: + import os + import os.path + from sonic_platform_base.thermal_base import ThermalBase + from .helper import APIHelper +except ImportError as e: + raise ImportError(str(e) + "- required module not found") + +NULL_VAL = "N/A" + +class Thermal(ThermalBase): + """Platform-specific Thermal class""" + + SS_CONFIG_PATH = "/etc/sensors.d/sensors.conf" + + def __init__(self, thermal_index,thermal_conf): + self.__index = thermal_index + self.__conf = thermal_conf + + if self.__conf[self.__index]['container'] == 'psu': + self.__attr_path_prefix = '/sys/switch/psu/psu{}/temp{}/'.format(self.__conf[self.__index]['container_index']+1,self.__index) + self.__test_path_prefix = '/sys/switch/psu/psu{}/temp{}/'.format(self.__conf[self.__index]['container_index']+1,self.__index) + else: + self.__attr_path_prefix = '/sys/switch/sensor/temp{}/'.format(self.__index) + self.__test_path_prefix = '/run/platform_cache/thermal_test/sensor/temp{}/'.format(self.__index) + + self.__api_helper = APIHelper() + + self.name = self.get_name() + + self.__minimum_thermal = self.get_temperature() + self.__maximum_thermal = self.get_temperature() + ThermalBase.__init__(self) + + def get_temperature(self): + """ + Retrieves current temperature reading from thermal + Returns: + A float number of current temperature in Celsius up to nearest thousandth + of one degree Celsius, e.g. 30.125 + """ + temperature = 0.0 + + #check whether test mode is set or not + if (os.path.isdir(self.__test_path_prefix)): + attr_rv = self.__api_helper.read_one_line_file(self.__test_path_prefix + 'temp_input') + else: + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'temp_input') + + if (attr_rv != None): + attr_rv = int(attr_rv, 10) + temperature = float(attr_rv/1000) + return temperature + + def get_high_threshold(self): + """ + Retrieves the high threshold temperature of thermal + Returns: + A float number, the high threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + high_threshold = 0.0 + #check whether test mode is set or not + if (os.path.isdir(self.__test_path_prefix)): + attr_rv = self.__api_helper.read_one_line_file(self.__test_path_prefix + 'temp_max_hyst') + else: + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'temp_max_hyst') + + if (attr_rv != None): + attr_rv = int(attr_rv, 10) + high_threshold = float(attr_rv/1000) + return high_threshold + + def get_low_threshold(self): + """ + Retrieves the low threshold temperature of thermal + Returns: + A float number, the low threshold temperature of thermal in Celsius + up to nearest thousandth of one degree Celsius, e.g. 30.125 + """ + return 0.001 + + def set_high_threshold(self, temperature): + """ + Sets the high threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + is_set = False + is_set = self.__api_helper.write_txt_file(self.__attr_path_prefix + 'temp_max_hyst',int(temperature*1000)) + return is_set + + def set_low_threshold(self, temperature): + """ + Sets the low threshold temperature of thermal + Args : + temperature: A float number up to nearest thousandth of one degree Celsius, + e.g. 30.125 + Returns: + A boolean, True if threshold is set successfully, False if not + """ + return False + + 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 + """ + high_threshold = 0.0 + #check whether test mode is set or not + if (os.path.isdir(self.__test_path_prefix)): + attr_rv = self.__api_helper.read_one_line_file(self.__test_path_prefix + 'temp_max') + else: + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'temp_max') + + if (attr_rv != None): + attr_rv = int(attr_rv, 10) + high_threshold = float(attr_rv/1000) + return high_threshold + + 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.001 + + 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 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 tmp > self.__maximum_thermal: + self.__maximum_thermal = tmp + return self.__maximum_thermal + + ############################################################## + ###################### Device methods ######################## + ############################################################## + + def get_name(self): + """ + Retrieves the name of the thermal device + Returns: + string: The name of the thermal device + """ + return self.__conf[self.__index]['name'] + + def get_presence(self): + """ + Retrieves the presence of the PSU + Returns: + bool: True if PSU is present, False if not + """ + return os.path.isfile(self.__attr_path_prefix + 'temp_max_hyst') + + def get_model(self): + """ + Retrieves the model number (or part number) of the device + Returns: + string: Model/part number of device + """ + return NULL_VAL + + def get_serial(self): + """ + Retrieves the serial number of the device + Returns: + string: Serial number of device + """ + return NULL_VAL + + 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 is_replaceable(self): + """ + Retrieves whether thermal module is replaceable + Returns: + A boolean value, True if replaceable, False if not + """ + return False + + def get_position_in_parent(self): + """ + Retrieves the thermal position information + Returns: + A int value, 0 represent ASIC thermal, 1 represent CPU thermal info + """ + if self.__conf[self.__index]['position'] == "cpu": + return 1 + return 0 diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_actions.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_actions.py new file mode 100644 index 000000000000..1af2bf6d44ea --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_actions.py @@ -0,0 +1,70 @@ +import os +#import sys +import time + +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 sonic_py_common import logger +#from sonic_platform.fault import Fault +from .helper import APIHelper + +SYSLOG_IDENTIFIER = 'thermalctld' +helper_logger = logger.Logger(SYSLOG_IDENTIFIER) + +PLATFORM_CAUSE_DIR = "/host/reboot-cause/platform" +#ADDITIONAL_FAULT_CAUSE_FILE = os.path.join(PLATFORM_CAUSE_DIR, "additional_fault_cause") +INT_STATUS_FILE = '/sys/devices/pci0000:00/0000:00:1f.3/i2c-0/i2c-1/i2c-6/6-0074/int_status' +ADDITIONAL_FAULT_CAUSE_FILE = "/usr/share/sonic/platform/api_files/reboot-cause/platform/additional_fault_cause" +THERMAL_OVERLOAD_POSITION_FILE = "/usr/share/sonic/platform/api_files/reboot-cause/platform/thermal_overload_position" + +@thermal_json_object('switch.power_cycling') +class SwitchPolicyAction(ThermalPolicyActionBase): + """ + Base class for thermal action. Once all thermal conditions in a thermal policy are matched, + all predefined thermal action will be executed. + """ + + def execute(self, thermal_info_dict): + """ + Take action when thermal condition matches. For example, power cycle the switch. + :param thermal_info_dict: A dictionary stores all thermal information. + :return: + """ + self.__api_helper = APIHelper() + helper_logger.log_error("Error: thermal overload !!!!!!!!!!!!!!!!!!Please reboot Now!!") + helper_logger.log_error("Error: thermal overload !!!!!!!!!!!!!!!!!!") + """ + helper_logger.log_error("recorded the fault cause begin...") + attr_rv = self.__api_helper.read_one_line_file(INT_STATUS_FILE) + attr_rv = int(attr_rv, 16) + REBOOT_FAN_FAULT = '' + REBOOT_PSU_FAULT = '' + #0 is fault and 1 is normal + if((attr_rv & 0x1) == 0): + REBOOT_FAN_FAULT = 'FAN' + if((attr_rv & 0x2) == 0): + REBOOT_PSU_FAULT = '3V3 SYSTEM POWER' + + #fault_status = Fault.get_fault_status() + # Write a new default reboot cause file for the next reboot check + if((attr_rv & 0x3) != 0): + REBOOT_FAULT_CAUSE = ' '.join([REBOOT_FAN_FAULT, REBOOT_PSU_FAULT]) + with open(ADDITIONAL_FAULT_CAUSE_FILE, "w") as additional_fault_cause_file: + additional_fault_cause_file.write(REBOOT_FAULT_CAUSE) + additional_fault_cause_file.close() + os.system('sync') + os.system('sync') + helper_logger.log_error("recorded the fault cause...done") + """ + #wait for all record actions done + wait_ms = 30 + while wait_ms > 0: + if os.path.isfile(THERMAL_OVERLOAD_POSITION_FILE): + thermal_overload_pos = self.__api_helper.read_one_line_file(THERMAL_OVERLOAD_POSITION_FILE) + if "critical threshold" in thermal_overload_pos: + break + time.sleep(1) + helper_logger.log_error("wait ############for recorded") + wait_ms = wait_ms - 1 + #system reset. + os.system('echo 1 > /sys/devices/pci0000:00/0000:00:1f.3/i2c-0/i2c-1/1-0018/sys_rst') diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_conditions.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_conditions.py new file mode 100644 index 000000000000..1f7eee35d187 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_conditions.py @@ -0,0 +1,20 @@ +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 + +class ThermalCondition(ThermalPolicyConditionBase): + def get_thermal_info(self, thermal_info_dict): + from .thermal_infos import ThermalInfo + if ThermalInfo.INFO_NAME in thermal_info_dict and isinstance(thermal_info_dict[ThermalInfo.INFO_NAME], ThermalInfo): + return thermal_info_dict[ThermalInfo.INFO_NAME] + else: + return None + + +@thermal_json_object('thermal.over.high_critical_threshold') +class ThermalOverHighCriticalCondition(ThermalCondition): + def is_match(self, thermal_info_dict): + thermal_info_obj = self.get_thermal_info(thermal_info_dict) + if thermal_info_obj: + return thermal_info_obj.is_over_high_critical_threshold() + else: + return False diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_infos.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_infos.py new file mode 100644 index 000000000000..f50e21283dff --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_infos.py @@ -0,0 +1,168 @@ +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 .helper import APIHelper +import os +import time + + +@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('thermal_info') +class ThermalInfo(ThermalPolicyInfoBase): + """ + Thermal information needed by thermal policy + """ + + # Fan information name + INFO_NAME = 'thermal_info' + + def collect(self, chassis): + """ + Collect thermal sensor temperature change status + :param chassis: The chassis object + :return: + """ + self._over_high_threshold = False + self._over_high_critical_threshold = False + self._thermal_overload_position = 'cpu' + + # Calculate average temp within the device + temp = 0 + num_of_thermals = chassis.get_num_thermals() + for index in range(num_of_thermals): + thermal = chassis.get_thermal(index) + temp = thermal.get_temperature() + high_threshold = thermal.get_high_threshold() + high_critical_threshold = thermal.get_high_critical_threshold() + + if high_threshold and temp > high_threshold: + self._over_high_threshold = True + + if high_critical_threshold and temp > high_critical_threshold: + self._thermal_overload_position = thermal.name + self._over_high_critical_threshold = True + + def is_over_threshold(self): + """ + Retrieves if the temperature is over any threshold + :return: True if the temperature is over any threshold else False + """ + return self._over_high_threshold or self._over_high_critical_threshold + + def is_over_high_critical_threshold(self): + """ + Retrieves if the temperature is over high critical threshold + :return: True if the temperature is over high critical threshold else False + """ + thermal_overload_position_path = '/usr/share/sonic/platform/api_files/reboot-cause/platform/thermal_overload_position' + if self._over_high_critical_threshold: + APIHelper().write_txt_file(thermal_overload_position_path, + self._thermal_overload_position + ' temperature over critical threshold') + time.sleep(1) + os.system('sync') + os.system('sync') + return self._over_high_critical_threshold + + def is_over_high_threshold(self): + """ + Retrieves if the temperature is over high threshold + :return: True if the temperature is over high threshold else False + """ + return self._over_high_threshold + + +@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/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_manager.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_manager.py new file mode 100644 index 000000000000..8fe160a0f800 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/thermal_manager.py @@ -0,0 +1,40 @@ +from sonic_platform_base.sonic_thermal_control.thermal_manager_base import ThermalManagerBase + +class ThermalManager(ThermalManagerBase): + + @classmethod + def start_thermal_control_algorithm(cls): + """ + Start vendor specific thermal control algorithm. The default behavior of this function is a no-op. + :return: + """ + return cls._enable_fancontrol_service(True) + + @classmethod + def stop_thermal_control_algorithm(cls): + """ + Stop thermal control algorithm + Returns: + bool: True if set success, False if fail. + """ + return cls._enable_fancontrol_service(False) + + @classmethod + def deinitialize(cls): + """ + Destroy thermal manager, including any vendor specific cleanup. The default behavior of this function + is a no-op. + :return: + """ + return cls._enable_fancontrol_service(True) + + @classmethod + def _enable_fancontrol_service(cls, enable): + """ + Control thermal by fcs algorithm + Args: + enable: Bool, indicate enable the algorithm or not + Returns: + bool: True if set success, False if fail. + """ + pass diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/watchdog.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/watchdog.py new file mode 100644 index 000000000000..ee3453234113 --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/sonic_platform/watchdog.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python + +from __future__ import print_function + +try: + from sonic_platform_base.watchdog_base import WatchdogBase + from .helper import APIHelper +except ImportError as e: + raise ImportError("%s - required module not found" % e) + +class Watchdog(WatchdogBase): + """ + Clounix watchdog class for interfacing with a hardware watchdog module + """ + + def __init__(self, watchdog_conf): + self.__conf=watchdog_conf + self.__attr_path_prefix = '/sys/switch/watchdog/' + self.__api_helper = APIHelper() + WatchdogBase.__init__(self) + + def get_name(self): + return self.__conf['name'] + + def get_model(self): + return "N/A" + + def get_presence(self): + return True + + def get_serial(self): + return "N/A" + + def get_status(self): + return True + + def get_position_in_parent(self): + return -1 + + def is_replaceable(self): + return False + + def get_identify(self): + identify = 'N/A' + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'identity') + if (attr_rv != None): + identify = attr_rv + return identify + + def get_timeout(self): + timeout = 0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'timeout') + if (attr_rv != None): + timeout = int(attr_rv) + return timeout + + def set_timeout(self,seconds): + timeout = 0 + + attr_rv = self.__api_helper.write_txt_file(self.__attr_path_prefix + 'timeout',seconds) + if (attr_rv != None): + timeout = int(attr_rv) + return timeout + + def arm(self, seconds): + """ + Arm the hardware watchdog with a timeout of seconds. + If the watchdog is currently armed, calling this function will + simply reset the timer to the provided value. If the underlying + hardware does not support the value provided in , this + method should arm the watchdog with the *next greater* available + value. + + Returns: + An integer specifying the *actual* number of seconds the watchdog + was armed with. On failure returns -1. + """ + arm_sec = -1 + self.__api_helper.write_txt_file(self.__attr_path_prefix + 'enable', '1') + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'timeout') + if (attr_rv != None): + arm_sec = int(attr_rv) + + return arm_sec + + def disarm(self): + """ + Disarm the hardware watchdog + + Returns: + A boolean, True if watchdog is disarmed successfully, False if not + """ + self.__api_helper.write_txt_file(self.__attr_path_prefix + 'enable', '0') + return True + + def get_remaining_time(self): + """ + If the watchdog is armed, retrieve the number of seconds remaining on + the watchdog timer + + Returns: + An integer specifying the number of seconds remaining on thei + watchdog timer. If the watchdog is not armed, returns -1. + """ + remaining_time = 0.0 + + attr_rv = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'timeleft') + if (attr_rv != None): + attr_rv = int(attr_rv, 10) + remaining_time = attr_rv + return remaining_time + + def is_armed(self): + """ + Retrieves the armed state of the hardware watchdog. + + Returns: + A boolean, True if watchdog is armed, False if not + """ + status = self.__api_helper.read_one_line_file(self.__attr_path_prefix + 'state') + status = status[0:3] + if (status == 'act'): + return True + else: + return False diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/install_firmware.sh b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/install_firmware.sh new file mode 100755 index 000000000000..12677e9df25b --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/install_firmware.sh @@ -0,0 +1,192 @@ +#!/bin/sh + +firmware=$1 +firmware_file=$2 +bin_path=/usr/local/bin +log_file=/run/fw_updates_log +identify_file=/usr/local/bin/fw_updates_identify + +[ -n "${firmware_file}" ] || { + echo "ERROR: unable to read firmware Image" + exit 1 +} + +stop_plt_service() +{ + #stop service + systemctl stop pmon + systemctl stop system-health + modprobe -r i2c_mux_pca9641 + echo 0 > /proc/sys/kernel/panic_on_unrecovered_nmi +} + +start_plt_service() +{ + #auto restart sytem for firmware upgrade later + return + #restart platfrom servic + systemctl stop fn8656_bnf-platform-init.service + systemctl start fn8656_bnf-platform-init.service + systemctl start pmon + systemctl start system-health +} + +mcu_fw_install() +{ + _file_name=$firmware_file + + _mb_type=0 + if [ "$firmware" = "mcu-mb" ]; then + _mb_type=1 + fi + echo "${firmware} mcu_fw_install, please wait..." >> $log_file + stop_plt_service + #configuraton for programming + i2cset -y 0 0x71 0x3 0x00 + i2cset -y 0 0x71 0x1 0x7 + i2cset -y 0 0x72 0x0 0x7 + #GPIO17_UART1_SEL:0 is for upgrade MUC used and 1 is for i2c bridge used(default) + #GPIO54_MB_FCn_MCU_SEL:0 is for Fan control board MCU upgrade and 1 is for MB MCU upgrade + gpio_uart_sel=453 #436+17=453 + gpio_mcu_sel=490 #436+54=490 + echo $gpio_uart_sel > /sys/class/gpio/export + echo out > /sys/class/gpio/gpio453/direction + echo 0 > /sys/class/gpio/gpio453/value #pull low for GPIO-17 to UART selection + echo $gpio_mcu_sel > /sys/class/gpio/export + echo out > /sys/class/gpio/gpio490/direction + if [ $_mb_type = 1 ]; then + echo 1 > /sys/class/gpio/gpio490/value #pull high for GPIO-54 to UART selection MB + else + echo 0 > /sys/class/gpio/gpio490/value #pull low for GPIO-54 to UART selection FB + fi + if [ $_mb_type = 1 ]; then + #write 0xA5 to MB_FW_UG + i2cset -y 0 0x70 0x0 0xa5 + else + #write 0xA5 to FB_FW_UG + i2cset -y 0 0x70 0x1 0xa5 + fi + #i2cget -y 0 0x70 0x1 + #upgrade MCU FW + cd /usr/local/bin/mcu_upgrade + echo "${firmware} mcu_fw_install, please wait..." >> $log_file + python3 $bin_path/mcu_upgrade/efm8load.py -p /dev/ttyS1 $_file_name + echo "${firmware} mcu_fw_install, done" >> $log_file + cd - + #for store GPIOs used + echo $gpio_uart_sel > /sys/class/gpio/unexport + echo $gpio_mcu_sel > /sys/class/gpio/unexport + start_plt_service + +} + +#loading for main board CPLD A/B/C +cpld_mb_install() +{ + _file_name=$firmware_file + + stop_plt_service + #configuraton for GPIO + #GPIO6 GPIO6_CPLD_DTO JTAG_TDO + #GPIO24 GPIO24_SUS_CPLD_TCK JTAG_TCK + #GPIO32 GPIO32_CPLD_TDI JTAG_TDI + #GPIO50 GPIO50_CPLD_TM5 JTAG_TM5 + echo 442 > /sys/class/gpio/export + echo 460 > /sys/class/gpio/export + echo 468 > /sys/class/gpio/export + echo 486 > /sys/class/gpio/export + echo "out" > /sys/class/gpio/gpio486/direction + echo "out" > /sys/class/gpio/gpio468/direction + echo "out" > /sys/class/gpio/gpio460/direction + echo "in" > /sys/class/gpio/gpio442/direction + #must copy to same folder + cp $_file_name $bin_path/cpld_upgrade + tmp_file=$bin_path/cpld_upgrade/${_file_name##*/} + #upgrade CPLD load + $bin_path/cpld_upgrade/cpld_upgrade_bdxde_mb $tmp_file + rm $tmp_file + + #restore GPOIs + echo 442 > /sys/class/gpio/unexport + echo 460 > /sys/class/gpio/unexport + echo 468 > /sys/class/gpio/unexport + echo 486 > /sys/class/gpio/unexport + start_plt_service +} + +#loading for CPU board CPLD D +cpld_cpu_install() +{ + _file_name=$firmware_file + + stop_plt_service + #configuraton for GPIO + #GPIO27 GPIO27_CPLD_DTO JTAG_TDO + #GPIO61 GPIO61_SUS_CPLD_TCK JTAG_TCK + #GPIO68 GPIO68_CPLD_TDI JTAG_TDI + #GPIO12 GPIO12_CPLD_TM5 JTAG_TM5 + #GPIO25 GPIO25_SUS_CPLD_DOWNLOAD_SEL + echo 448 > /sys/class/gpio/export + echo 461 > /sys/class/gpio/export + echo 463 > /sys/class/gpio/export + echo 497 > /sys/class/gpio/export + echo 504 > /sys/class/gpio/export + echo "out" > /sys/class/gpio/gpio448/direction + echo "out" > /sys/class/gpio/gpio461/direction + echo "out" > /sys/class/gpio/gpio497/direction + echo "out" > /sys/class/gpio/gpio504/direction + echo "in" > /sys/class/gpio/gpio463/direction + echo 1 > /sys/class/gpio/gpio461/value + echo 1 > /sys/class/gpio/gpio448/value + echo 1 > /sys/class/gpio/gpio504/value + #About Upgrading CPU CPLD, due to JTAG-MUX set to BMC channel, + #so here need additional step to control CPLD(D) BMCR1 register bit [0] to CPU sid + i2cset -y 0 0x71 0x3 0x00 + i2cset -y 0 0x71 0x1 0x7 + i2cset -y 0 0x18 0x0B 0x29 + #must copy to same folder + cp $_file_name $bin_path/cpld_upgrade + tmp_file=$bin_path/cpld_upgrade/${_file_name##*/} + #upgrade CPLD load + $bin_path/cpld_upgrade/cpld_upgrade_bdxde_cpu $tmp_file + rm $tmp_file + + #resore GPIOs + echo 448 > /sys/class/gpio/unexport + echo 461 > /sys/class/gpio/unexport + echo 463 > /sys/class/gpio/unexport + echo 497 > /sys/class/gpio/unexport + echo 504 > /sys/class/gpio/unexport + start_plt_service +} + +echo "${firmware} loading, please wait..." +touch $log_file +touch $identify_file +echo "${firmware} loading, please wait..." >> $log_file +case "$firmware" in +mcu-fb | mcu-mb) + mcu_fw_install + ;; +cpld-mb) + cpld_mb_install + ;; +cpld-cpu) + cpld_cpu_install + ;; +fpga) + cd /usr/local/bin/fpga_bin + ./fpga_bin -f ${firmware_file} -b 3 + ;; +bios) + cd /usr/local/bin/bios_bin + ./afulnx_64 ${firmware_file} /p /b /n + ;; +*) + echo "Usage: $0 {cpld-mb|cpld-cpu|mcu-mb|mcu-fb|bios}" + exit 1 + ;; +esac +echo "${firmware} upgrade is done." +echo "${firmware} upgrade done." >> $log_file +echo "${firmware} upgrade done" >> $identify_file diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/install_firmware_ext.sh b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/install_firmware_ext.sh new file mode 100755 index 000000000000..6cfaf7401c9d --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/install_firmware_ext.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +action=$1 + +[ -n "${action}" ] || { + echo "ERROR: no action is found." + exit 1 +} + +stop_plt_service() +{ + echo "service start" + #stop service + systemctl stop pmon + systemctl stop system-health + modprobe -r i2c_mux_pca9641 + echo 0 > /proc/sys/kernel/panic_on_unrecovered_nmi +} + +start_plt_service() +{ + echo "service start" + #restart platfrom servic + systemctl stop fn8656_bnf-platform-init.service + systemctl start fn8656_bnf-platform-init.service + systemctl start pmon + systemctl start system-health +} + + + +echo "start" +case "$action" in +start) + start_plt_service + ;; +stop) + stop_plt_service + ;; +*) + echo "Usage: $0 {cpld-mb|cpld-cpu|mcu-mb|mcu-fb|bios}" + exit 1 + ;; +esac +echo "done" diff --git a/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/pegatron_fn8656_bnf_util.py b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/pegatron_fn8656_bnf_util.py new file mode 100755 index 000000000000..fc9050cdf0ad --- /dev/null +++ b/platform/clounix/sonic-platform-modules-pegatron/fn8656-bnf/utils/pegatron_fn8656_bnf_util.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Pegatron, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +from pegaProcess import common + +#message handler +def doCommand(cmd): + """ + Command: + global : Set global config + device : Set device config + """ + if len(cmd[0:]) < 1 or cmd[0] not in common.CMD_TYPE: + print(doCommand.__doc__) + return + msg = ' '.join(str(data) for data in cmd) + result = common.doSend(msg, common.SOCKET_PORT) + print (result) + + return + +def main(): + """ + Command: + install : Install drivers + uninstall : Uninstall drivers + cmd : Commands + """ + args = common.sys.argv[1:] + + if len(args[0:]) < 1: + print(main.__doc__) + return + + if args[0] == 'uninstall': + doCommand(['global', 'uninstall']) + elif args[0] == 'cmd': + doCommand(args[1:]) + else: + print(main.__doc__) + common.sys.exit(0) + +if __name__ == "__main__": + main()